Create EnumConstantDecl objects for each enum value, and fill them into

the EnumDecl when the enum type is complete.  This allows us to detect
redefinitions of enums.

llvm-svn: 39300
This commit is contained in:
Chris Lattner
2007-01-25 07:29:02 +00:00
parent 5f521506aa
commit c1915e2052
9 changed files with 182 additions and 63 deletions

View File

@@ -47,6 +47,21 @@ void FunctionDecl::setParams(VarDecl **NewParamInfo, unsigned NumParams) {
}
/// defineElements - When created, EnumDecl correspond to a forward declared
/// enum. This method is used to mark the decl as being defined, with the
/// specified contents.
void EnumDecl::defineElements(EnumConstantDecl **Elts, unsigned NumElts) {
assert(!isDefinition() && "Cannot redefine enums!");
setDefinition(true);
NumElements = NumElts;
if (NumElts) {
Elements = new EnumConstantDecl*[NumElts];
memcpy(Elements, Elts, NumElts*sizeof(Decl*));
}
}
/// defineBody - When created, RecordDecl's correspond to a forward declared
/// record. This method is used to mark the decl as being defined, with the
/// specified contents.

View File

@@ -90,6 +90,11 @@ public:
Declarator &D, ExprTy *BitfieldWidth);
virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl,
DeclTy **Fields, unsigned NumFields);
virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl,
SourceLocation IdLoc, IdentifierInfo *Id,
SourceLocation EqualLoc, ExprTy *Val);
virtual void ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
DeclTy **Elements, unsigned NumElements);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.

View File

@@ -316,7 +316,6 @@ Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
// Okay, this is definition of a previously declared or referenced tag.
// Move the location of the decl to be the definition site.
PrevDecl->setLocation(NameLoc);
//PrevDecl->setDefinition(true);
return PrevDecl;
}
}
@@ -337,8 +336,7 @@ Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
case Decl::Enum:
New = new EnumDecl(Loc, Name);
// If this is an undefined enum, warn.
if (TK != TK_Definition)
Diag(Loc, diag::ext_forward_ref_enum);
if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
break;
case Decl::Union:
case Decl::Struct:
@@ -387,7 +385,7 @@ Sema::DeclTy *Sema::ParseField(Scope *S, DeclTy *TagDecl,
void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl,
DeclTy **Fields, unsigned NumFields) {
RecordDecl *Record = cast<RecordDecl>(static_cast<TagDecl*>(RecDecl));
RecordDecl *Record = cast<RecordDecl>(static_cast<Decl*>(RecDecl));
if (Record->isDefinition()) {
// Diagnose code like:
// struct S { struct S {} X; };
@@ -478,4 +476,29 @@ void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl,
Record->defineBody(&RecFields[0], RecFields.size());
}
Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *EnumDeclX,
SourceLocation IdLoc, IdentifierInfo *Id,
SourceLocation EqualLoc, ExprTy *Val) {
EnumDecl *TheEnumDecl = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
TypeRef Ty = Context.getTagDeclType(TheEnumDecl);
return new EnumConstantDecl(IdLoc, Id, Ty);
}
void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
DeclTy **Elements, unsigned NumElements) {
EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
assert(!Enum->isDefinition() && "Enum redefinitions can't reach here");
// Verify that all the values are okay.
SmallVector<EnumConstantDecl*, 32> Values;
for (unsigned i = 0; i != NumElements; ++i) {
EnumConstantDecl *ECD =
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(Elements[i]));
if (!ECD) continue; // Already issued a diagnostic.
Values.push_back(ECD);
}
Enum->defineElements(&Values[0], Values.size());
}

View File

