From: Douglas Gregor Date: Tue, 17 Mar 2009 19:05:46 +0000 (+0000) Subject: Implement instantiation of enums within class templates. This isn't X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=879fd49f99742e61965f7fefecf1f3b4ba90e197;p=clang 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::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 --- 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(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(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(*Member)) { + // FIXME: Spaghetti, anyone? + EnumDecl *New = EnumDecl::Create(Context, ClassTemplateSpec, + Enum->getLocation(), + Enum->getIdentifier(), + /*PrevDecl=*/0); + ClassTemplateSpec->addDecl(New); + New->startDefinition(); + + llvm::SmallVector 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 +struct adder { + enum { + value = I + J, + value2 + }; +}; + +int array1[adder::value == 7? 1 : -1];