Instantiating a class template should not instantiate the definition of any

scoped enumeration members. Later uses of an enumeration temploid as a nested
name specifier should cause its instantiation. Plus some groundwork for
explicit specialization of member enumerations of class templates.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152750 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2012-03-14 23:13:10 +00:00
Родитель 59e7f4e6e6
Коммит f1c66b4021
16 изменённых файлов: 492 добавлений и 142 удалений

Просмотреть файл

@ -2458,7 +2458,7 @@ private:
/// in the syntax of a declarator. /// in the syntax of a declarator.
bool IsEmbeddedInDeclarator : 1; bool IsEmbeddedInDeclarator : 1;
/// /brief True if this tag is free standing, e.g. "struct foo;". /// \brief True if this tag is free standing, e.g. "struct foo;".
bool IsFreeStanding : 1; bool IsFreeStanding : 1;
protected: protected:
@ -2467,7 +2467,7 @@ protected:
unsigned NumNegativeBits : 8; unsigned NumNegativeBits : 8;
/// IsScoped - True if this tag declaration is a scoped enumeration. Only /// IsScoped - True if this tag declaration is a scoped enumeration. Only
/// possible in C++0x mode. /// possible in C++11 mode.
bool IsScoped : 1; bool IsScoped : 1;
/// IsScopedUsingClassTag - If this tag declaration is a scoped enum, /// IsScopedUsingClassTag - If this tag declaration is a scoped enum,
/// then this is true if the scoped enum was declared using the class /// then this is true if the scoped enum was declared using the class
@ -2476,7 +2476,7 @@ protected:
bool IsScopedUsingClassTag : 1; bool IsScopedUsingClassTag : 1;
/// IsFixed - True if this is an enumeration with fixed underlying type. Only /// IsFixed - True if this is an enumeration with fixed underlying type. Only
/// possible in C++0x mode. /// possible in C++11 or Microsoft extensions mode.
bool IsFixed : 1; bool IsFixed : 1;
private: private:
@ -2671,8 +2671,9 @@ public:
friend class ASTDeclWriter; friend class ASTDeclWriter;
}; };
/// EnumDecl - Represents an enum. As an extension, we allow forward-declared /// EnumDecl - Represents an enum. In C++11, enums can be forward-declared
/// enums. /// with a fixed underlying type, and in C we allow them to be forward-declared
/// with no underlying type as an extension.
class EnumDecl : public TagDecl { class EnumDecl : public TagDecl {
virtual void anchor(); virtual void anchor();
/// IntegerType - This represent the integer type that the enum corresponds /// IntegerType - This represent the integer type that the enum corresponds
@ -2698,10 +2699,10 @@ class EnumDecl : public TagDecl {
/// in C++) are of the enum type instead. /// in C++) are of the enum type instead.
QualType PromotionType; QualType PromotionType;
/// \brief If the enumeration was instantiated from an enumeration /// \brief If this enumeration is an instantiation of a member enumeration
/// within a class or function template, this pointer refers to the /// of a class template specialization, this is the member specialization
/// enumeration declared within the template. /// information.
EnumDecl *InstantiatedFrom; MemberSpecializationInfo *SpecializationInfo;
// The number of positive and negative bits required by the // The number of positive and negative bits required by the
// enumerators are stored in the SubclassBits field. // enumerators are stored in the SubclassBits field.
@ -2714,7 +2715,7 @@ class EnumDecl : public TagDecl {
IdentifierInfo *Id, EnumDecl *PrevDecl, IdentifierInfo *Id, EnumDecl *PrevDecl,
bool Scoped, bool ScopedUsingClassTag, bool Fixed) bool Scoped, bool ScopedUsingClassTag, bool Fixed)
: TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc), : TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc),
InstantiatedFrom(0) { SpecializationInfo(0) {
assert(Scoped || !ScopedUsingClassTag); assert(Scoped || !ScopedUsingClassTag);
IntegerType = (const Type*)0; IntegerType = (const Type*)0;
NumNegativeBits = 0; NumNegativeBits = 0;
@ -2723,6 +2724,9 @@ class EnumDecl : public TagDecl {
IsScopedUsingClassTag = ScopedUsingClassTag; IsScopedUsingClassTag = ScopedUsingClassTag;
IsFixed = Fixed; IsFixed = Fixed;
} }
void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
TemplateSpecializationKind TSK);
public: public:
EnumDecl *getCanonicalDecl() { EnumDecl *getCanonicalDecl() {
return cast<EnumDecl>(TagDecl::getCanonicalDecl()); return cast<EnumDecl>(TagDecl::getCanonicalDecl());
@ -2745,6 +2749,10 @@ public:
return cast<EnumDecl>(TagDecl::getMostRecentDecl()); return cast<EnumDecl>(TagDecl::getMostRecentDecl());
} }
EnumDecl *getDefinition() const {
return cast_or_null<EnumDecl>(TagDecl::getDefinition());
}
static EnumDecl *Create(ASTContext &C, DeclContext *DC, static EnumDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc, SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, EnumDecl *PrevDecl, IdentifierInfo *Id, EnumDecl *PrevDecl,
@ -2767,14 +2775,14 @@ public:
typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator; typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator;
enumerator_iterator enumerator_begin() const { enumerator_iterator enumerator_begin() const {
const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition()); const EnumDecl *E = getDefinition();
if (!E) if (!E)
E = this; E = this;
return enumerator_iterator(E->decls_begin()); return enumerator_iterator(E->decls_begin());
} }
enumerator_iterator enumerator_end() const { enumerator_iterator enumerator_end() const {
const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition()); const EnumDecl *E = getDefinition();
if (!E) if (!E)
E = this; E = this;
return enumerator_iterator(E->decls_end()); return enumerator_iterator(E->decls_end());
@ -2859,11 +2867,21 @@ public:
/// \brief Returns the enumeration (declared within the template) /// \brief Returns the enumeration (declared within the template)
/// from which this enumeration type was instantiated, or NULL if /// from which this enumeration type was instantiated, or NULL if
/// this enumeration was not instantiated from any template. /// this enumeration was not instantiated from any template.
EnumDecl *getInstantiatedFromMemberEnum() const { EnumDecl *getInstantiatedFromMemberEnum() const;
return InstantiatedFrom;
/// \brief If this enumeration is an instantiation of a member enumeration of
/// a class template specialization, retrieves the member specialization
/// information.
MemberSpecializationInfo *getMemberSpecializationInfo() const {
return SpecializationInfo;
} }
void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; } /// \brief Specify that this enumeration is an instantiation of the
/// member enumeration ED.
void setInstantiationOfMemberEnum(EnumDecl *ED,
TemplateSpecializationKind TSK) {
setInstantiationOfMemberEnum(getASTContext(), ED, TSK);
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumDecl *D) { return true; } static bool classof(const EnumDecl *D) { return true; }