@@ -579,10 +579,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
}
Actions.ParseRecordBody(RecordLoc, TagDecl, &FieldDecls[0],FieldDecls.size());
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
Actions.ParseRecordBody(RecordLoc, TagDecl, &FieldDecls[0],FieldDecls.size());
// If attributes exist after struct contents, parse them.
if (Tok.getKind() == tok::kw___attribute)
ParseAttributes();
@@ -597,15 +597,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
/// '}' attributes[opt]
/// 'enum' identifier
/// [GNU] 'enum' attributes[opt] identifier
/// enumerator-list:
/// enumerator
/// enumerator-list ',' enumerator
/// enumerator:
/// enumeration-constant
/// enumeration-constant '=' constant-expression
/// enumeration-constant:
/// identifier
///
void Parser::ParseEnumSpecifier(DeclSpec &DS) {
assert(Tok.getKind() == tok::kw_enum && "Not an enum specifier");
SourceLocation StartLoc = ConsumeToken();
@@ -615,45 +606,73 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) {
if (ParseTag(TagDecl, DeclSpec::TST_enum, StartLoc))
return;
if (Tok.getKind() == tok::l_brace) {
SourceLocation LBraceLoc = ConsumeBrace();
if (Tok.getKind() == tok::r_brace)
Diag(Tok, diag::ext_empty_struct_union_enum, "enum");
// Parse the enumerator-list.
while (Tok.getKind() == tok::identifier) {
ConsumeToken();
if (Tok.getKind() == tok::equal) {
ConsumeToken();
ExprResult Res = ParseConstantExpression();
if (Res.isInvalid) SkipUntil(tok::comma, true, false);
}
if (Tok.getKind() != tok::comma)
break;
SourceLocation CommaLoc = ConsumeToken();
if (Tok.getKind() != tok::identifier && !getLang().C99)
Diag(CommaLoc, diag::ext_c99_enumerator_list_comma);
}
// Eat the }.
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
// If attributes exist after the identifier list, parse them.
if (Tok.getKind() == tok::kw___attribute)
ParseAttributes();
}
if (Tok.getKind() == tok::l_brace)
ParseEnumBody(StartLoc, TagDecl);
// TODO: semantic analysis on the declspec for enums.
const char *PrevSpec = 0;
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl))
Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
}
/// ParseEnumBody - Parse a {} enclosed enumerator-list.
/// enumerator-list:
/// enumerator
/// enumerator-list ',' enumerator
/// enumerator:
/// enumeration-constant
/// enumeration-constant '=' constant-expression
/// enumeration-constant:
/// identifier
///
void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) {
SourceLocation LBraceLoc = ConsumeBrace();
if (Tok.getKind() == tok::r_brace)
Diag(Tok, diag::ext_empty_struct_union_enum, "enum");
SmallVector<DeclTy*, 32> EnumConstantDecls;
// Parse the enumerator-list.
while (Tok.getKind() == tok::identifier) {
IdentifierInfo *Ident = Tok.getIdentifierInfo();
SourceLocation IdentLoc = ConsumeToken();
SourceLocation EqualLoc;
ExprTy *AssignedVal = 0;
if (Tok.getKind() == tok::equal) {
EqualLoc = ConsumeToken();
ExprResult Res = ParseConstantExpression();
if (Res.isInvalid)
SkipUntil(tok::comma, true, false);
else
AssignedVal = Res.Val;
}
// Install the enumerator constant into EnumDecl.
DeclTy *ConstDecl = Actions.ParseEnumConstant(CurScope, EnumDecl,
IdentLoc, Ident,
EqualLoc, AssignedVal);
EnumConstantDecls.push_back(ConstDecl);
if (Tok.getKind() != tok::comma)
break;
SourceLocation CommaLoc = ConsumeToken();
if (Tok.getKind() != tok::identifier && !getLang().C99)
Diag(CommaLoc, diag::ext_c99_enumerator_list_comma);
}
// Eat the }.
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
Actions.ParseEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0],
EnumConstantDecls.size());
// If attributes exist after the identifier list, parse them.
if (Tok.getKind() == tok::kw___attribute)
ParseAttributes();
}
/// isTypeSpecifierQualifier - Return true if the current token could be the
/// start of a specifier-qualifier-list.

View File

@@ -90,6 +90,11 @@ public:
Declarator &D, ExprTy *BitfieldWidth);
virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl,
DeclTy **Fields, unsigned NumFields);
virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl,
SourceLocation IdLoc, IdentifierInfo *Id,
SourceLocation EqualLoc, ExprTy *Val);
virtual void ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
DeclTy **Elements, unsigned NumElements);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.

View File

