diff --git a/clang/AST/Decl.cpp b/clang/AST/Decl.cpp index 169e4a48efe9..ca37f7cfc9f1 100644 --- a/clang/AST/Decl.cpp +++ b/clang/AST/Decl.cpp @@ -136,21 +136,6 @@ 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/Expr.cpp b/clang/AST/Expr.cpp index 3f4ae07eaba3..c483481b04c2 100644 --- a/clang/AST/Expr.cpp +++ b/clang/AST/Expr.cpp @@ -206,6 +206,9 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue() { /// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, /// comma, etc +/// +/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not +/// permit this. bool Expr::isIntegerConstantExpr(APSInt &Result, SourceLocation *Loc, bool isEvaluated) const { switch (getStmtClass()) { diff --git a/clang/Parse/ParseDecl.cpp b/clang/Parse/ParseDecl.cpp index 4ad8f5878f80..48c32dea66a1 100644 --- a/clang/Parse/ParseDecl.cpp +++ b/clang/Parse/ParseDecl.cpp @@ -770,6 +770,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { SmallVector EnumConstantDecls; + DeclTy *LastEnumConstDecl = 0; + // Parse the enumerator-list. while (Tok.getKind() == tok::identifier) { IdentifierInfo *Ident = Tok.getIdentifierInfo(); @@ -787,10 +789,12 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { } // Install the enumerator constant into EnumDecl. - DeclTy *ConstDecl = Actions.ParseEnumConstant(CurScope, EnumDecl, - IdentLoc, Ident, - EqualLoc, AssignedVal); - EnumConstantDecls.push_back(ConstDecl); + DeclTy *EnumConstDecl = Actions.ParseEnumConstant(CurScope, EnumDecl, + LastEnumConstDecl, + IdentLoc, Ident, + EqualLoc, AssignedVal); + EnumConstantDecls.push_back(EnumConstDecl); + LastEnumConstDecl = EnumConstDecl; if (Tok.getKind() != tok::comma) break; diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index 9e4235286735..45cfcad3b15e 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -116,6 +116,7 @@ private: virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl, DeclTy **Fields, unsigned NumFields); virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl, + DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation EqualLoc, ExprTy *Val); virtual void ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl, diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index 49c6347cf116..88d081a65bdb 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -849,10 +849,14 @@ void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl, Record->defineBody(&RecFields[0], RecFields.size()); } -Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *EnumDeclX, +Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *theEnumDecl, + DeclTy *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *Val) { - EnumDecl *TheEnumDecl = cast(static_cast(EnumDeclX)); + SourceLocation EqualLoc, ExprTy *val) { + theEnumDecl = theEnumDecl; // silence unused warning. + EnumConstantDecl *LastEnumConst = + cast_or_null(static_cast(lastEnumConst)); + Expr *Val = static_cast(val); // Verify that there isn't already something declared with this name in this // scope. @@ -863,19 +867,43 @@ Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *EnumDeclX, else Diag(IdLoc, diag::err_redefinition, Id->getName()); Diag(PrevDecl->getLocation(), diag::err_previous_definition); + // FIXME: Don't leak memory: delete Val; return 0; } } - SourceLocation expLoc; - // C99 6.7.2.2p2: Make sure we have an integer constant expression. - // FIXME: Capture this value in the enumconstantdecl. - if (Val && !((Expr *)Val)->isIntegerConstantExpr(&expLoc)) { - Diag(expLoc, diag::err_enum_value_not_integer_constant_expr, Id->getName()); - return 0; + + APSInt EnumVal(32); + QualType EltTy; + if (Val) { + // C99 6.7.2.2p2: Make sure we have an integer constant expression. + SourceLocation ExpLoc; + if (!Val->isIntegerConstantExpr(EnumVal, &ExpLoc)) { + Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr, + Id->getName()); + // FIXME: Don't leak memory: delete Val; + return 0; + } + EltTy = Val->getType(); + } else if (LastEnumConst) { + // Assign the last value + 1. + EnumVal = LastEnumConst->getInitVal(); + ++EnumVal; + // FIXME: detect overflow! + EltTy = LastEnumConst->getType(); + } else { + // First value, set to zero. + EltTy = Context.IntTy; + // FIXME: Resize EnumVal to the size of int. } - QualType Ty = Context.getTagDeclType(TheEnumDecl); - // FIXME: Chain EnumConstantDecl's together. - EnumConstantDecl *New = new EnumConstantDecl(IdLoc, Id, Ty, (Expr *)Val, 0); + + // TODO: Default promotions to int/uint. + + // TODO: If the result value doesn't fit in an int, it must be a long or long + // long value. ISO C does not support this, but GCC does as an extension, + // emit a warning. + + EnumConstantDecl *New = new EnumConstantDecl(IdLoc, Id, EltTy, Val, EnumVal, + LastEnumConst); // Register this decl in the current scope stack. New->setNext(Id->getFETokenInfo()); @@ -889,17 +917,18 @@ void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, EnumDecl *Enum = cast(static_cast(EnumDeclX)); assert(!Enum->isDefinition() && "Enum redefinitions can't reach here"); - // Verify that all the values are okay. - SmallVector Values; + // Verify that all the values are okay, and reverse the list. + EnumConstantDecl *EltList = 0; for (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = cast_or_null(static_cast(Elements[i])); if (!ECD) continue; // Already issued a diagnostic. - - Values.push_back(ECD); + + ECD->setNextDeclarator(EltList); + EltList = ECD; } - Enum->defineElements(&Values[0], Values.size()); + Enum->defineElements(EltList); } void Sema::AddTopLevelDecl(Decl *current, Decl *last) { diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index d3e302b2d457..a05fd8e81cb1 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -16,6 +16,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/AST/Type.h" +#include "llvm/ADT/APSInt.h" namespace llvm { namespace clang { @@ -274,11 +275,16 @@ public: /// TagType for the X EnumDecl. class EnumConstantDecl : public ValueDecl { Expr *Init; // an integer constant expression + APSInt Val; // The value. public: EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E, - Decl *PrevDecl) - : ValueDecl(EnumConstant, L, Id, T, PrevDecl), Init(E) {} + const APSInt &V, Decl *PrevDecl) + : ValueDecl(EnumConstant, L, Id, T, PrevDecl), Init(E), Val(V) {} + const Expr *getInitExpr() const { return Init; } + Expr *getInitExpr() { return Init; } + const APSInt &getInitVal() const { return Val; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == EnumConstant; @@ -363,21 +369,23 @@ protected: /// EnumDecl - Represents an enum. As an extension, we allow forward-declared /// enums. class EnumDecl : public TagDecl { - /// Elements/NumElements - This is a new[]'d array of pointers to - /// EnumConstantDecls. - EnumConstantDecl **Elements; // Null if not defined. - int NumElements; // -1 if not defined. + /// ElementList - this is a linked list of EnumConstantDecl's which are linked + /// together through their getNextDeclarator pointers. + EnumConstantDecl *ElementList; public: EnumDecl(SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl) : TagDecl(Enum, L, Id, PrevDecl) { - Elements = 0; - NumElements = -1; + ElementList = 0; } /// 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 defineElements(EnumConstantDecl **Elements, unsigned NumElements); + /// specified list of enums. + void defineElements(EnumConstantDecl *ListHead) { + assert(!isDefinition() && "Cannot redefine enums!"); + ElementList = ListHead; + setDefinition(true); + } 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 8be89de41408..48644f9ea095 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -169,6 +169,7 @@ public: DeclTy **Fields, unsigned NumFields) {} virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl, + DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation EqualLoc, ExprTy *Val) { return 0;