]> granicus.if.org Git - clang/commitdiff
Delay checking of dependent underlying types for redeclarations of member
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 26 Mar 2012 04:08:46 +0000 (04:08 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 26 Mar 2012 04:08:46 +0000 (04:08 +0000)
enumerations in templates until the template is instantiated.

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

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

index 68b27ef1f983633813a5edc9169e01349f8f1f07..e92b3e4acab7f2982f3425e594c7fef2b716d687 100644 (file)
@@ -7780,7 +7780,9 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
   }
 
   if (IsFixed && Prev->isFixed()) {
-    if (!Context.hasSameUnqualifiedType(EnumUnderlyingTy,
+    if (!EnumUnderlyingTy->isDependentType() &&
+        !Prev->getIntegerType()->isDependentType() &&
+        !Context.hasSameUnqualifiedType(EnumUnderlyingTy,
                                         Prev->getIntegerType())) {
       Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch)
         << EnumUnderlyingTy << Prev->getIntegerType();
index ebc43d443db72becaf5590917053522821b52bf5..caf134e0259ce6c5ee8551c63811533a61155351 100644 (file)
@@ -588,9 +588,20 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
   if (SubstQualifier(D, Enum)) return 0;
   Owner->addDecl(Enum);
 
-  // FIXME: If this is a redeclaration:
-  // CheckEnumRedeclaration(Enum->getLocation(), Enum->isScoped(),
-  //                        Enum->getIntegerType(), Prev);
+  EnumDecl *Def = D->getDefinition();
+  if (Def && Def != D) {
+    // If this is an out-of-line definition of an enum member template, check
+    // that the underlying types match in the instantiation of both
+    // declarations.
+    if (TypeSourceInfo *TI = Def->getIntegerTypeSourceInfo()) {
+      SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
+      QualType DefnUnderlying =
+        SemaRef.SubstType(TI->getType(), TemplateArgs,
+                          UnderlyingLoc, DeclarationName());
+      SemaRef.CheckEnumRedeclaration(Def->getLocation(), Def->isScoped(),
+                                     DefnUnderlying, Enum);
+    }
+  }
 
   if (D->getDeclContext()->isFunctionOrMethod())
     SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
@@ -600,8 +611,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
   // 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() && D->getDefinition())
-    InstantiateEnumDefinition(Enum, D);
+  if (!Enum->isScoped() && Def)
+    InstantiateEnumDefinition(Enum, Def);
 
   return Enum;
 }
index 44394296e37d30776a30a9ada1003ac0c3c966b4..c842dcde848a602801c22a8c8b970b10214524cb 100644 (file)
@@ -195,8 +195,29 @@ namespace test8 {
     enum A : int; // expected-note {{here}}
     enum class B; // expected-note {{here}}
     enum class C : int; // expected-note {{here}}
+    enum class D : int; // expected-note {{here}}
   };
   template<typename T> enum S<T>::A { a }; // expected-error {{previously declared with fixed underlying type}}
   template<typename T> enum class S<T>::B : char { b }; // expected-error {{redeclared with different underlying}}
   template<typename T> enum S<T>::C : int { c }; // expected-error {{previously declared as scoped}}
+  template<typename T> enum class S<T>::D : char { d }; // expected-error {{redeclared with different underlying}}
+}
+
+namespace test9 {
+  template<typename T> struct S {
+    enum class ET : T; // expected-note 2{{here}}
+    enum class Eint : int; // expected-note 2{{here}}
+  };
+  template<> enum class S<int>::ET : int {};
+  template<> enum class S<char>::ET : short {}; // expected-error {{different underlying type}}
+  template<> enum class S<int>::Eint : short {}; // expected-error {{different underlying type}}
+  template<> enum class S<char>::Eint : int {};
+
+  template<typename T> enum class S<T>::ET : int {}; // expected-error {{different underlying type 'int' (was 'short')}}
+  template<typename T> enum class S<T>::Eint : T {}; // expected-error {{different underlying type 'short' (was 'int')}}
+
+  // The implicit instantiation of S<short> causes the implicit instantiation of
+  // all declarations of member enumerations, so is ill-formed, even though we
+  // never instantiate the definitions of S<short>::ET nor S<short>::Eint.
+  S<short> s; // expected-note {{in instantiation of}}
 }