Delay checking of dependent underlying types for redeclarations of member

enumerations in templates until the template is instantiated.

llvm-svn: 153426
This commit is contained in:
Richard Smith 2012-03-26 04:08:46 +00:00
parent eb75cc26af
commit 258a744bbd
3 changed files with 40 additions and 6 deletions

View 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();

View 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;
}

View 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}}
}