r326299 - Fix a couple of cases where we would fail to correctly parse deduced class template specialization types.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 27 19:02:23 PST 2018
Author: rsmith
Date: Tue Feb 27 19:02:23 2018
New Revision: 326299
URL: http://llvm.org/viewvc/llvm-project?rev=326299&view=rev
Log:
Fix a couple of cases where we would fail to correctly parse deduced class template specialization types.
Specifically, we would not properly parse these types within template arguments
(for non-type template parameters), and in tentative parses. Fixing both of
these essentially requires that we parse deduced template specialization types
as types in all contexts, even in template argument lists -- in particular,
tentative parsing may look ahead and annotate a deduced template specialization
type before we figure out that we're actually supposed to treat the tokens as a
template-name. We deal with this by simply permitting deduced template
specialization types when parsing template arguments, and converting them to
template template arguments.
Modified:
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/TemplateName.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseTemplate.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp
cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Tue Feb 27 19:02:23 2018
@@ -326,6 +326,7 @@ public:
PQ_TypeSpecifier = 2,
PQ_TypeQualifier = 4,
PQ_FunctionSpecifier = 8
+ // FIXME: Attributes should be included here.
};
private:
@@ -1732,7 +1733,8 @@ enum class DeclaratorContext {
ConversionIdContext, // C++ conversion-type-id.
TrailingReturnContext, // C++11 trailing-type-specifier.
TrailingReturnVarContext, // C++11 trailing-type-specifier for variable.
- TemplateTypeArgContext, // Template type argument.
+ TemplateArgContext, // Any template argument (in template argument list).
+ TemplateTypeArgContext, // Template type argument (in default argument).
AliasDeclContext, // C++11 alias-declaration.
AliasTemplateContext // C++11 alias-declaration template.
};
@@ -1949,6 +1951,7 @@ public:
case DeclaratorContext::BlockLiteralContext:
case DeclaratorContext::LambdaExprContext:
case DeclaratorContext::ConversionIdContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
@@ -1986,6 +1989,7 @@ public:
case DeclaratorContext::BlockLiteralContext:
case DeclaratorContext::LambdaExprContext:
case DeclaratorContext::ConversionIdContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
@@ -2027,6 +2031,7 @@ public:
case DeclaratorContext::BlockLiteralContext:
case DeclaratorContext::LambdaExprContext:
case DeclaratorContext::ConversionIdContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
@@ -2082,6 +2087,7 @@ public:
case DeclaratorContext::BlockLiteralContext:
case DeclaratorContext::LambdaExprContext:
case DeclaratorContext::ConversionIdContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
return false;
@@ -2291,6 +2297,7 @@ public:
case DeclaratorContext::BlockLiteralContext:
case DeclaratorContext::LambdaExprContext:
case DeclaratorContext::ConversionIdContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
@@ -2326,13 +2333,14 @@ public:
case DeclaratorContext::ConversionIdContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
+ case DeclaratorContext::TemplateTypeArgContext:
return false;
case DeclaratorContext::BlockContext:
case DeclaratorContext::ForContext:
case DeclaratorContext::InitStmtContext:
case DeclaratorContext::ConditionContext:
- case DeclaratorContext::TemplateTypeArgContext:
+ case DeclaratorContext::TemplateArgContext:
return true;
}
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 27 19:02:23 2018
@@ -6168,6 +6168,8 @@ public:
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
TemplateArgumentListInfo &Out);
+ ParsedTemplateArgument ActOnTemplateTypeArgument(TypeResult ParsedType);
+
void NoteAllFoundTemplates(TemplateName Name);
QualType CheckTemplateIdType(TemplateName Template,
Modified: cfe/trunk/lib/AST/TemplateName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateName.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TemplateName.cpp (original)
+++ cfe/trunk/lib/AST/TemplateName.cpp Tue Feb 27 19:02:23 2018
@@ -185,6 +185,11 @@ bool TemplateName::isInstantiationDepend
}
bool TemplateName::containsUnexpandedParameterPack() const {
+ if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
+ if (QTN->getQualifier()->containsUnexpandedParameterPack())
+ return true;
+ }
+
if (TemplateDecl *Template = getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Template))
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Feb 27 19:02:23 2018
@@ -2686,7 +2686,8 @@ Parser::getDeclSpecContextFromDeclarator
return DeclSpecContext::DSC_top_level;
if (Context == DeclaratorContext::TemplateParamContext)
return DeclSpecContext::DSC_template_param;
- if (Context == DeclaratorContext::TemplateTypeArgContext)
+ if (Context == DeclaratorContext::TemplateArgContext ||
+ Context == DeclaratorContext::TemplateTypeArgContext)
return DeclSpecContext::DSC_template_type_arg;
if (Context == DeclaratorContext::TrailingReturnContext ||
Context == DeclaratorContext::TrailingReturnVarContext)
@@ -5637,7 +5638,7 @@ void Parser::ParseDirectDeclarator(Decla
// An identifier within parens is unlikely to be intended to be anything
// other than a name being "declared".
DiagnoseIdentifier = true;
- else if (D.getContext() == DeclaratorContext::TemplateTypeArgContext)
+ else if (D.getContext() == DeclaratorContext::TemplateArgContext)
// T<int N> is an accidental identifier; T<int N indicates a missing '>'.
DiagnoseIdentifier =
NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater);
Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Feb 27 19:02:23 2018
@@ -1207,15 +1207,9 @@ ParsedTemplateArgument Parser::ParseTemp
EnterExpressionEvaluationContext EnterConstantEvaluated(
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
- SourceLocation Loc = Tok.getLocation();
TypeResult TypeArg = ParseTypeName(
- /*Range=*/nullptr, DeclaratorContext::TemplateTypeArgContext);
- if (TypeArg.isInvalid())
- return ParsedTemplateArgument();
-
- return ParsedTemplateArgument(ParsedTemplateArgument::Type,
- TypeArg.get().getAsOpaquePtr(),
- Loc);
+ /*Range=*/nullptr, DeclaratorContext::TemplateArgContext);
+ return Actions.ActOnTemplateTypeArgument(TypeArg);
}
// Try to parse a template template argument.
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Tue Feb 27 19:02:23 2018
@@ -1246,6 +1246,17 @@ Parser::isCXXDeclarationSpecifier(Parser
case ANK_TentativeDecl:
return TPResult::False;
case ANK_TemplateName:
+ // In C++17, this could be a type template for class template argument
+ // deduction. Try to form a type annotation for it. If we're in a
+ // template template argument, we'll undo this when checking the
+ // validity of the argument.
+ if (getLangOpts().CPlusPlus17) {
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error;
+ if (Tok.isNot(tok::identifier))
+ break;
+ }
+
// A bare type template-name which can't be a template template
// argument is an error, and was probably intended to be a type.
return GreaterThanIsOperator ? TPResult::True : TPResult::False;
@@ -1424,8 +1435,6 @@ Parser::isCXXDeclarationSpecifier(Parser
*HasMissingTypename = true;
return TPResult::Ambiguous;
}
-
- // FIXME: Fails to either revert or commit the tentative parse!
} else {
// Try to resolve the name. If it doesn't exist, assume it was
// intended to name a type and keep disambiguating.
@@ -1435,19 +1444,33 @@ Parser::isCXXDeclarationSpecifier(Parser
case ANK_TentativeDecl:
return TPResult::False;
case ANK_TemplateName:
+ // In C++17, this could be a type template for class template
+ // argument deduction.
+ if (getLangOpts().CPlusPlus17) {
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error;
+ if (Tok.isNot(tok::identifier))
+ break;
+ }
+
// A bare type template-name which can't be a template template
// argument is an error, and was probably intended to be a type.
- return GreaterThanIsOperator ? TPResult::True : TPResult::False;
+ // In C++17, this could be class template argument deduction.
+ return (getLangOpts().CPlusPlus17 || GreaterThanIsOperator)
+ ? TPResult::True
+ : TPResult::False;
case ANK_Unresolved:
return HasMissingTypename ? TPResult::Ambiguous
: TPResult::False;
case ANK_Success:
- // Annotated it, check again.
- assert(Tok.isNot(tok::annot_cxxscope) ||
- NextToken().isNot(tok::identifier));
- return isCXXDeclarationSpecifier(BracedCastResult,
- HasMissingTypename);
+ break;
}
+
+ // Annotated it, check again.
+ assert(Tok.isNot(tok::annot_cxxscope) ||
+ NextToken().isNot(tok::identifier));
+ return isCXXDeclarationSpecifier(BracedCastResult,
+ HasMissingTypename);
}
}
return TPResult::False;
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Feb 27 19:02:23 2018
@@ -1775,8 +1775,8 @@ bool Parser::TryAnnotateTypeOrScopeToken
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
false, NextToken().is(tok::period), nullptr,
/*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo*/ true,
- /*IsClassTemplateDeductionContext*/GreaterThanIsOperator)) {
+ /*NonTrivialTypeSourceInfo*/true,
+ /*IsClassTemplateDeductionContext*/true)) {
SourceLocation BeginLoc = Tok.getLocation();
if (SS.isNotEmpty()) // it was a C++ qualified type name.
BeginLoc = SS.getBeginLoc();
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 27 19:02:23 2018
@@ -783,6 +783,56 @@ static void maybeDiagnoseTemplateParamet
SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl);
}
+/// Convert a parsed type into a parsed template argument. This is mostly
+/// trivial, except that we may have parsed a C++17 deduced class template
+/// specialization type, in which case we should form a template template
+/// argument instead of a type template argument.
+ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) {
+ TypeSourceInfo *TInfo;
+ QualType T = GetTypeFromParser(ParsedType.get(), &TInfo);
+ if (T.isNull())
+ return ParsedTemplateArgument();
+ assert(TInfo && "template argument with no location");
+
+ // If we might have formed a deduced template specialization type, convert
+ // it to a template template argument.
+ if (getLangOpts().CPlusPlus17) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ SourceLocation EllipsisLoc;
+ if (auto PET = TL.getAs<PackExpansionTypeLoc>()) {
+ EllipsisLoc = PET.getEllipsisLoc();
+ TL = PET.getPatternLoc();
+ }
+
+ CXXScopeSpec SS;
+ if (auto ET = TL.getAs<ElaboratedTypeLoc>()) {
+ SS.Adopt(ET.getQualifierLoc());
+ TL = ET.getNamedTypeLoc();
+ }
+
+ if (auto DTST = TL.getAs<DeducedTemplateSpecializationTypeLoc>()) {
+ TemplateName Name = DTST.getTypePtr()->getTemplateName();
+ if (SS.isSet())
+ Name = Context.getQualifiedTemplateName(SS.getScopeRep(),
+ /*HasTemplateKeyword*/ false,
+ Name.getAsTemplateDecl());
+ ParsedTemplateArgument Result(SS, TemplateTy::make(Name),
+ DTST.getTemplateNameLoc());
+ if (EllipsisLoc.isValid())
+ Result = Result.getTemplatePackExpansion(EllipsisLoc);
+ return Result;
+ }
+ }
+
+ // This is a normal type template argument. Note, if the type template
+ // argument is an injected-class-name for a template, it has a dual nature
+ // and can be used as either a type or a template. We handle that in
+ // convertTypeTemplateArgumentToTemplate.
+ return ParsedTemplateArgument(ParsedTemplateArgument::Type,
+ ParsedType.get().getAsOpaquePtr(),
+ TInfo->getTypeLoc().getLocStart());
+}
+
/// ActOnTypeParameter - Called when a C++ template type parameter
/// (e.g., "typename T") has been parsed. Typename specifies whether
/// the keyword "typename" was used to declare the type parameter
@@ -4148,11 +4198,12 @@ bool Sema::CheckTemplateTypeArgument(Tem
ArgType = Arg.getAsType();
TSI = AL.getTypeSourceInfo();
break;
- case TemplateArgument::Template: {
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion: {
// We have a template type parameter but the template argument
// is a template without any arguments.
SourceRange SR = AL.getSourceRange();
- TemplateName Name = Arg.getAsTemplate();
+ TemplateName Name = Arg.getAsTemplateOrTemplatePattern();
Diag(SR.getBegin(), diag::err_template_missing_args)
<< (int)getTemplateNameKindForDiagnostics(Name) << Name << SR;
if (TemplateDecl *Decl = Name.getAsTemplateDecl())
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Feb 27 19:02:23 2018
@@ -2852,6 +2852,14 @@ static QualType GetDeclSpecTypeForDeclar
case DeclaratorContext::BlockLiteralContext:
Error = 9; // Block literal
break;
+ case DeclaratorContext::TemplateArgContext:
+ // Within a template argument list, a deduced template specialization
+ // type will be reinterpreted as a template template argument.
+ if (isa<DeducedTemplateSpecializationType>(Deduced) &&
+ !D.getNumTypeObjects() &&
+ D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier)
+ break;
+ LLVM_FALLTHROUGH;
case DeclaratorContext::TemplateTypeArgContext:
Error = 10; // Template type argument
break;
@@ -2991,6 +2999,7 @@ static QualType GetDeclSpecTypeForDeclar
case DeclaratorContext::CXXNewContext:
case DeclaratorContext::CXXCatchContext:
case DeclaratorContext::ObjCCatchContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
DiagID = diag::err_type_defined_in_type_specifier;
break;
@@ -4011,6 +4020,7 @@ static TypeSourceInfo *GetFullTypeForDec
case DeclaratorContext::LambdaExprParameterContext:
case DeclaratorContext::ObjCCatchContext:
case DeclaratorContext::TemplateParamContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TypeNameContext:
case DeclaratorContext::FunctionalCastContext:
@@ -4832,6 +4842,7 @@ static TypeSourceInfo *GetFullTypeForDec
!(Kind == Member &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
!IsTypedefName &&
+ D.getContext() != DeclaratorContext::TemplateArgContext &&
D.getContext() != DeclaratorContext::TemplateTypeArgContext) {
SourceLocation Loc = D.getLocStart();
SourceRange RemovalRange;
@@ -4959,6 +4970,7 @@ static TypeSourceInfo *GetFullTypeForDec
case DeclaratorContext::ConversionIdContext:
case DeclaratorContext::TrailingReturnContext:
case DeclaratorContext::TrailingReturnVarContext:
+ case DeclaratorContext::TemplateArgContext:
case DeclaratorContext::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp?rev=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp Tue Feb 27 19:02:23 2018
@@ -65,8 +65,8 @@ namespace WrongScope {
};
template<typename T> struct Local {};
void f() {
- Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}}
+ Local(int) -> Local<int>; // expected-error {{expected}}
using WrongScope::Local;
- Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}}
+ Local(int) -> Local<int>; // expected-error {{expected}}
}
}
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=326299&r1=326298&r2=326299&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Tue Feb 27 19:02:23 2018
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
-template <typename T> struct A { // expected-note 35{{declared here}}
+template <typename T> struct A { // expected-note 38{{declared here}}
constexpr A() {}
constexpr A(int) {}
constexpr operator int() { return 0; }
@@ -17,6 +17,12 @@ namespace template_template_arg {
Y<A> ya; // expected-error {{requires template arguments}}
X<::A> xcca;
Y<::A> ycca; // expected-error {{requires template arguments}}
+ X<A*> xap; // expected-error {{requires template arguments}}
+ X<const A> xca; // expected-error {{requires template arguments}}
+ X<A const> xac; // expected-error {{requires template arguments}}
+ // FIXME: This should not parse as a template template argument due to the
+ // trailing attributes.
+ X<A [[]]> xa_attr;
template<template<typename> typename = A> struct XD {};
template<typename = A> struct YD {}; // expected-error {{requires template arguments}}
@@ -28,6 +34,23 @@ namespace template_template_arg {
template<typename T = A> struct G { }; // expected-error {{requires template arguments}}
}
+namespace template_template_arg_pack {
+ template<template<typename> typename...> struct XP {};
+ template<typename...> struct YP {};
+
+ struct Z { template<typename T> struct Q {}; }; // expected-note 2{{here}}
+
+ template<typename T> using ZId = Z;
+
+ template<typename ...Ts> struct A {
+ XP<ZId<Ts>::Q...> xe;
+ YP<ZId<Ts>::Q...> ye; // expected-error {{requires template arguments}}
+
+ XP<ZId<Ts>::Q> xp; // expected-error {{unexpanded parameter pack}}
+ YP<ZId<Ts>::Q> yp; // expected-error {{requires template arguments}}
+ };
+}
+
namespace injected_class_name {
template<typename T> struct A {
A(T);
@@ -193,3 +216,18 @@ namespace typename_specifier {
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}}
}
+
+namespace parenthesized {
+ template<typename T> struct X { X(T); };
+ auto n = (X([]{}));
+}
+
+namespace within_template_arg_list {
+ template<typename T> struct X { constexpr X(T v) : v(v) {} T v; };
+ template<int N = X(1).v> struct Y {};
+ using T = Y<>;
+ using T = Y<X(1).v>;
+ using T = Y<within_template_arg_list::X(1).v>;
+
+ template<int ...N> struct Z { Y<X(N)...> y; };
+}
More information about the cfe-commits
mailing list