forked from OSchip/llvm-project
Towards P0091R3: parsing support for class template argument deduction in typename-specifiers.
llvm-svn: 293455
This commit is contained in:
parent
e4ddaa4427
commit
c95726ea39
|
@ -2946,6 +2946,16 @@ inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
|
|||
return P.get<TemplateTemplateParmDecl*>();
|
||||
}
|
||||
|
||||
inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
|
||||
auto *TD = dyn_cast<TemplateDecl>(D);
|
||||
return TD && (isa<ClassTemplateDecl>(TD) ||
|
||||
isa<ClassTemplatePartialSpecializationDecl>(TD) ||
|
||||
isa<TypeAliasTemplateDecl>(TD) ||
|
||||
isa<TemplateTemplateParmDecl>(TD))
|
||||
? TD
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} /* end of namespace clang */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1884,6 +1884,11 @@ def err_auto_not_allowed : Error<
|
|||
"|in conversion function type|here|in lambda parameter"
|
||||
"|in type allocated by 'new'|in K&R-style function parameter"
|
||||
"|in template parameter|in friend declaration}1">;
|
||||
def err_dependent_deduced_tst : Error<
|
||||
"typename specifier refers to "
|
||||
"%select{class template|function template|variable template|alias template|"
|
||||
"template template parameter|template}0 member in %1; "
|
||||
"argument deduction not allowed here">;
|
||||
def err_auto_not_allowed_var_inst : Error<
|
||||
"'auto' variable template instantiation is not allowed">;
|
||||
def err_auto_var_requires_init : Error<
|
||||
|
|
|
@ -7359,7 +7359,8 @@ public:
|
|||
|
||||
TypeSourceInfo *SubstType(TypeSourceInfo *T,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
SourceLocation Loc, DeclarationName Entity);
|
||||
SourceLocation Loc, DeclarationName Entity,
|
||||
bool AllowDeducedTST = false);
|
||||
|
||||
QualType SubstType(QualType T,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
|
|
|
@ -60,11 +60,6 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {
|
|||
return DeclGroupPtrTy::make(DeclGroupRef(Ptr));
|
||||
}
|
||||
|
||||
static bool isTypeTemplate(NamedDecl *ND) {
|
||||
return isa<ClassTemplateDecl>(ND) || isa<TypeAliasTemplateDecl>(ND) ||
|
||||
isa<TemplateTemplateParmDecl>(ND);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
|
||||
|
@ -81,7 +76,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
|
|||
bool ValidateCandidate(const TypoCorrection &candidate) override {
|
||||
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
|
||||
bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
|
||||
bool AllowedTemplate = AllowTemplates && isTypeTemplate(ND);
|
||||
bool AllowedTemplate = AllowTemplates && getAsTypeTemplateDecl(ND);
|
||||
return (IsType || AllowedTemplate) &&
|
||||
(AllowInvalidDecl || !ND->isInvalidDecl());
|
||||
}
|
||||
|
@ -405,7 +400,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
|
|||
for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end();
|
||||
Res != ResEnd; ++Res) {
|
||||
if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res) ||
|
||||
(AllowDeducedTemplate && isTypeTemplate(*Res))) {
|
||||
(AllowDeducedTemplate && getAsTypeTemplateDecl(*Res))) {
|
||||
if (!IIDecl ||
|
||||
(*Res)->getLocation().getRawEncoding() <
|
||||
IIDecl->getLocation().getRawEncoding())
|
||||
|
@ -458,9 +453,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
|
|||
(void)DiagnoseUseOfDecl(IDecl, NameLoc);
|
||||
if (!HasTrailingDot)
|
||||
T = Context.getObjCInterfaceType(IDecl);
|
||||
} else if (AllowDeducedTemplate && isTypeTemplate(IIDecl)) {
|
||||
T = Context.getDeducedTemplateSpecializationType(
|
||||
TemplateName(cast<TemplateDecl>(IIDecl)), QualType(), false);
|
||||
} else if (AllowDeducedTemplate) {
|
||||
if (auto *TD = getAsTypeTemplateDecl(IIDecl))
|
||||
T = Context.getDeducedTemplateSpecializationType(TemplateName(TD),
|
||||
QualType(), false);
|
||||
}
|
||||
|
||||
if (T.isNull()) {
|
||||
|
|
|
@ -8792,8 +8792,18 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
|
|||
Context.getTypeDeclType(Type));
|
||||
}
|
||||
|
||||
// FIXME: Form a deduced template specialization type if we get a template
|
||||
// declaration here.
|
||||
// C++ [dcl.type.simple]p2:
|
||||
// A type-specifier of the form
|
||||
// typename[opt] nested-name-specifier[opt] template-name
|
||||
// is a placeholder for a deduced class type [...].
|
||||
if (getLangOpts().CPlusPlus1z) {
|
||||
if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) {
|
||||
return Context.getElaboratedType(
|
||||
Keyword, QualifierLoc.getNestedNameSpecifier(),
|
||||
Context.getDeducedTemplateSpecializationType(TemplateName(TD),
|
||||
QualType(), false));
|
||||
}
|
||||
}
|
||||
|
||||
DiagID = diag::err_typename_nested_not_type;
|
||||
Referenced = Result.getFoundDecl();
|
||||
|
|
|
@ -1490,12 +1490,16 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
|
|||
/// a cast expression) or that the entity has no name (e.g., an
|
||||
/// unnamed function parameter).
|
||||
///
|
||||
/// \param AllowDeducedTST Whether a DeducedTemplateSpecializationType is
|
||||
/// acceptable as the top level type of the result.
|
||||
///
|
||||
/// \returns If the instantiation succeeds, the instantiated
|
||||
/// type. Otherwise, produces diagnostics and returns a NULL type.
|
||||
TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
|
||||
const MultiLevelTemplateArgumentList &Args,
|
||||
SourceLocation Loc,
|
||||
DeclarationName Entity) {
|
||||
DeclarationName Entity,
|
||||
bool AllowDeducedTST) {
|
||||
assert(!ActiveTemplateInstantiations.empty() &&
|
||||
"Cannot perform an instantiation without some context on the "
|
||||
"instantiation stack");
|
||||
|
@ -1505,7 +1509,8 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
|
|||
return T;
|
||||
|
||||
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
|
||||
return Instantiator.TransformType(T);
|
||||
return AllowDeducedTST ? Instantiator.TransformTypeWithDeducedTST(T)
|
||||
: Instantiator.TransformType(T);
|
||||
}
|
||||
|
||||
TypeSourceInfo *Sema::SubstType(TypeLoc TL,
|
||||
|
|
|
@ -657,10 +657,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
|
|||
ArrayRef<BindingDecl*> *Bindings) {
|
||||
|
||||
// Do substitution on the type of the declaration
|
||||
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
|
||||
TemplateArgs,
|
||||
D->getTypeSpecStartLoc(),
|
||||
D->getDeclName());
|
||||
TypeSourceInfo *DI = SemaRef.SubstType(
|
||||
D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(),
|
||||
D->getDeclName(), /*AllowDeducedTST*/true);
|
||||
if (!DI)
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -307,6 +307,17 @@ public:
|
|||
///
|
||||
QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL);
|
||||
|
||||
/// \brief Transform a type that is permitted to produce a
|
||||
/// DeducedTemplateSpecializationType.
|
||||
///
|
||||
/// This is used in the (relatively rare) contexts where it is acceptable
|
||||
/// for transformation to produce a class template type with deduced
|
||||
/// template arguments.
|
||||
/// @{
|
||||
QualType TransformTypeWithDeducedTST(QualType T);
|
||||
TypeSourceInfo *TransformTypeWithDeducedTST(TypeSourceInfo *DI);
|
||||
/// @}
|
||||
|
||||
/// \brief Transform the given statement.
|
||||
///
|
||||
/// By default, this routine transforms a statement by delegating to the
|
||||
|
@ -898,7 +909,7 @@ public:
|
|||
/// By default, builds a new ParenType type from the inner type.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
QualType RebuildParenType(QualType InnerType) {
|
||||
return SemaRef.Context.getParenType(InnerType);
|
||||
return SemaRef.BuildParenType(InnerType);
|
||||
}
|
||||
|
||||
/// \brief Build a new qualified name type.
|
||||
|
@ -968,7 +979,8 @@ public:
|
|||
SourceLocation KeywordLoc,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
const IdentifierInfo *Id,
|
||||
SourceLocation IdLoc) {
|
||||
SourceLocation IdLoc,
|
||||
bool DeducedTSTContext) {
|
||||
CXXScopeSpec SS;
|
||||
SS.Adopt(QualifierLoc);
|
||||
|
||||
|
@ -980,9 +992,25 @@ public:
|
|||
Id);
|
||||
}
|
||||
|
||||
if (Keyword == ETK_None || Keyword == ETK_Typename)
|
||||
return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
|
||||
*Id, IdLoc);
|
||||
if (Keyword == ETK_None || Keyword == ETK_Typename) {
|
||||
QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
|
||||
*Id, IdLoc);
|
||||
// If a dependent name resolves to a deduced template specialization type,
|
||||
// check that we're in one of the syntactic contexts permitting it.
|
||||
if (!DeducedTSTContext) {
|
||||
if (auto *Deduced = dyn_cast_or_null<DeducedTemplateSpecializationType>(
|
||||
T.isNull() ? nullptr : T->getContainedDeducedType())) {
|
||||
SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst)
|
||||
<< (int)SemaRef.getTemplateNameKindForDiagnostics(
|
||||
Deduced->getTemplateName())
|
||||
<< QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0);
|
||||
if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl())
|
||||
SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here);
|
||||
return QualType();
|
||||
}
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
|
||||
|
||||
|
@ -3157,6 +3185,10 @@ private:
|
|||
TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType,
|
||||
NamedDecl *FirstQualifierInScope,
|
||||
CXXScopeSpec &SS);
|
||||
|
||||
QualType TransformDependentNameType(TypeLocBuilder &TLB,
|
||||
DependentNameTypeLoc TL,
|
||||
bool DeducibleTSTContext);
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
|
@ -4048,6 +4080,52 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
|
|||
llvm_unreachable("unhandled type loc!");
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformTypeWithDeducedTST(QualType T) {
|
||||
if (!isa<DependentNameType>(T))
|
||||
return TransformType(T);
|
||||
|
||||
if (getDerived().AlreadyTransformed(T))
|
||||
return T;
|
||||
TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T,
|
||||
getDerived().getBaseLocation());
|
||||
TypeSourceInfo *NewDI = getDerived().TransformTypeWithDeducedTST(DI);
|
||||
return NewDI ? NewDI->getType() : QualType();
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
TypeSourceInfo *
|
||||
TreeTransform<Derived>::TransformTypeWithDeducedTST(TypeSourceInfo *DI) {
|
||||
if (!isa<DependentNameType>(DI->getType()))
|
||||
return TransformType(DI);
|
||||
|
||||
// Refine the base location to the type's location.
|
||||
TemporaryBase Rebase(*this, DI->getTypeLoc().getBeginLoc(),
|
||||
getDerived().getBaseEntity());
|
||||
if (getDerived().AlreadyTransformed(DI->getType()))
|
||||
return DI;
|
||||
|
||||
TypeLocBuilder TLB;
|
||||
|
||||
TypeLoc TL = DI->getTypeLoc();
|
||||
TLB.reserve(TL.getFullDataSize());
|
||||
|
||||
Qualifiers Quals;
|
||||
if (auto QTL = TL.getAs<QualifiedTypeLoc>()) {
|
||||
Quals = QTL.getType().getLocalQualifiers();
|
||||
TL = QTL.getUnqualifiedLoc();
|
||||
}
|
||||
|
||||
auto DNTL = TL.castAs<DependentNameTypeLoc>();
|
||||
|
||||
QualType Result = getDerived().TransformDependentNameType(
|
||||
TLB, DNTL, /*DeducedTSTContext*/true);
|
||||
if (Result.isNull())
|
||||
return nullptr;
|
||||
|
||||
return TLB.getTypeSourceInfo(SemaRef.Context, Result);
|
||||
}
|
||||
|
||||
/// FIXME: By default, this routine adds type qualifiers only to types
|
||||
/// that can have qualifiers, and silently suppresses those qualifiers
|
||||
/// that are not permitted (e.g., qualifiers on reference or function
|
||||
|
@ -5854,8 +5932,14 @@ TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB,
|
|||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
|
||||
DependentNameTypeLoc TL) {
|
||||
QualType TreeTransform<Derived>::TransformDependentNameType(
|
||||
TypeLocBuilder &TLB, DependentNameTypeLoc TL) {
|
||||
return TransformDependentNameType(TLB, TL, false);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformDependentNameType(
|
||||
TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext) {
|
||||
const DependentNameType *T = TL.getTypePtr();
|
||||
|
||||
NestedNameSpecifierLoc QualifierLoc
|
||||
|
@ -5868,7 +5952,8 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
|
|||
TL.getElaboratedKeywordLoc(),
|
||||
QualifierLoc,
|
||||
T->getIdentifier(),
|
||||
TL.getNameLoc());
|
||||
TL.getNameLoc(),
|
||||
DeducedTSTContext);
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
|
||||
|
@ -9474,7 +9559,8 @@ template<typename Derived>
|
|||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
|
||||
CXXFunctionalCastExpr *E) {
|
||||
TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten());
|
||||
TypeSourceInfo *Type =
|
||||
getDerived().TransformTypeWithDeducedTST(E->getTypeInfoAsWritten());
|
||||
if (!Type)
|
||||
return ExprError();
|
||||
|
||||
|
@ -9663,8 +9749,8 @@ template<typename Derived>
|
|||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
|
||||
// Transform the type that we're allocating
|
||||
TypeSourceInfo *AllocTypeInfo
|
||||
= getDerived().TransformType(E->getAllocatedTypeSourceInfo());
|
||||
TypeSourceInfo *AllocTypeInfo =
|
||||
getDerived().TransformTypeWithDeducedTST(E->getAllocatedTypeSourceInfo());
|
||||
if (!AllocTypeInfo)
|
||||
return ExprError();
|
||||
|
||||
|
@ -10375,7 +10461,8 @@ template<typename Derived>
|
|||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
|
||||
CXXTemporaryObjectExpr *E) {
|
||||
TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo());
|
||||
TypeSourceInfo *T =
|
||||
getDerived().TransformTypeWithDeducedTST(E->getTypeSourceInfo());
|
||||
if (!T)
|
||||
return ExprError();
|
||||
|
||||
|
@ -10672,7 +10759,8 @@ template<typename Derived>
|
|||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
|
||||
CXXUnresolvedConstructExpr *E) {
|
||||
TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo());
|
||||
TypeSourceInfo *T =
|
||||
getDerived().TransformTypeWithDeducedTST(E->getTypeSourceInfo());
|
||||
if (!T)
|
||||
return ExprError();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
|
||||
|
||||
template<typename T> struct A {}; // expected-note 31{{declared here}}
|
||||
template<typename T> struct A {}; // expected-note 35{{declared here}}
|
||||
|
||||
// Make sure we still correctly parse cases where a template can appear without arguments.
|
||||
namespace template_template_arg {
|
||||
|
@ -101,6 +101,8 @@ namespace expr {
|
|||
(void)reinterpret_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
(void)const_cast<A>(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
(void)*(A*)(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
(void)(A)(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
(void)(A){n}; // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
|
||||
(void)A(n); // expected-error {{not yet supported}}
|
||||
(void)A{n}; // expected-error {{not yet supported}}
|
||||
|
@ -121,6 +123,7 @@ namespace decl {
|
|||
|
||||
A a; // expected-error {{requires an initializer}}
|
||||
A b = 0; // expected-error {{not yet supported}}
|
||||
const A c = 0; // expected-error {{not yet supported}}
|
||||
A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
|
||||
A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
|
||||
A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
|
||||
|
@ -129,3 +132,57 @@ namespace decl {
|
|||
A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
|
||||
A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{not yet supported}}
|
||||
}
|
||||
|
||||
namespace typename_specifier {
|
||||
struct F {};
|
||||
|
||||
void e() {
|
||||
(void) typename ::A(0); // expected-error {{not yet supported}}
|
||||
(void) typename ::A{0}; // expected-error {{not yet supported}}
|
||||
new typename ::A(0); // expected-error {{not yet supported}}
|
||||
new typename ::A{0}; // expected-error {{not yet supported}}
|
||||
typename ::A a = 0; // expected-error {{not yet supported}}
|
||||
const typename ::A b = 0; // expected-error {{not yet supported}}
|
||||
if (typename ::A a = 0) {} // expected-error {{not yet supported}}
|
||||
for (typename ::A a = 0; typename ::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
|
||||
|
||||
(void)(typename ::A)(0); // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
(void)(typename ::A){0}; // expected-error{{requires template arguments; argument deduction not allowed here}}
|
||||
}
|
||||
typename ::A a = 0; // expected-error {{not yet supported}}
|
||||
const typename ::A b = 0; // expected-error {{not yet supported}}
|
||||
typename ::A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
|
||||
typename ::A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
|
||||
typename ::A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
|
||||
typename ::A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
|
||||
typename ::A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
|
||||
typename ::A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
|
||||
typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{not yet supported}}
|
||||
|
||||
struct X { template<typename T> struct A {}; }; // expected-note 8{{template}}
|
||||
|
||||
template<typename T> void f() {
|
||||
(void) typename T::A(0); // expected-error {{not yet supported}}
|
||||
(void) typename T::A{0}; // expected-error {{not yet supported}}
|
||||
new typename T::A(0); // expected-error {{not yet supported}}
|
||||
new typename T::A{0}; // expected-error {{not yet supported}}
|
||||
typename T::A a = 0; // expected-error {{not yet supported}}
|
||||
const typename T::A b = 0; // expected-error {{not yet supported}}
|
||||
if (typename T::A a = 0) {} // expected-error {{not yet supported}}
|
||||
for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
|
||||
|
||||
{(void)(typename T::A)(0);} // expected-error{{refers to class template member}}
|
||||
{(void)(typename T::A){0};} // expected-error{{refers to class template member}}
|
||||
{typename T::A (parens) = 0;} // expected-error {{refers to class template member in 'typename_specifier::X'; argument deduction not allowed here}}
|
||||
{typename T::A *p = 0;} // expected-error {{refers to class template member}}
|
||||
{typename T::A &r = *p;} // expected-error {{refers to class template member}}
|
||||
{typename T::A arr[3] = 0;} // expected-error {{refers to class template member}}
|
||||
{typename T::A F::*pm = 0;} // expected-error {{refers to class template member}}
|
||||
{typename T::A (*fp)() = 0;} // expected-error {{refers to class template member}}
|
||||
{typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{not yet supported}}
|
||||
}
|
||||
template void f<X>(); // expected-note {{instantiation of}}
|
||||
|
||||
template<typename T> void g(typename T::A = 0); // expected-note {{refers to class template member}}
|
||||
void h() { g<X>(); } // expected-error {{no matching function}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue