forked from OSchip/llvm-project
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. llvm-svn: 152750
This commit is contained in:
parent
be84d85905
commit
4b38ded66a
|
@ -2458,7 +2458,7 @@ private:
|
|||
/// in the syntax of a declarator.
|
||||
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;
|
||||
|
||||
protected:
|
||||
|
@ -2467,7 +2467,7 @@ protected:
|
|||
unsigned NumNegativeBits : 8;
|
||||
|
||||
/// IsScoped - True if this tag declaration is a scoped enumeration. Only
|
||||
/// possible in C++0x mode.
|
||||
/// possible in C++11 mode.
|
||||
bool IsScoped : 1;
|
||||
/// IsScopedUsingClassTag - If this tag declaration is a scoped enum,
|
||||
/// then this is true if the scoped enum was declared using the class
|
||||
|
@ -2476,7 +2476,7 @@ protected:
|
|||
bool IsScopedUsingClassTag : 1;
|
||||
|
||||
/// 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;
|
||||
|
||||
private:
|
||||
|
@ -2671,8 +2671,9 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
|
||||
/// enums.
|
||||
/// EnumDecl - Represents an enum. In C++11, enums can be forward-declared
|
||||
/// 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 {
|
||||
virtual void anchor();
|
||||
/// 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.
|
||||
QualType PromotionType;
|
||||
|
||||
/// \brief If the enumeration was instantiated from an enumeration
|
||||
/// within a class or function template, this pointer refers to the
|
||||
/// enumeration declared within the template.
|
||||
EnumDecl *InstantiatedFrom;
|
||||
/// \brief If this enumeration is an instantiation of a member enumeration
|
||||
/// of a class template specialization, this is the member specialization
|
||||
/// information.
|
||||
MemberSpecializationInfo *SpecializationInfo;
|
||||
|
||||
// The number of positive and negative bits required by the
|
||||
// enumerators are stored in the SubclassBits field.
|
||||
|
@ -2714,7 +2715,7 @@ class EnumDecl : public TagDecl {
|
|||
IdentifierInfo *Id, EnumDecl *PrevDecl,
|
||||
bool Scoped, bool ScopedUsingClassTag, bool Fixed)
|
||||
: TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc),
|
||||
InstantiatedFrom(0) {
|
||||
SpecializationInfo(0) {
|
||||
assert(Scoped || !ScopedUsingClassTag);
|
||||
IntegerType = (const Type*)0;
|
||||
NumNegativeBits = 0;
|
||||
|
@ -2723,6 +2724,9 @@ class EnumDecl : public TagDecl {
|
|||
IsScopedUsingClassTag = ScopedUsingClassTag;
|
||||
IsFixed = Fixed;
|
||||
}
|
||||
|
||||
void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
|
||||
TemplateSpecializationKind TSK);
|
||||
public:
|
||||
EnumDecl *getCanonicalDecl() {
|
||||
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
|
||||
|
@ -2745,6 +2749,10 @@ public:
|
|||
return cast<EnumDecl>(TagDecl::getMostRecentDecl());
|
||||
}
|
||||
|
||||
EnumDecl *getDefinition() const {
|
||||
return cast_or_null<EnumDecl>(TagDecl::getDefinition());
|
||||
}
|
||||
|
||||
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, EnumDecl *PrevDecl,
|
||||
|
@ -2767,14 +2775,14 @@ public:
|
|||
typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator;
|
||||
|
||||
enumerator_iterator enumerator_begin() const {
|
||||
const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition());
|
||||
const EnumDecl *E = getDefinition();
|
||||
if (!E)
|
||||
E = this;
|
||||
return enumerator_iterator(E->decls_begin());
|
||||
}
|
||||
|
||||
enumerator_iterator enumerator_end() const {
|
||||
const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition());
|
||||
const EnumDecl *E = getDefinition();
|
||||
if (!E)
|
||||
E = this;
|
||||
return enumerator_iterator(E->decls_end());
|
||||
|
@ -2859,11 +2867,21 @@ public:
|
|||
/// \brief Returns the enumeration (declared within the template)
|
||||
/// from which this enumeration type was instantiated, or NULL if
|
||||
/// this enumeration was not instantiated from any template.
|
||||
EnumDecl *getInstantiatedFromMemberEnum() const {
|
||||
return InstantiatedFrom;
|
||||
EnumDecl *getInstantiatedFromMemberEnum() const;
|
||||
|
||||
/// \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 EnumDecl *D) { return true; }
|
||||
|
|
|
@ -355,8 +355,8 @@ public:
|
|||
};
|
||||
|
||||
/// \brief Provides information a specialization of a member of a class
|
||||
/// template, which may be a member function, static data member, or
|
||||
/// member class.
|
||||
/// template, which may be a member function, static data member,
|
||||
/// member class or member enumeration.
|
||||
class MemberSpecializationInfo {
|
||||
// The member declaration from which this member was instantiated, and the
|
||||
// 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">;
|
||||
def note_template_static_data_member_def_here : Note<
|
||||
"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<
|
||||
"in instantiation of template type alias %0 requested here">;
|
||||
|
||||
|
|
|
@ -1343,6 +1343,9 @@ public:
|
|||
SourceLocation IdLoc,
|
||||
IdentifierInfo *Id,
|
||||
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,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
|
@ -5489,6 +5492,11 @@ public:
|
|||
TemplateSpecializationKind TSK,
|
||||
bool Complain = true);
|
||||
|
||||
bool InstantiateEnum(SourceLocation PointOfInstantiation,
|
||||
EnumDecl *Instantiation, EnumDecl *Pattern,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
TemplateSpecializationKind TSK);
|
||||
|
||||
struct LateInstantiatedAttribute {
|
||||
const Attr *TmplAttr;
|
||||
LocalInstantiationScope *Scope;
|
||||
|
|
|
@ -484,6 +484,7 @@ namespace clang {
|
|||
InstantiateClassTemplatePartialSpecialization(
|
||||
ClassTemplateDecl *ClassTemplate,
|
||||
ClassTemplatePartialSpecializationDecl *PartialSpec);
|
||||
void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2674,6 +2674,19 @@ void EnumDecl::completeDefinition(QualType NewType,
|
|||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "clang/Sema/SemaInternal.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
@ -209,43 +210,52 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
|
|||
DeclContext *DC) {
|
||||
assert(DC != 0 && "given null context");
|
||||
|
||||
if (TagDecl *tag = dyn_cast<TagDecl>(DC)) {
|
||||
// If this is a dependent type, then we consider it complete.
|
||||
if (tag->isDependentContext())
|
||||
return false;
|
||||
TagDecl *tag = dyn_cast<TagDecl>(DC);
|
||||
|
||||
// If we're currently defining this type, then lookup into the
|
||||
// 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;
|
||||
// If this is a dependent type, then we consider it complete.
|
||||
if (!tag || tag->isDependentContext())
|
||||
return false;
|
||||
|
||||
SourceLocation loc = SS.getLastQualifierNameLoc();
|
||||
if (loc.isInvalid()) loc = SS.getRange().getBegin();
|
||||
// If we're currently defining this type, then lookup into the
|
||||
// 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.
|
||||
if (RequireCompleteType(loc, type,
|
||||
PDiag(diag::err_incomplete_nested_name_spec)
|
||||
<< SS.getRange())) {
|
||||
SS.SetInvalid(SS.getRange());
|
||||
return true;
|
||||
}
|
||||
SourceLocation loc = SS.getLastQualifierNameLoc();
|
||||
if (loc.isInvalid()) loc = SS.getRange().getBegin();
|
||||
|
||||
// Fixed enum types are complete, but they aren't valid as scopes
|
||||
// until we see a definition, so awkwardly pull out this special
|
||||
// case.
|
||||
if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) {
|
||||
if (!enumType->getDecl()->isCompleteDefinition()) {
|
||||
Diag(loc, diag::err_incomplete_nested_name_spec)
|
||||
<< type << SS.getRange();
|
||||
SS.SetInvalid(SS.getRange());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// The type must be complete.
|
||||
if (RequireCompleteType(loc, type,
|
||||
PDiag(diag::err_incomplete_nested_name_spec)
|
||||
<< 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,
|
||||
|
|
|
@ -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
|
||||
/// 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);
|
||||
EnumUnderlying = TI;
|
||||
|
||||
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
|
||||
|
||||
if (!T->isDependentType() && !T->isIntegralType(Context)) {
|
||||
Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
|
||||
<< T;
|
||||
if (CheckEnumUnderlyingType(TI))
|
||||
// Recover by falling back to int.
|
||||
EnumUnderlying = Context.IntTy.getTypePtr();
|
||||
}
|
||||
|
||||
if (DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI,
|
||||
if (DiagnoseUnexpandedParameterPack(TI->getTypeLoc().getBeginLoc(), TI,
|
||||
UPPC_FixedUnderlyingType))
|
||||
EnumUnderlying = Context.IntTy.getTypePtr();
|
||||
|
||||
|
@ -8196,37 +8235,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
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
|
||||
// returning the previous declaration.
|
||||
if (ScopedEnum != PrevEnum->isScoped()) {
|
||||
Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch)
|
||||
<< PrevEnum->isScoped();
|
||||
Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
|
||||
if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc,
|
||||
ScopedEnum, EnumUnderlyingTy, PrevEnum))
|
||||
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) {
|
||||
|
|
|
@ -469,6 +469,11 @@ void Sema::PrintInstantiationStack() {
|
|||
diag::note_template_static_data_member_def_here)
|
||||
<< VD
|
||||
<< Active->InstantiationRange;
|
||||
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
diag::note_template_enum_def_here)
|
||||
<< ED
|
||||
<< Active->InstantiationRange;
|
||||
} else {
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
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.
|
||||
///
|
||||
/// \param PointOfInstantiation The point of instantiation within the
|
||||
|
@ -1712,38 +1762,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
|
||||
CXXRecordDecl *PatternDef
|
||||
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
|
||||
if (!PatternDef || PatternDef->isBeingDefined()) {
|
||||
if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
|
||||
// Say nothing
|
||||
} 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();
|
||||
if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
|
||||
Instantiation->getInstantiatedFromMemberClass(),
|
||||
Pattern, PatternDef, TSK, Complain))
|
||||
return true;
|
||||
}
|
||||
Pattern = PatternDef;
|
||||
|
||||
// \brief Record the point of instantiation.
|
||||
|
@ -1911,6 +1933,63 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
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 {
|
||||
/// \brief A partial specialization whose template arguments have matched
|
||||
/// a given template-id.
|
||||
|
@ -2231,6 +2310,36 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
|||
if (Pattern)
|
||||
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
|
||||
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(),
|
||||
D->isScopedUsingClassTag(), 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
|
||||
// has been explicitly set by the user. Perform substitution on it before
|
||||
// moving on.
|
||||
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
|
||||
Enum->setIntegerTypeSourceInfo(SemaRef.SubstType(TI,
|
||||
TemplateArgs,
|
||||
UnderlyingLoc,
|
||||
DeclarationName()));
|
||||
|
||||
if (!Enum->getIntegerTypeSourceInfo())
|
||||
TypeSourceInfo *NewTI = SemaRef.SubstType(TI, TemplateArgs, UnderlyingLoc,
|
||||
DeclarationName());
|
||||
if (!NewTI || SemaRef.CheckEnumUnderlyingType(NewTI))
|
||||
Enum->setIntegerType(SemaRef.Context.IntTy);
|
||||
}
|
||||
else {
|
||||
else
|
||||
Enum->setIntegerTypeSourceInfo(NewTI);
|
||||
} else {
|
||||
assert(!D->getIntegerType()->isDependentType()
|
||||
&& "Dependent type without type source info");
|
||||
Enum->setIntegerType(D->getIntegerType());
|
||||
|
@ -585,20 +583,38 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
|
|||
|
||||
SemaRef.InstantiateAttrs(TemplateArgs, D, Enum);
|
||||
|
||||
Enum->setInstantiationOfMemberEnum(D);
|
||||
Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
|
||||
Enum->setAccess(D->getAccess());
|
||||
if (SubstQualifier(D, Enum)) return 0;
|
||||
Owner->addDecl(Enum);
|
||||
Enum->startDefinition();
|
||||
|
||||
// FIXME: If this is a redeclaration:
|
||||
// CheckEnumRedeclaration(Enum->getLocation(), Enum->isScoped(),
|
||||
// Enum->getIntegerType(), Prev);
|
||||
|
||||
if (D->getDeclContext()->isFunctionOrMethod())
|
||||
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;
|
||||
|
||||
EnumConstantDecl *LastEnumConst = 0;
|
||||
for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(),
|
||||
ECEnd = D->enumerator_end();
|
||||
for (EnumDecl::enumerator_iterator EC = Pattern->enumerator_begin(),
|
||||
ECEnd = Pattern->enumerator_end();
|
||||
EC != ECEnd; ++EC) {
|
||||
// The specified value for the enumerator.
|
||||
ExprResult Value = SemaRef.Owned((Expr *)0);
|
||||
|
@ -636,7 +652,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
|
|||
Enumerators.push_back(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
|
||||
// constant as a local.
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
|
||||
|
@ -644,14 +661,11 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Fixup LBraceLoc and RBraceLoc
|
||||
// FIXME: Empty Scope and AttributeList (required to handle attribute packed).
|
||||
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
|
||||
Enum,
|
||||
// FIXME: Fixup LBraceLoc
|
||||
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(),
|
||||
Enum->getRBraceLoc(), Enum,
|
||||
Enumerators.data(), Enumerators.size(),
|
||||
0, 0);
|
||||
|
||||
return Enum;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
|
||||
|
|
|
@ -453,7 +453,13 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
|
|||
ED->IsScoped = Record[Idx++];
|
||||
ED->IsScopedUsingClassTag = 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) {
|
||||
|
|
|
@ -230,7 +230,13 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
|
|||
Record.push_back(D->isScoped());
|
||||
Record.push_back(D->isScopedUsingClassTag());
|
||||
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() &&
|
||||
!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>
|
||||
struct X0 {
|
||||
struct MemberClass;
|
||||
|
||||
|
||||
T* f0(T* ptr);
|
||||
|
||||
|
||||
static T* static_member;
|
||||
};
|
||||
|
||||
template class X0<int>; // okay
|
||||
template class X0<int(int)>; // okay; nothing gets instantiated.
|
||||
template class X0<int(int)>; // ok; nothing gets instantiated.
|
||||
|
||||
template<typename T>
|
||||
struct X0<T>::MemberClass {
|
||||
|
@ -25,3 +24,17 @@ T* X0<T>::f0(T* ptr) {
|
|||
template<typename T>
|
||||
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>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
Loading…
Reference in New Issue