@@ -316,7 +316,6 @@ Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
// Okay, this is definition of a previously declared or referenced tag.
// Move the location of the decl to be the definition site.
PrevDecl->setLocation(NameLoc);
//PrevDecl->setDefinition(true);
return PrevDecl;
}
}
@@ -337,8 +336,7 @@ Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
case Decl::Enum:
New = new EnumDecl(Loc, Name);
// If this is an undefined enum, warn.
if (TK != TK_Definition)
Diag(Loc, diag::ext_forward_ref_enum);
if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
break;
case Decl::Union:
case Decl::Struct:
@@ -387,7 +385,7 @@ Sema::DeclTy *Sema::ParseField(Scope *S, DeclTy *TagDecl,
void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl,
DeclTy **Fields, unsigned NumFields) {
RecordDecl *Record = cast<RecordDecl>(static_cast<TagDecl*>(RecDecl));
RecordDecl *Record = cast<RecordDecl>(static_cast<Decl*>(RecDecl));
if (Record->isDefinition()) {
// Diagnose code like:
// struct S { struct S {} X; };
@@ -478,4 +476,29 @@ void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl,
Record->defineBody(&RecFields[0], RecFields.size());
}
Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *EnumDeclX,
SourceLocation IdLoc, IdentifierInfo *Id,
SourceLocation EqualLoc, ExprTy *Val) {
EnumDecl *TheEnumDecl = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
TypeRef Ty = Context.getTagDeclType(TheEnumDecl);
return new EnumConstantDecl(IdLoc, Id, Ty);
}
void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
DeclTy **Elements, unsigned NumElements) {
EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
assert(!Enum->isDefinition() && "Enum redefinitions can't reach here");
// Verify that all the values are okay.
SmallVector<EnumConstantDecl*, 32> Values;
for (unsigned i = 0; i != NumElements; ++i) {
EnumConstantDecl *ECD =
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(Elements[i]));
if (!ECD) continue; // Already issued a diagnostic.
Values.push_back(ECD);
}
Enum->defineElements(&Values[0], Values.size());
}

View File

@@ -20,6 +20,7 @@
namespace llvm {
namespace clang {
class IdentifierInfo;
class Expr;
class Stmt;
class FunctionDecl;
@@ -29,7 +30,7 @@ class FunctionDecl;
class Decl {
public:
enum Kind {
Typedef, Function, Variable, Field,
Typedef, Function, Variable, Field, EnumConstant,
Struct, Union, Class, Enum
};
@@ -189,7 +190,6 @@ public:
/// FunctionDecl - An instance of this class is created to represent a function
/// declaration or definition.
class FieldDecl : public ObjectDecl {
public:
FieldDecl(SourceLocation L, IdentifierInfo *Id, TypeRef T)
: ObjectDecl(Field, L, Id, T) {}
@@ -201,6 +201,26 @@ public:
static bool classof(const FieldDecl *D) { return true; }
};
/// EnumConstantDecl - An instance of this object exists for each enum constant
/// that is defined. For example, in "enum X {a,b}", each of a/b are
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
/// TaggedType for the X EnumDecl.
class EnumConstantDecl : public ObjectDecl {
public:
// FIXME: Capture value info.
EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, TypeRef T)
: ObjectDecl(EnumConstant, L, Id, T) {}
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() == EnumConstant;
}
static bool classof(const EnumConstantDecl *D) { return true; }
};
/// TagDecl - Represents the declaration of a struct/union/class/enum.
class TagDecl : public Decl {
/// IsDefinition - True if this is a definition ("struct foo {};"), false if
@@ -240,19 +260,20 @@ protected:
/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
/// enums.
class EnumDecl : public TagDecl {
/// Fields/NumFields - This is a new[]'d array of pointers to Decls.
//Decl **Fields; // Null if not defined.
//int NumFields; // -1 if not defined.
/// Elements/NumElements - This is a new[]'d array of pointers to
/// EnumConstantDecls.
EnumConstantDecl **Elements; // Null if not defined.
int NumElements; // -1 if not defined.
public:
EnumDecl(SourceLocation L, IdentifierInfo *Id) : TagDecl(Enum, L, Id) {
//Fields = 0;
//NumFields = -1;
Elements = 0;
NumElements = -1;
}
/// defineBody - When created, RecordDecl's correspond to a forward declared
/// record. This method is used to mark the decl as being defined, with the
/// defineElements - When created, EnumDecl correspond to a forward declared
/// enum. This method is used to mark the decl as being defined, with the
/// specified contents.
//void defineBody(Decl **fields, unsigned numFields);
void defineElements(EnumConstantDecl **Elements, unsigned NumElements);
static bool classof(const Decl *D) {
return D->getKind() == Enum;

View File

@@ -160,7 +160,14 @@ public:
virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl,
DeclTy **Fields, unsigned NumFields) {}
virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl,
SourceLocation IdLoc, IdentifierInfo *Id,
SourceLocation EqualLoc, ExprTy *Val) {
return 0;
}
virtual void ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
DeclTy **Elements, unsigned NumElements) {}
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks.
//===--------------------------------------------------------------------===//

View File

@@ -333,6 +333,7 @@ private:
bool ParseTag(DeclTy *&Decl, unsigned TagType, SourceLocation StartLoc);
void ParseEnumSpecifier(DeclSpec &DS);
void ParseEnumBody(SourceLocation StartLoc, DeclTy *TagDecl);
void ParseStructUnionSpecifier(DeclSpec &DS);
void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
DeclTy *TagDecl);