]> granicus.if.org Git - clang/commitdiff
Handle instantiations of redeclarations of forward-declared enumerations within
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 26 Mar 2012 04:58:10 +0000 (04:58 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 26 Mar 2012 04:58:10 +0000 (04:58 +0000)
templated functions. Build a redeclaration chain, and only instantiate the
definition of the enum when visiting the defining declaration.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153427 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/enum-scoped.cpp

index caf134e0259ce6c5ee8551c63811533a61155351..8729a39f9bcd9a43a385ec8e1b49a3eef0909212 100644 (file)
@@ -558,9 +558,18 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
 }
 
 Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
+  EnumDecl *PrevDecl = 0;
+  if (D->getPreviousDecl()) {
+    NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
+                                                   D->getPreviousDecl(),
+                                                   TemplateArgs);
+    if (!Prev) return 0;
+    PrevDecl = cast<EnumDecl>(Prev);
+  }
+
   EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocStart(),
                                     D->getLocation(), D->getIdentifier(),
-                                    /*PrevDecl=*/0, D->isScoped(),
+                                    PrevDecl, D->isScoped(),
                                     D->isScopedUsingClassTag(), D->isFixed());
   if (D->isFixed()) {
     if (TypeSourceInfo *TI = D->getIntegerTypeSourceInfo()) {
@@ -610,8 +619,11 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
   // specialization causes the implicit instantiation of the declarations, but
   // not the definitions of scoped member enumerations.
   // FIXME: There appears to be no wording for what happens for an enum defined
-  // within a block scope, but we treat that like a member of a class template.
-  if (!Enum->isScoped() && Def)
+  // within a block scope, but we treat that much like a member template. Only
+  // instantiate the definition when visiting the definition in that case, since
+  // we will visit all redeclarations.
+  if (!Enum->isScoped() && Def &&
+      (!D->getDeclContext()->isFunctionOrMethod() || D->isCompleteDefinition()))
     InstantiateEnumDefinition(Enum, Def);
 
   return Enum;
index c842dcde848a602801c22a8c8b970b10214524cb..ebe924535850b4e609ad15ec99d06422285aa050 100644 (file)
@@ -221,3 +221,27 @@ namespace test9 {
   // never instantiate the definitions of S<short>::ET nor S<short>::Eint.
   S<short> s; // expected-note {{in instantiation of}}
 }
+
+namespace test10 {
+  template<typename T> int f() {
+    enum E : int;
+    enum E : T; // expected-note {{here}}
+    E x;
+    enum E : int { e }; // expected-error {{different underlying}}
+    x = e;
+    return x;
+  }
+  int k = f<int>();
+  int l = f<short>(); // expected-note {{here}}
+
+  template<typename T> int g() {
+    enum class E : int;
+    enum class E : T; // expected-note {{here}}
+    E x;
+    enum class E : int { e }; // expected-error {{different underlying}}
+    x = E::e;
+    return (int)x;
+  }
+  int m = g<int>();
+  int n = g<short>(); // expected-note {{here}}
+}