Просмотреть файл

@ -355,8 +355,8 @@ public:
}; };
/// \brief Provides information a specialization of a member of a class /// \brief Provides information a specialization of a member of a class
/// template, which may be a member function, static data member, or /// template, which may be a member function, static data member,
/// member class. /// member class or member enumeration.
class MemberSpecializationInfo { class MemberSpecializationInfo {
// The member declaration from which this member was instantiated, and the // The member declaration from which this member was instantiated, and the
// manner in which the instantiation occurred (in the lower two bits). // manner in which the instantiation occurred (in the lower two bits).

Просмотреть файл

@ -2529,6 +2529,8 @@ def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">; "in instantiation of function template specialization %q0 requested here">;
def note_template_static_data_member_def_here : Note< def note_template_static_data_member_def_here : Note<
"in instantiation of static data member %q0 requested here">; "in instantiation of static data member %q0 requested here">;
def note_template_enum_def_here : Note<
"in instantiation of enumeration %q0 requested here">;
def note_template_type_alias_instantiation_here : Note< def note_template_type_alias_instantiation_here : Note<
"in instantiation of template type alias %0 requested here">; "in instantiation of template type alias %0 requested here">;

Просмотреть файл

@ -1343,6 +1343,9 @@ public:
SourceLocation IdLoc, SourceLocation IdLoc,
IdentifierInfo *Id, IdentifierInfo *Id,
Expr *val); Expr *val);
bool CheckEnumUnderlyingType(TypeSourceInfo *TI);
bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
QualType EnumUnderlyingTy, const EnumDecl *Prev);
Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, IdentifierInfo *Id,
@ -5489,6 +5492,11 @@ public:
TemplateSpecializationKind TSK, TemplateSpecializationKind TSK,
bool Complain = true); bool Complain = true);
bool InstantiateEnum(SourceLocation PointOfInstantiation,
EnumDecl *Instantiation, EnumDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK);
struct LateInstantiatedAttribute { struct LateInstantiatedAttribute {
const Attr *TmplAttr; const Attr *TmplAttr;
LocalInstantiationScope *Scope; LocalInstantiationScope *Scope;

Просмотреть файл

@ -484,6 +484,7 @@ namespace clang {
InstantiateClassTemplatePartialSpecialization( InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate, ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec); ClassTemplatePartialSpecializationDecl *PartialSpec);
void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern);
}; };
} }

