r293455 - Towards P0091R3: parsing support for class template argument deduction in typename-specifiers.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 29 20:38:29 PST 2017
Author: rsmith
Date: Sun Jan 29 22:38:28 2017
New Revision: 293455
URL: http://llvm.org/viewvc/llvm-project?rev=293455&view=rev
Log:
Towards P0091R3: parsing support for class template argument deduction in typename-specifiers.
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Sun Jan 29 22:38:28 2017
@@ -2946,6 +2946,16 @@ inline NamedDecl *getAsNamedDecl(Templat
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
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Jan 29 22:38:28 2017
@@ -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<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Jan 29 22:38:28 2017
@@ -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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Jan 29 22:38:28 2017
@@ -60,11 +60,6 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclTo
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 Corr
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 Ident
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 Ident
(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()) {
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun Jan 29 22:38:28 2017
@@ -8792,8 +8792,18 @@ Sema::CheckTypenameType(ElaboratedTypeKe
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();
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sun Jan 29 22:38:28 2017
@@ -1490,12 +1490,16 @@ TemplateInstantiator::TransformSubstTemp
/// 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(TypeSour
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,
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sun Jan 29 22:38:28 2017
@@ -657,10 +657,9 @@ Decl *TemplateDeclInstantiator::VisitVar
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;
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Sun Jan 29 22:38:28 2017
@@ -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(Ty
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>::TransformParenTy
}
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>::Transfo
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();
Modified: cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp?rev=293455&r1=293454&r2=293455&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Sun Jan 29 22:38:28 2017
@@ -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}}
+}
More information about the cfe-commits
mailing list