aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-17 19:05:46 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-17 19:05:46 +0000
commit879fd49f99742e61965f7fefecf1f3b4ba90e197 (patch)
tree94f7603c0ae78bc3bcf9eda2701b44f9405d226c
parent1fd6c4b8abbbdcbae0e221f35100102112dabff2 (diff)
Implement instantiation of enums within class templates. This isn't
quite as great as it sounds, because, while we can refer to the enumerator values outside the template, e.g., adder<long, 3, 4>::value we can't yet refer to them with dependent names, so no Fibonacci (yet). InstantiateClassTemplateSpecialization is getting messy; next commit will put it into a less-ugly state. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67092 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDecl.cpp93
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp55
-rw-r--r--test/SemaTemplate/instantiate-enum.cpp11
4 files changed, 125 insertions, 40 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 13c3e87bfe..ed6b2d4160 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -399,6 +399,12 @@ public:
/// the definition of a tag (enumeration, class, struct, or union).
virtual void ActOnTagFinishDefinition(Scope *S, DeclTy *TagDecl);
+ EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum,
+ EnumConstantDecl *LastEnumConst,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ ExprArg val);
+
virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl,
DeclTy *LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d34a8e7111..7eedd0b07f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3755,6 +3755,57 @@ void Sema::ActOnFields(Scope* S,
ProcessDeclAttributeList(Record, Attr);
}
+EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
+ EnumConstantDecl *LastEnumConst,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ ExprArg val) {
+ Expr *Val = (Expr *)val.get();
+
+ llvm::APSInt EnumVal(32);
+ QualType EltTy;
+ if (Val && !Val->isTypeDependent()) {
+ // Make sure to promote the operand type to int.
+ UsualUnaryConversions(Val);
+ if (Val != val.get()) {
+ val.release();
+ val = Val;
+ }
+
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
+ SourceLocation ExpLoc;
+ if (!Val->isValueDependent() &&
+ VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ Val = 0;
+ } else {
+ EltTy = Val->getType();
+ }
+ }
+
+ if (!Val) {
+ if (LastEnumConst) {
+ // Assign the last value + 1.
+ EnumVal = LastEnumConst->getInitVal();
+ ++EnumVal;
+
+ // Check for overflow on increment.
+ if (EnumVal < LastEnumConst->getInitVal())
+ Diag(IdLoc, diag::warn_enum_value_overflow);
+
+ EltTy = LastEnumConst->getType();
+ } else {
+ // First value, set to zero.
+ EltTy = Context.IntTy;
+ EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
+ }
+ }
+
+ val.release();
+ return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
+ Val, EnumVal);
+}
+
+
Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl,
DeclTy *lastEnumConst,
SourceLocation IdLoc, IdentifierInfo *Id,
@@ -3794,46 +3845,12 @@ Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl,
}
}
- llvm::APSInt EnumVal(32);
- QualType EltTy;
- if (Val) {
- // Make sure to promote the operand type to int.
- UsualUnaryConversions(Val);
-
- // C99 6.7.2.2p2: Make sure we have an integer constant expression.
- SourceLocation ExpLoc;
- if (VerifyIntegerConstantExpression(Val, &EnumVal)) {
- Val->Destroy(Context);
- Val = 0; // Just forget about it.
- } else {
- EltTy = Val->getType();
- }
- }
-
- if (!Val) {
- if (LastEnumConst) {
- // Assign the last value + 1.
- EnumVal = LastEnumConst->getInitVal();
- ++EnumVal;
+ EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst,
+ IdLoc, Id, Owned(Val));
- // Check for overflow on increment.
- if (EnumVal < LastEnumConst->getInitVal())
- Diag(IdLoc, diag::warn_enum_value_overflow);
-
- EltTy = LastEnumConst->getType();
- } else {
- // First value, set to zero.
- EltTy = Context.IntTy;
- EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
- }
- }
-
- EnumConstantDecl *New =
- EnumConstantDecl::Create(Context, TheEnumDecl, IdLoc, Id, EltTy,
- Val, EnumVal);
-
// Register this decl in the current scope stack.
- PushOnScopeChains(New, S);
+ if (New)
+ PushOnScopeChains(New, S);
return New;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 25553e510f..4f0a9923bd 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -664,8 +664,7 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
Sema::OwningExprResult
TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) {
- Sema::OwningExprResult SubExpr
- = SemaRef.InstantiateExpr(E->getSubExpr(), TemplateArgs, NumTemplateArgs);
+ Sema::OwningExprResult SubExpr = Visit(E->getSubExpr());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -733,6 +732,7 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
// expression.
First.release();
Second.release();
+ // FIXME: Don't reuse the callee here. We need to instantiate it.
return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
SemaRef.Context,
E->getOperator(),
@@ -1147,6 +1147,57 @@ Sema::InstantiateClassTemplateSpecialization(
} else
Invalid = true;
+ } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(*Member)) {
+ // FIXME: Spaghetti, anyone?
+ EnumDecl *New = EnumDecl::Create(Context, ClassTemplateSpec,
+ Enum->getLocation(),
+ Enum->getIdentifier(),
+ /*PrevDecl=*/0);
+ ClassTemplateSpec->addDecl(New);
+ New->startDefinition();
+
+ llvm::SmallVector<DeclTy *, 16> Enumerators;
+
+ EnumConstantDecl *LastEnumConst = 0;
+ for (EnumDecl::enumerator_iterator EC = Enum->enumerator_begin(),
+ ECEnd = Enum->enumerator_end();
+ EC != ECEnd; ++EC) {
+ // The specified value for the enumerator.
+ OwningExprResult Value = Owned((Expr *)0);
+ if (Expr *UninstValue = EC->getInitExpr())
+ Value = InstantiateExpr(UninstValue,
+ ClassTemplateSpec->getTemplateArgs(),
+ ClassTemplateSpec->getNumTemplateArgs());
+
+ // Drop the initial value and continue.
+ bool isInvalid = false;
+ if (Value.isInvalid()) {
+ Value = Owned((Expr *)0);
+ isInvalid = true;
+ }
+
+ EnumConstantDecl *NewEnumConst
+ = CheckEnumConstant(New, LastEnumConst,
+ EC->getLocation(),
+ EC->getIdentifier(),
+ move(Value));
+
+ if (isInvalid) {
+ if (NewEnumConst)
+ NewEnumConst->setInvalidDecl();
+ New->setInvalidDecl();
+ Invalid = true;
+ }
+
+ if (NewEnumConst) {
+ New->addDecl(NewEnumConst);
+ Enumerators.push_back(NewEnumConst);
+ LastEnumConst = NewEnumConst;
+ }
+ }
+
+ ActOnEnumBody(New->getLocation(), New,
+ &Enumerators[0], Enumerators.size());
}
}
diff --git a/test/SemaTemplate/instantiate-enum.cpp b/test/SemaTemplate/instantiate-enum.cpp
new file mode 100644
index 0000000000..665746cfd4
--- /dev/null
+++ b/test/SemaTemplate/instantiate-enum.cpp
@@ -0,0 +1,11 @@
+// RUN: clang -fsyntax-only %s
+
+template<typename T, T I, int J>
+struct adder {
+ enum {
+ value = I + J,
+ value2
+ };
+};
+
+int array1[adder<long, 3, 4>::value == 7? 1 : -1];