Просмотреть файл

@ -2674,6 +2674,19 @@ void EnumDecl::completeDefinition(QualType NewType,
TagDecl::completeDefinition(); TagDecl::completeDefinition();
} }
EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const {
if (SpecializationInfo)
return cast<EnumDecl>(SpecializationInfo->getInstantiatedFrom());
return 0;
}
void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
TemplateSpecializationKind TSK) {
assert(!SpecializationInfo && "Member enum is already a specialization");
SpecializationInfo = new (C) MemberSpecializationInfo(ED, TSK);
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// RecordDecl Implementation // RecordDecl Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

Просмотреть файл

@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h" #include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprCXX.h"
@ -209,43 +210,52 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
DeclContext *DC) { DeclContext *DC) {
assert(DC != 0 && "given null context"); assert(DC != 0 && "given null context");
if (TagDecl *tag = dyn_cast<TagDecl>(DC)) { TagDecl *tag = dyn_cast<TagDecl>(DC);
// If this is a dependent type, then we consider it complete.
if (tag->isDependentContext())
return false;
// If we're currently defining this type, then lookup into the // If this is a dependent type, then we consider it complete.
// type is okay: don't complain that it isn't complete yet. if (!tag || tag->isDependentContext())
QualType type = Context.getTypeDeclType(tag); return false;
const TagType *tagType = type->getAs<TagType>();
if (tagType && tagType->isBeingDefined())
return false;
SourceLocation loc = SS.getLastQualifierNameLoc(); // If we're currently defining this type, then lookup into the
if (loc.isInvalid()) loc = SS.getRange().getBegin(); // type is okay: don't complain that it isn't complete yet.
QualType type = Context.getTypeDeclType(tag);
const TagType *tagType = type->getAs<TagType>();
if (tagType && tagType->isBeingDefined())
return false;
// The type must be complete. SourceLocation loc = SS.getLastQualifierNameLoc();
if (RequireCompleteType(loc, type, if (loc.isInvalid()) loc = SS.getRange().getBegin();
PDiag(diag::err_incomplete_nested_name_spec)
<< SS.getRange())) {
SS.SetInvalid(SS.getRange());
return true;
}
// Fixed enum types are complete, but they aren't valid as scopes // The type must be complete.
// until we see a definition, so awkwardly pull out this special if (RequireCompleteType(loc, type,
// case. PDiag(diag::err_incomplete_nested_name_spec)
if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) { << SS.getRange())) {
if (!enumType->getDecl()->isCompleteDefinition()) { SS.SetInvalid(SS.getRange());
Diag(loc, diag::err_incomplete_nested_name_spec) return true;
<< type << SS.getRange();
SS.SetInvalid(SS.getRange());
return true;
}
}
} }
return false; // Fixed enum types are complete, but they aren't valid as scopes
// until we see a definition, so awkwardly pull out this special
// case.
const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
if (!enumType || enumType->getDecl()->isCompleteDefinition())
return false;
// Try to instantiate the definition, if this is a specialization of an
// enumeration temploid.
EnumDecl *ED = enumType->getDecl();
if (EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
MemberSpecializationInfo *MSI = ED->getMemberSpecializationInfo();
if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
return InstantiateEnum(loc, ED, Pattern,
getTemplateInstantiationArgs(ED),
TSK_ImplicitInstantiation);
}
Diag(loc, diag::err_incomplete_nested_name_spec)
<< type << SS.getRange();
SS.SetInvalid(SS.getRange());
return true;
} }
bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc, bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,

