Implement capturing of enum values and chaining of enums together.

llvm-svn: 39644
This commit is contained in:
Chris Lattner
2007-06-11 01:28:17 +00:00
parent a8fd973aa0
commit 4ef40013d7
7 changed files with 77 additions and 46 deletions

View File

@@ -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.

View File

@@ -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()) {

View File

@@ -770,6 +770,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) {
SmallVector<DeclTy*, 32> 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;

View File

@@ -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,

View File

@@ -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<EnumDecl>(static_cast<Decl*>(EnumDeclX));
SourceLocation EqualLoc, ExprTy *val) {
theEnumDecl = theEnumDecl; // silence unused warning.
EnumConstantDecl *LastEnumConst =
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(lastEnumConst));
Expr *Val = static_cast<Expr*>(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<Decl>());
@@ -889,17 +917,18 @@ void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
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;
// 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<EnumConstantDecl>(static_cast<Decl*>(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) {

View File

@@ -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;

View File

@@ -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;