Allow referring to the struct type being defined in its members.

It's now legal to write:

struct Foo { Foo *next; };

previously, a predeclaration "struct Foo;" was required.  This fixes
issue #287.

This change also fixes a bug where multiple forward declarations 
"struct Foo; struct Foo;" would incorrectly issue an error on the
second one.
This commit is contained in:
Matt Pharr
2012-06-21 16:44:04 -07:00
parent 5a2c8342eb
commit 8b891da628

View File

@@ -232,6 +232,7 @@ struct ForeachDimension {
%type <enumType> enum_specifier %type <enumType> enum_specifier
%type <type> specifier_qualifier_list struct_or_union_specifier %type <type> specifier_qualifier_list struct_or_union_specifier
%type <type> struct_or_union_and_name
%type <type> type_specifier type_name rate_qualified_type_specifier %type <type> type_specifier type_name rate_qualified_type_specifier
%type <type> short_vec_specifier %type <type> short_vec_specifier
%type <typeList> type_specifier_list %type <typeList> type_specifier_list
@@ -876,18 +877,44 @@ struct_or_union_name
| TOKEN_TYPE_NAME { $$ = strdup(yytext); } | TOKEN_TYPE_NAME { $$ = strdup(yytext); }
; ;
struct_or_union_and_name
: struct_or_union struct_or_union_name
{
const Type *st = m->symbolTable->LookupType($2);
if (st == NULL) {
st = new UndefinedStructType($2, Variability::Unbound, false, @2);
m->symbolTable->AddType($2, st, @2);
$$ = st;
}
else {
if (CastType<StructType>(st) == NULL &&
CastType<UndefinedStructType>(st) == NULL) {
Error(@2, "Type \"%s\" is not a struct type! (%s)", $2,
st->GetString().c_str());
$$ = NULL;
}
else
$$ = st;
}
}
;
struct_or_union_specifier struct_or_union_specifier
: struct_or_union struct_or_union_name '{' struct_declaration_list '}' : struct_or_union_and_name
| struct_or_union_and_name '{' struct_declaration_list '}'
{ {
if ($4 != NULL) { if ($3 != NULL) {
llvm::SmallVector<const Type *, 8> elementTypes; llvm::SmallVector<const Type *, 8> elementTypes;
llvm::SmallVector<std::string, 8> elementNames; llvm::SmallVector<std::string, 8> elementNames;
llvm::SmallVector<SourcePos, 8> elementPositions; llvm::SmallVector<SourcePos, 8> elementPositions;
GetStructTypesNamesPositions(*$4, &elementTypes, &elementNames, GetStructTypesNamesPositions(*$3, &elementTypes, &elementNames,
&elementPositions); &elementPositions);
StructType *st = new StructType($2, elementTypes, elementNames, const std::string &name = CastType<StructType>($1) ?
elementPositions, false, Variability::Unbound, @2); CastType<StructType>($1)->GetStructName() :
m->symbolTable->AddType($2, st, @2); CastType<UndefinedStructType>($1)->GetStructName();
StructType *st = new StructType(name, elementTypes, elementNames,
elementPositions, false, Variability::Unbound, @1);
m->symbolTable->AddType(name.c_str(), st, @1);
$$ = st; $$ = st;
} }
else else
@@ -915,26 +942,18 @@ struct_or_union_specifier
$$ = new StructType("", elementTypes, elementNames, elementPositions, $$ = new StructType("", elementTypes, elementNames, elementPositions,
false, Variability::Unbound, @1); false, Variability::Unbound, @1);
} }
| struct_or_union struct_or_union_name '{' '}' | struct_or_union_and_name '{' '}'
{ {
llvm::SmallVector<const Type *, 8> elementTypes; llvm::SmallVector<const Type *, 8> elementTypes;
llvm::SmallVector<std::string, 8> elementNames; llvm::SmallVector<std::string, 8> elementNames;
llvm::SmallVector<SourcePos, 8> elementPositions; llvm::SmallVector<SourcePos, 8> elementPositions;
StructType *st = new StructType($2, elementTypes, elementNames, elementPositions, const std::string &name = CastType<StructType>($1) ?
CastType<StructType>($1)->GetStructName() :
CastType<UndefinedStructType>($1)->GetStructName();
StructType *st = new StructType(name, elementTypes,
elementNames, elementPositions,
false, Variability::Unbound, @1); false, Variability::Unbound, @1);
m->symbolTable->AddType($2, st, @2); m->symbolTable->AddType(name.c_str(), st, @2);
$$ = st;
}
| struct_or_union struct_or_union_name
{
const Type *st = m->symbolTable->LookupType($2);
if (st == NULL) {
st = new UndefinedStructType($2, Variability::Unbound, false, @2);
m->symbolTable->AddType($2, st, @2);
}
else if (CastType<StructType>(st) == NULL)
Error(@2, "Type \"%s\" is not a struct type! (%s)", $2,
st->GetString().c_str());
$$ = st; $$ = st;
} }
; ;