Просмотреть файл

@ -7738,6 +7738,50 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
} }
/// \brief Check that this is a valid underlying type for an enum declaration.
bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
QualType T = TI->getType();
if (T->isDependentType() || T->isIntegralType(Context))
return false;
Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
return true;
}
/// Check whether this is a valid redeclaration of a previous enumeration.
/// \return true if the redeclaration was invalid.
bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
QualType EnumUnderlyingTy,
const EnumDecl *Prev) {
bool IsFixed = !EnumUnderlyingTy.isNull();
if (IsScoped != Prev->isScoped()) {
Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch)
<< Prev->isScoped();
Diag(Prev->getLocation(), diag::note_previous_use);
return true;
}
if (IsFixed && Prev->isFixed()) {
if (!Context.hasSameUnqualifiedType(EnumUnderlyingTy,
Prev->getIntegerType())) {
Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch)
<< EnumUnderlyingTy << Prev->getIntegerType();
Diag(Prev->getLocation(), diag::note_previous_use);
return true;
}
} else if (IsFixed != Prev->isFixed()) {
Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch)
<< Prev->isFixed();
Diag(Prev->getLocation(), diag::note_previous_use);
return true;
}
return false;
}
/// \brief Determine whether a tag with a given kind is acceptable /// \brief Determine whether a tag with a given kind is acceptable
/// as a redeclaration of the given tag declaration. /// as a redeclaration of the given tag declaration.
/// ///
@ -7913,16 +7957,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
QualType T = GetTypeFromParser(UnderlyingType.get(), &TI); QualType T = GetTypeFromParser(UnderlyingType.get(), &TI);
EnumUnderlying = TI; EnumUnderlying = TI;
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); if (CheckEnumUnderlyingType(TI))
if (!T->isDependentType() && !T->isIntegralType(Context)) {
Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
<< T;
// Recover by falling back to int. // Recover by falling back to int.
EnumUnderlying = Context.IntTy.getTypePtr(); EnumUnderlying = Context.IntTy.getTypePtr();
}
if (DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI, if (DiagnoseUnexpandedParameterPack(TI->getTypeLoc().getBeginLoc(), TI,
UPPC_FixedUnderlyingType)) UPPC_FixedUnderlyingType))
EnumUnderlying = Context.IntTy.getTypePtr(); EnumUnderlying = Context.IntTy.getTypePtr();
@ -8196,37 +8235,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
return PrevTagDecl; return PrevTagDecl;
} }
QualType EnumUnderlyingTy;
if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
EnumUnderlyingTy = TI->getType();
else if (const Type *T = EnumUnderlying.dyn_cast<const Type*>())
EnumUnderlyingTy = QualType(T, 0);
// All conflicts with previous declarations are recovered by // All conflicts with previous declarations are recovered by
// returning the previous declaration. // returning the previous declaration.
if (ScopedEnum != PrevEnum->isScoped()) { if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc,
Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch) ScopedEnum, EnumUnderlyingTy, PrevEnum))
<< PrevEnum->isScoped();
Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
return PrevTagDecl; return PrevTagDecl;
}
else if (EnumUnderlying && PrevEnum->isFixed()) {
QualType T;
if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
T = TI->getType();
else
T = QualType(EnumUnderlying.get<const Type*>(), 0);
if (!Context.hasSameUnqualifiedType(T,
PrevEnum->getIntegerType())) {
Diag(NameLoc.isValid() ? NameLoc : KWLoc,
diag::err_enum_redeclare_type_mismatch)
<< T
<< PrevEnum->getIntegerType();
Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
return PrevTagDecl;
}
}
else if (!EnumUnderlying.isNull() != PrevEnum->isFixed()) {
Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch)
<< PrevEnum->isFixed();
Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
return PrevTagDecl;
}
} }
if (!Invalid) { if (!Invalid) {

Просмотреть файл

@ -469,6 +469,11 @@ void Sema::PrintInstantiationStack() {
diag::note_template_static_data_member_def_here) diag::note_template_static_data_member_def_here)
<< VD << VD
<< Active->InstantiationRange; << Active->InstantiationRange;
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_enum_def_here)
<< ED
<< Active->InstantiationRange;
} else { } else {
Diags.Report(Active->PointOfInstantiation, Diags.Report(Active->PointOfInstantiation,
diag::note_template_type_alias_instantiation_here) diag::note_template_type_alias_instantiation_here)
@ -1680,6 +1685,51 @@ namespace clang {
} }
} }
/// Determine whether we would be unable to instantiate this template (because
/// it either has no definition, or is in the process of being instantiated).
static bool DiagnoseUninstantiableTemplate(Sema &S,
SourceLocation PointOfInstantiation,
TagDecl *Instantiation,
bool InstantiatedFromMember,
TagDecl *Pattern,
TagDecl *PatternDef,
TemplateSpecializationKind TSK,
bool Complain = true) {
if (PatternDef && !PatternDef->isBeingDefined())
return false;
if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
// Say nothing
} else if (PatternDef) {
assert(PatternDef->isBeingDefined());
S.Diag(PointOfInstantiation,
diag::err_template_instantiate_within_definition)
<< (TSK != TSK_ImplicitInstantiation)
<< S.Context.getTypeDeclType(Instantiation);
// Not much point in noting the template declaration here, since
// we're lexically inside it.
Instantiation->setInvalidDecl();
} else if (InstantiatedFromMember) {
S.Diag(PointOfInstantiation,
diag::err_implicit_instantiate_member_undefined)
<< S.Context.getTypeDeclType(Instantiation);
S.Diag(Pattern->getLocation(), diag::note_member_of_template_here);
} else {
S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
<< (TSK != TSK_ImplicitInstantiation)
<< S.Context.getTypeDeclType(Instantiation);
S.Diag(Pattern->getLocation(), diag::note_template_decl_here);
}
// In general, Instantiation isn't marked invalid to get more than one
// error for multiple undefined instantiations. But the code that does
// explicit declaration -> explicit definition conversion can't handle
// invalid declarations, so mark as invalid in that case.
if (TSK == TSK_ExplicitInstantiationDeclaration)
Instantiation->setInvalidDecl();
return true;
}
/// \brief Instantiate the definition of a class from a given pattern. /// \brief Instantiate the definition of a class from a given pattern.
/// ///
/// \param PointOfInstantiation The point of instantiation within the /// \param PointOfInstantiation The point of instantiation within the
@ -1712,38 +1762,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *PatternDef CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); = cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
if (!PatternDef || PatternDef->isBeingDefined()) { if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { Instantiation->getInstantiatedFromMemberClass(),
// Say nothing Pattern, PatternDef, TSK, Complain))
} else if (PatternDef) {
assert(PatternDef->isBeingDefined());
Diag(PointOfInstantiation,
diag::err_template_instantiate_within_definition)
<< (TSK != TSK_ImplicitInstantiation)
<< Context.getTypeDeclType(Instantiation);
// Not much point in noting the template declaration here, since
// we're lexically inside it.
Instantiation->setInvalidDecl();
} else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
Diag(PointOfInstantiation,
diag::err_implicit_instantiate_member_undefined)
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_member_of_template_here);
} else {
Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
<< (TSK != TSK_ImplicitInstantiation)
<< Context.getTypeDeclType(Instantiation);
Diag(Pattern->getLocation(), diag::note_template_decl_here);
}
// In general, Instantiation isn't marked invalid to get more than one
// error for multiple undefined instantiations. But the code that does
// explicit declaration -> explicit definition conversion can't handle
// invalid declarations, so mark as invalid in that case.
if (TSK == TSK_ExplicitInstantiationDeclaration)
Instantiation->setInvalidDecl();
return true; return true;
}
Pattern = PatternDef; Pattern = PatternDef;
// \brief Record the point of instantiation. // \brief Record the point of instantiation.
@ -1911,6 +1933,63 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
return Invalid; return Invalid;
} }
/// \brief Instantiate the definition of an enum from a given pattern.
///
/// \param PointOfInstantiation The point of instantiation within the
/// source code.
/// \param Instantiation is the declaration whose definition is being
/// instantiated. This will be a member enumeration of a class
/// temploid specialization, or a local enumeration within a
/// function temploid specialization.
/// \param Pattern The templated declaration from which the instantiation
/// occurs.
/// \param TemplateArgs The template arguments to be substituted into
/// the pattern.
/// \param TSK The kind of implicit or explicit instantiation to perform.
///
/// \return \c true if an error occurred, \c false otherwise.
bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
EnumDecl *Instantiation, EnumDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK) {
EnumDecl *PatternDef = Pattern->getDefinition();
if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
Instantiation->getInstantiatedFromMemberEnum(),
Pattern, PatternDef, TSK,/*Complain*/true))
return true;
Pattern = PatternDef;
// Record the point of instantiation.
if (MemberSpecializationInfo *MSInfo
= Instantiation->getMemberSpecializationInfo()) {
MSInfo->setTemplateSpecializationKind(TSK);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst)
return true;
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
EnterExpressionEvaluationContext EvalContext(*this,
Sema::PotentiallyEvaluated);
LocalInstantiationScope Scope(*this, /*MergeWithParentScope*/true);
// Pull attributes from the pattern onto the instantiation.
InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
Instantiator.InstantiateEnumDefinition(Instantiation, Pattern);
// Exit the scope of this instantiation.
SavedContext.pop();
return Instantiation->isInvalidDecl();
}
namespace { namespace {
/// \brief A partial specialization whose template arguments have matched /// \brief A partial specialization whose template arguments have matched
/// a given template-id. /// a given template-id.
@ -2231,6 +2310,36 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (Pattern) if (Pattern)
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
TSK); TSK);
} else if (EnumDecl *Enum = dyn_cast<EnumDecl>(*D)) {
MemberSpecializationInfo *MSInfo = Enum->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
if (MSInfo->getTemplateSpecializationKind()
== TSK_ExplicitSpecialization)
continue;
if (CheckSpecializationInstantiationRedecl(
PointOfInstantiation, TSK, Enum,
MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation(), SuppressNew) ||
SuppressNew)
continue;
if (Enum->getDefinition())
continue;
EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum();
assert(Pattern && "Missing instantiated-from-template information");
if (TSK == TSK_ExplicitInstantiationDefinition) {
if (!Pattern->getDefinition())
continue;
InstantiateEnum(PointOfInstantiation, Enum, Pattern, TemplateArgs, TSK);
} else {
MSInfo->setTemplateSpecializationKind(TSK);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
}
} }
} }
} }

