зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
59e7f4e6e6
Коммит
f1c66b4021
|
@ -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>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче