diff options
| author | Chris Lattner <sabre@nondot.org> | 2007-01-25 07:29:02 +0000 |
|---|---|---|
| committer | Chris Lattner <sabre@nondot.org> | 2007-01-25 07:29:02 +0000 |
| commit | c1915e2052f5874d030953e01adbf565cbf74b26 (patch) | |
| tree | 4c913da5a185ff47579cdb5a32cfbd328ab4cb9c /clang | |
| parent | 5f521506aa4689aceb62d425806821e184a39fbe (diff) | |
| download | bcm5719-llvm-c1915e2052f5874d030953e01adbf565cbf74b26.tar.gz bcm5719-llvm-c1915e2052f5874d030953e01adbf565cbf74b26.zip | |
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
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/AST/Decl.cpp | 15 | ||||
| -rw-r--r-- | clang/AST/Sema.h | 5 | ||||
| -rw-r--r-- | clang/AST/SemaDecl.cpp | 31 | ||||
| -rw-r--r-- | clang/Parse/ParseDecl.cpp | 101 | ||||
| -rw-r--r-- | clang/Sema/Sema.h | 5 | ||||
| -rw-r--r-- | clang/Sema/SemaDecl.cpp | 31 | ||||
| -rw-r--r-- | clang/include/clang/AST/Decl.h | 41 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 9 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 1 |
9 files changed, 179 insertions, 60 deletions
diff --git a/clang/AST/Decl.cpp b/clang/AST/Decl.cpp index 11d92055c11..7e8cea9ae07 100644 --- a/clang/AST/Decl.cpp +++ b/clang/AST/Decl.cpp @@ -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. diff --git a/clang/AST/Sema.h b/clang/AST/Sema.h index cc13aa8f467..b7642efc64d 100644 --- a/clang/AST/Sema.h +++ b/clang/AST/Sema.h @@ -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. diff --git a/clang/AST/SemaDecl.cpp b/clang/AST/SemaDecl.cpp index b0f80c84390..14558bb3eae 100644 --- a/clang/AST/SemaDecl.cpp +++ b/clang/AST/SemaDecl.cpp @@ -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()); +} diff --git a/clang/Parse/ParseDecl.cpp b/clang/Parse/ParseDecl.cpp index 7dbba29575c..781d09b7bc0 100644 --- a/clang/Parse/ParseDecl.cpp +++ b/clang/Parse/ParseDecl.cpp @@ -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,6 +597,25 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// '}' attributes[opt] /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier +void Parser::ParseEnumSpecifier(DeclSpec &DS) { + assert(Tok.getKind() == tok::kw_enum && "Not an enum specifier"); + SourceLocation StartLoc = ConsumeToken(); + + // Parse the tag portion of this. + DeclTy *TagDecl; + if (ParseTag(TagDecl, DeclSpec::TST_enum, StartLoc)) + return; + + 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 @@ -606,55 +625,55 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// enumeration-constant: /// identifier /// -void Parser::ParseEnumSpecifier(DeclSpec &DS) { - assert(Tok.getKind() == tok::kw_enum && "Not an enum specifier"); - SourceLocation StartLoc = ConsumeToken(); +void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { + SourceLocation LBraceLoc = ConsumeBrace(); - // Parse the tag portion of this. - DeclTy *TagDecl; - if (ParseTag(TagDecl, DeclSpec::TST_enum, StartLoc)) - return; + if (Tok.getKind() == tok::r_brace) + Diag(Tok, diag::ext_empty_struct_union_enum, "enum"); - if (Tok.getKind() == tok::l_brace) { - 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(); - // 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); + 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; } - // Eat the }. - MatchRHSPunctuation(tok::r_brace, LBraceLoc); - - // If attributes exist after the identifier list, parse them. - if (Tok.getKind() == tok::kw___attribute) - ParseAttributes(); + // 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); } - // TODO: semantic analysis on the declspec for enums. + // Eat the }. + MatchRHSPunctuation(tok::r_brace, LBraceLoc); + + Actions.ParseEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0], + EnumConstantDecls.size()); - const char *PrevSpec = 0; - if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); + // 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. bool Parser::isTypeSpecifierQualifier() const { diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index cc13aa8f467..b7642efc64d 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -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. diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index b0f80c84390..14558bb3eae 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -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()); +} diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 1f12c62a1db..6b6be92d227 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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; diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index ebc31c04d95..13a49efbb80 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -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. //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 21499228423..6368a651425 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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); |