Просмотреть файл

@ -563,20 +563,18 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
/*PrevDecl=*/0, D->isScoped(), /*PrevDecl=*/0, D->isScoped(),
D->isScopedUsingClassTag(), D->isFixed()); D->isScopedUsingClassTag(), D->isFixed());
if (D->isFixed()) { if (D->isFixed()) {
if (TypeSourceInfo* TI = D->getIntegerTypeSourceInfo()) { if (TypeSourceInfo *TI = D->getIntegerTypeSourceInfo()) {
// If we have type source information for the underlying type, it means it // If we have type source information for the underlying type, it means it
// has been explicitly set by the user. Perform substitution on it before // has been explicitly set by the user. Perform substitution on it before
// moving on. // moving on.
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
Enum->setIntegerTypeSourceInfo(SemaRef.SubstType(TI, TypeSourceInfo *NewTI = SemaRef.SubstType(TI, TemplateArgs, UnderlyingLoc,
TemplateArgs, DeclarationName());
UnderlyingLoc, if (!NewTI || SemaRef.CheckEnumUnderlyingType(NewTI))
DeclarationName()));
if (!Enum->getIntegerTypeSourceInfo())
Enum->setIntegerType(SemaRef.Context.IntTy); Enum->setIntegerType(SemaRef.Context.IntTy);
} else
else { Enum->setIntegerTypeSourceInfo(NewTI);
} else {
assert(!D->getIntegerType()->isDependentType() assert(!D->getIntegerType()->isDependentType()
&& "Dependent type without type source info"); && "Dependent type without type source info");
Enum->setIntegerType(D->getIntegerType()); Enum->setIntegerType(D->getIntegerType());
@ -585,20 +583,38 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
SemaRef.InstantiateAttrs(TemplateArgs, D, Enum); SemaRef.InstantiateAttrs(TemplateArgs, D, Enum);
Enum->setInstantiationOfMemberEnum(D); Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
Enum->setAccess(D->getAccess()); Enum->setAccess(D->getAccess());
if (SubstQualifier(D, Enum)) return 0; if (SubstQualifier(D, Enum)) return 0;
Owner->addDecl(Enum); Owner->addDecl(Enum);
Enum->startDefinition();
// FIXME: If this is a redeclaration:
// CheckEnumRedeclaration(Enum->getLocation(), Enum->isScoped(),
// Enum->getIntegerType(), Prev);
if (D->getDeclContext()->isFunctionOrMethod()) if (D->getDeclContext()->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum); SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
// C++11 [temp.inst]p1: The implicit instantiation of a class template
// 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())
InstantiateEnumDefinition(Enum, D);
return Enum;
}
void TemplateDeclInstantiator::InstantiateEnumDefinition(
EnumDecl *Enum, EnumDecl *Pattern) {
Enum->startDefinition();
SmallVector<Decl*, 4> Enumerators; SmallVector<Decl*, 4> Enumerators;
EnumConstantDecl *LastEnumConst = 0; EnumConstantDecl *LastEnumConst = 0;
for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(), for (EnumDecl::enumerator_iterator EC = Pattern->enumerator_begin(),
ECEnd = D->enumerator_end(); ECEnd = Pattern->enumerator_end();
EC != ECEnd; ++EC) { EC != ECEnd; ++EC) {
// The specified value for the enumerator. // The specified value for the enumerator.
ExprResult Value = SemaRef.Owned((Expr *)0); ExprResult Value = SemaRef.Owned((Expr *)0);
@ -636,7 +652,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
Enumerators.push_back(EnumConst); Enumerators.push_back(EnumConst);
LastEnumConst = EnumConst; LastEnumConst = EnumConst;
if (D->getDeclContext()->isFunctionOrMethod()) { if (Pattern->getDeclContext()->isFunctionOrMethod() &&
!Enum->isScoped()) {
// If the enumeration is within a function or method, record the enum // If the enumeration is within a function or method, record the enum
// constant as a local. // constant as a local.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst); SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
@ -644,14 +661,11 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
} }
} }
// FIXME: Fixup LBraceLoc and RBraceLoc // FIXME: Fixup LBraceLoc
// FIXME: Empty Scope and AttributeList (required to handle attribute packed). SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(),
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(), Enum->getRBraceLoc(), Enum,
Enum,
Enumerators.data(), Enumerators.size(), Enumerators.data(), Enumerators.size(),
0, 0); 0, 0);
return Enum;
} }
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {

Просмотреть файл

@ -453,7 +453,13 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
ED->IsScoped = Record[Idx++]; ED->IsScoped = Record[Idx++];
ED->IsScopedUsingClassTag = Record[Idx++]; ED->IsScopedUsingClassTag = Record[Idx++];
ED->IsFixed = Record[Idx++]; ED->IsFixed = Record[Idx++];
ED->setInstantiationOfMemberEnum(ReadDeclAs<EnumDecl>(Record, Idx));
if (EnumDecl *InstED = ReadDeclAs<EnumDecl>(Record, Idx)) {
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK);
ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
}
} }
void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) { void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {

Просмотреть файл

@ -230,7 +230,13 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.push_back(D->isScoped()); Record.push_back(D->isScoped());
Record.push_back(D->isScopedUsingClassTag()); Record.push_back(D->isScopedUsingClassTag());
Record.push_back(D->isFixed()); Record.push_back(D->isFixed());
Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record); if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
Record.push_back(MemberInfo->getTemplateSpecializationKind());
Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
} else {
Writer.AddDeclRef(0, Record);
}
if (!D->hasAttrs() && if (!D->hasAttrs() &&
!D->isImplicit() && !D->isImplicit() &&

Просмотреть файл

@ -1,16 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T> template<typename T>
struct X0 { struct X0 {
struct MemberClass; struct MemberClass;
T* f0(T* ptr); T* f0(T* ptr);
static T* static_member; static T* static_member;
}; };
template class X0<int>; // okay template class X0<int(int)>; // ok; nothing gets instantiated.
template class X0<int(int)>; // okay; nothing gets instantiated.
template<typename T> template<typename T>
struct X0<T>::MemberClass { struct X0<T>::MemberClass {
@ -25,3 +24,17 @@ T* X0<T>::f0(T* ptr) {
template<typename T> template<typename T>
T* X0<T>::static_member = 0; T* X0<T>::static_member = 0;
template class X0<int>; // ok
template<typename T>
struct X1 {
enum class E {
e = T::error // expected-error 2{{no members}}
};
};
template struct X1<int>; // expected-note {{here}}
extern template struct X1<char>; // ok
template struct X1<char>; // expected-note {{here}}

Просмотреть файл

@ -0,0 +1,104 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
// The implicit specialization of a class template specialuzation causes the
// implicit instantiation of the declarations, but not the definitions or
// default arguments, of:
// FIXME: Many omitted cases
// - scoped member enumerations
namespace ScopedEnum {
template<typename T> struct ScopedEnum1 {
enum class E {
e = T::error // expected-error {{'double' cannot be used prior to '::'}}
};
};
ScopedEnum1<int> se1; // ok
template<typename T> struct ScopedEnum2 {
enum class E : T { // expected-error {{non-integral type 'void *' is an invalid underlying type}}
e = 0
};
};
ScopedEnum2<void*> se2; // expected-note {{here}}
template<typename T> struct UnscopedEnum3 {
enum class E : T {
e = 4
};
int arr[(int)E::e];
};
UnscopedEnum3<int> ue3; // ok
ScopedEnum1<double>::E e1; // ok
ScopedEnum1<double>::E e2 = decltype(e2)::e; // expected-note {{in instantiation of enumeration 'ScopedEnum::ScopedEnum1<double>::E' requested here}}
// The behavior for enums defined within function templates is not clearly
// specified by the standard. We follow the rules for enums defined within
// class templates.
template<typename T>
int f() {
enum class E {
e = T::error
};
return (int)E();
}
int test1 = f<int>();
template<typename T>
int g() {
enum class E {
e = T::error // expected-error {{has no members}}
};
return E::e; // expected-note {{here}}
}
int test2 = g<int>(); // expected-note {{here}}
}
// And it cases the implicit instantiations of the definitions of:
// - unscoped member enumerations
namespace UnscopedEnum {
template<typename T> struct UnscopedEnum1 {
enum E {
e = T::error // expected-error {{'int' cannot be used prior to '::'}}
};
};
UnscopedEnum1<int> ue1; // expected-note {{here}}
template<typename T> struct UnscopedEnum2 {
enum E : T { // expected-error {{non-integral type 'void *' is an invalid underlying type}}
e = 0
};
};
UnscopedEnum2<void*> ue2; // expected-note {{here}}
template<typename T> struct UnscopedEnum3 {
enum E : T {
e = 4
};
int arr[E::e];
};
UnscopedEnum3<int> ue3; // ok
template<typename T>
int f() {
enum E {
e = T::error // expected-error {{has no members}}
};
return (int)E();
}
int test1 = f<int>(); // expected-note {{here}}
template<typename T>
int g() {
enum E {
e = T::error // expected-error {{has no members}}
};
return E::e;
}
int test2 = g<int>(); // expected-note {{here}}
}
// FIXME:
//- - member anonymous unions

Просмотреть файл

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
template<typename T> struct S {
enum class E {
e = T() // expected-error {{conversion from 'double' to 'int'}}
};
};
S<int> a;
S<long>::E b;
S<double>::E c;
template struct S<char>;
#else
int k1 = (int)S<int>::E::e;
int k2 = (int)decltype(b)::e;
int k3 = (int)decltype(c)::e; // expected-note {{here}}
int k4 = (int)S<char>::E::e;
#endif

Просмотреть файл

@ -156,7 +156,8 @@ with clang; other versions have not been tested.</p>
</tr> </tr>
<tr> <tr>
<td>Forward declarations for enums</td> <td>Forward declarations for enums</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764</a>
<br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1206">DR1206</a></td>
<td class="none" align="center">No</td> <td class="none" align="center">No</td>
</tr> </tr>
<tr> <tr>