From: Richard Smith Date: Mon, 26 Mar 2012 04:08:46 +0000 (+0000) Subject: Delay checking of dependent underlying types for redeclarations of member X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ca93d9978aac02b01814b4f749d6903a1f87ee5;p=clang Delay checking of dependent underlying types for redeclarations of member 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 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 68b27ef1f9..e92b3e4aca 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ebc43d443d..caf134e025 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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; } diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp index 44394296e3..c842dcde84 100644 --- a/test/SemaCXX/enum-scoped.cpp +++ b/test/SemaCXX/enum-scoped.cpp @@ -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 enum S::A { a }; // expected-error {{previously declared with fixed underlying type}} template enum class S::B : char { b }; // expected-error {{redeclared with different underlying}} template enum S::C : int { c }; // expected-error {{previously declared as scoped}} + template enum class S::D : char { d }; // expected-error {{redeclared with different underlying}} +} + +namespace test9 { + template struct S { + enum class ET : T; // expected-note 2{{here}} + enum class Eint : int; // expected-note 2{{here}} + }; + template<> enum class S::ET : int {}; + template<> enum class S::ET : short {}; // expected-error {{different underlying type}} + template<> enum class S::Eint : short {}; // expected-error {{different underlying type}} + template<> enum class S::Eint : int {}; + + template enum class S::ET : int {}; // expected-error {{different underlying type 'int' (was 'short')}} + template enum class S::Eint : T {}; // expected-error {{different underlying type 'short' (was 'int')}} + + // The implicit instantiation of S causes the implicit instantiation of + // all declarations of member enumerations, so is ill-formed, even though we + // never instantiate the definitions of S::ET nor S::Eint. + S s; // expected-note {{in instantiation of}} }