diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f110b8cf76507..b89d055304f4a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -329,6 +329,9 @@ C++17 Feature Support ^^^^^^^^^^^^^^^^^^^^^ - The implementation of the relaxed template template argument matching rules is more complete and reliable, and should provide more accurate diagnostics. + This implements: + - `P3310R5: Solving issues introduced by relaxed template template parameter matching `_. + - `P3579R0: Fix matching of non-type template parameters when matching template template parameters `_. Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 774e5484cfa0e..6be67a36b9fe7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -82,11 +82,11 @@ def err_typecheck_converted_constant_expression_indirect : Error< "conversion from %0 to %1 in converted constant expression would " "bind reference to a temporary">; def err_expr_not_cce : Error< - "%select{case value|enumerator value|non-type template argument|" + "%select{case value|enumerator value|non-type template argument|non-type parameter of template template parameter|" "array size|explicit specifier argument|noexcept specifier argument|" "call to 'size()'|call to 'data()'}0 is not a constant expression">; def ext_cce_narrowing : ExtWarn< - "%select{case value|enumerator value|non-type template argument|" + "%select{case value|enumerator value|non-type template argument|non-type parameter of template template parameter|" "array size|explicit specifier argument|noexcept specifier argument|" "call to 'size()'|call to 'data()'}0 %select{cannot be narrowed from " "type %2 to %3|evaluates to %2, which cannot be narrowed to type %3}1">, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4d6e02fe2956e..1ea7c62cb36f0 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9999,6 +9999,7 @@ class Sema final : public SemaBase { CCEK_CaseValue, ///< Expression in a case label. CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. + CCEK_InjectedTTP, ///< Injected parameter of a template template parameter. CCEK_ArrayBound, ///< Array bound in array declarator or new-expression. CCEK_ExplicitBool, ///< Condition in an explicit(bool) specifier. CCEK_Noexcept, ///< Condition in a noexcept(bool) specifier. @@ -11682,6 +11683,7 @@ class Sema final : public SemaBase { SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, CheckTemplateArgumentKind CTAK, bool PartialOrdering, + bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg); /// Check that the given template arguments can be provided to @@ -11755,6 +11757,7 @@ class Sema final : public SemaBase { QualType InstantiatedParamType, Expr *Arg, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, + bool PartialOrderingTTP, CheckTemplateArgumentKind CTAK); /// Check a template argument against its corresponding diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 2ed8d3608d49e..26f53532a1491 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3676,7 +3676,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, if (CheckTemplateArgument( Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), 0, SugaredChecked, CanonicalChecked, CTAK_Specified, - /*PartialOrdering=*/false, + /*PartialOrdering=*/false, /*PartialOrderingTTP=*/false, /*MatchedPackOnParmToNonPackOnArg=*/nullptr) || Trap.hasErrorOccurred()) IsTemplate = false; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6ae9c51c06b31..20eaf494e90bb 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6151,8 +6151,8 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, Sema::CCEKind CCE, NamedDecl *Dest, APValue &PreNarrowingValue) { - assert(S.getLangOpts().CPlusPlus11 && - "converted constant expression outside C++11"); + assert((S.getLangOpts().CPlusPlus11 || CCE == Sema::CCEK_InjectedTTP) && + "converted constant expression outside C++11 or TTP matching"); if (checkPlaceholderForOverload(S, From)) return ExprError(); @@ -6221,8 +6221,10 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, // earlier, but that's not guaranteed to work when initializing an object of // class type. ExprResult Result; + bool IsTemplateArgument = + CCE == Sema::CCEK_TemplateArg || CCE == Sema::CCEK_InjectedTTP; if (T->isRecordType()) { - assert(CCE == Sema::CCEK_TemplateArg && + assert(IsTemplateArgument && "unexpected class type converted constant expr"); Result = S.PerformCopyInitialization( InitializedEntity::InitializeTemplateParameter( @@ -6239,7 +6241,7 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, // A full-expression is [...] a constant-expression [...] Result = S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(), /*DiscardedValue=*/false, /*IsConstexpr=*/true, - CCE == Sema::CCEKind::CCEK_TemplateArg); + IsTemplateArgument); if (Result.isInvalid()) return Result; @@ -6248,9 +6250,6 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, QualType PreNarrowingType; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, PreNarrowingType)) { - case NK_Dependent_Narrowing: - // Implicit conversion to a narrower type, but the expression is - // value-dependent so we can't tell whether it's actually narrowing. case NK_Variable_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. We'll diagnose this in a moment. @@ -6271,6 +6270,14 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T; break; + case NK_Dependent_Narrowing: + // Implicit conversion to a narrower type, but the expression is + // value-dependent so we can't tell whether it's actually narrowing. + // For matching the parameters of a TTP, the conversion is ill-formed + // if it may narrow. + if (CCE != Sema::CCEK_InjectedTTP) + break; + [[fallthrough]]; case NK_Type_Narrowing: // FIXME: It would be better to diagnose that the expression is not a // constant expression. @@ -6343,6 +6350,8 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value, Expr::EvalResult Eval; Eval.Diag = &Notes; + assert(CCE != Sema::CCEK_InjectedTTP && "unnexpected CCE Kind"); + ConstantExprKind Kind; if (CCE == Sema::CCEK_TemplateArg && T->isRecordType()) Kind = ConstantExprKind::ClassTemplateArgument; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 38196c5c2bc12..210df2836eeb0 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5205,7 +5205,7 @@ bool Sema::CheckTemplateArgument( SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, CheckTemplateArgumentKind CTAK, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg) { + bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted, @@ -5260,8 +5260,9 @@ bool Sema::CheckTemplateArgument( Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument SugaredResult, CanonicalResult; unsigned CurSFINAEErrors = NumSFINAEErrors; - ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult, - CanonicalResult, CTAK); + ExprResult Res = + CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult, + CanonicalResult, PartialOrderingTTP, CTAK); if (Res.isInvalid()) return true; // If the current template argument causes an error, give up now. @@ -5326,7 +5327,8 @@ bool Sema::CheckTemplateArgument( TemplateArgument SugaredResult, CanonicalResult; E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult, - CanonicalResult, CTAK_Specified); + CanonicalResult, /*PartialOrderingTTP=*/false, + CTAK_Specified); if (E.isInvalid()) return true; @@ -5585,11 +5587,11 @@ bool Sema::CheckTemplateArgumentList( getExpandedPackSize(*Param)) Arg = Arg.getPackExpansionPattern(); TemplateArgumentLoc NewArgLoc(Arg, ArgLoc.getLocInfo()); - if (CheckTemplateArgument(*Param, NewArgLoc, Template, TemplateLoc, - RAngleLoc, SugaredArgumentPack.size(), - SugaredConverted, CanonicalConverted, - CTAK_Specified, /*PartialOrdering=*/false, - MatchedPackOnParmToNonPackOnArg)) + if (CheckTemplateArgument( + *Param, NewArgLoc, Template, TemplateLoc, RAngleLoc, + SugaredArgumentPack.size(), SugaredConverted, + CanonicalConverted, CTAK_Specified, /*PartialOrdering=*/false, + /*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg)) return true; Arg = NewArgLoc.getArgument(); CanonicalConverted.back().setIsDefaulted( @@ -5601,11 +5603,11 @@ bool Sema::CheckTemplateArgumentList( TemplateArgumentLoc(TemplateArgument::CreatePackCopy(Context, Args), ArgLoc.getLocInfo()); } else { - if (CheckTemplateArgument(*Param, ArgLoc, Template, TemplateLoc, - RAngleLoc, SugaredArgumentPack.size(), - SugaredConverted, CanonicalConverted, - CTAK_Specified, /*PartialOrdering=*/false, - MatchedPackOnParmToNonPackOnArg)) + if (CheckTemplateArgument( + *Param, ArgLoc, Template, TemplateLoc, RAngleLoc, + SugaredArgumentPack.size(), SugaredConverted, + CanonicalConverted, CTAK_Specified, /*PartialOrdering=*/false, + PartialOrderingTTP, MatchedPackOnParmToNonPackOnArg)) return true; CanonicalConverted.back().setIsDefaulted( clang::isSubstitutedDefaultArgument(Context, ArgLoc.getArgument(), @@ -5753,6 +5755,7 @@ bool Sema::CheckTemplateArgumentList( if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, SugaredConverted, CanonicalConverted, CTAK_Specified, /*PartialOrdering=*/false, + /*PartialOrderingTTP=*/false, /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) return true; @@ -6740,6 +6743,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *Arg, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, + bool PartialOrderingTTP, CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getBeginLoc(); @@ -6930,17 +6934,21 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, IsConvertedConstantExpression = false; } - if (getLangOpts().CPlusPlus17) { + if (getLangOpts().CPlusPlus17 || PartialOrderingTTP) { // C++17 [temp.arg.nontype]p1: // A template-argument for a non-type template parameter shall be // a converted constant expression of the type of the template-parameter. APValue Value; ExprResult ArgResult; if (IsConvertedConstantExpression) { - ArgResult = BuildConvertedConstantExpression(Arg, ParamType, - CCEK_TemplateArg, Param); - if (ArgResult.isInvalid()) + ArgResult = BuildConvertedConstantExpression( + Arg, ParamType, + PartialOrderingTTP ? CCEK_InjectedTTP : CCEK_TemplateArg, Param); + assert(!ArgResult.isUnset()); + if (ArgResult.isInvalid()) { + NoteTemplateParameterLocation(*Param); return ExprError(); + } } else { ArgResult = Arg; } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 7882d7a755d34..2b96692727a7c 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2979,7 +2979,8 @@ static bool ConvertDeducedTemplateArgument( ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) : Sema::CTAK_Specified, - PartialOrdering, &MatchedPackOnParmToNonPackOnArg); + PartialOrdering, /*PartialOrderingTTP=*/false, + &MatchedPackOnParmToNonPackOnArg); if (MatchedPackOnParmToNonPackOnArg) Info.setMatchedPackOnParmToNonPackOnArg(); return Res; @@ -3179,6 +3180,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(), /*ArgumentPackIndex=*/0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified, /*PartialOrdering=*/false, + /*PartialOrderingTTP=*/false, /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3dc5696bd3821..862086a0c5340 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2399,9 +2399,10 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr( // The call to CheckTemplateArgument here produces the ImpCast. TemplateArgument SugaredConverted, CanonicalConverted; if (SemaRef - .CheckTemplateArgument(E->getParameter(), SubstType, - SubstReplacement.get(), SugaredConverted, - CanonicalConverted, Sema::CTAK_Specified) + .CheckTemplateArgument( + E->getParameter(), SubstType, SubstReplacement.get(), + SugaredConverted, CanonicalConverted, + /*PartialOrderingTTP=*/false, Sema::CTAK_Specified) .isInvalid()) return true; return transformNonTypeTemplateParmRef(E->getAssociatedDecl(), diff --git a/clang/test/CXX/drs/cwg0xx.cpp b/clang/test/CXX/drs/cwg0xx.cpp index 15f469440c66f..44a0eb520af22 100644 --- a/clang/test/CXX/drs/cwg0xx.cpp +++ b/clang/test/CXX/drs/cwg0xx.cpp @@ -521,12 +521,12 @@ namespace example1 { namespace A { int i; } - + namespace A1 { using A::i; using A::i; } - + void f() { using A::i; @@ -1371,7 +1371,7 @@ namespace cwg92 { // cwg92: 4 c++17 // considered in this context. In C++17, we *do* perform an implicit // conversion (which performs initialization), and the exception specification // is part of the type of the parameter, so this is invalid. - template struct X {}; + template struct X {}; // since-cxx17-note {{template parameter is declared here}} X<&f> xp; // since-cxx17-error@-1 {{value of type 'void (*)() throw(int, float)' is not implicitly convertible to 'void (*)() throw()'}} diff --git a/clang/test/CXX/drs/cwg12xx.cpp b/clang/test/CXX/drs/cwg12xx.cpp index 344adb6d72023..e02a7e11b80b2 100644 --- a/clang/test/CXX/drs/cwg12xx.cpp +++ b/clang/test/CXX/drs/cwg12xx.cpp @@ -155,6 +155,8 @@ namespace cwg1295 { // cwg1295: 4 // cxx98-14-error@-1 {{non-type template argument does not refer to any declaration}} // cxx98-14-note@#cwg1295-Y {{template parameter is declared here}} // since-cxx17-error@#cwg1295-y {{reference cannot bind to bit-field in converted constant expression}} + // since-cxx17-note@#cwg1295-Y {{template parameter is declared here}} + #if __cplusplus >= 201103L const unsigned other = 0; diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index b5e07a66bb4ed..6c420ecd4c91d 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -444,7 +444,7 @@ namespace cwg329 { // cwg329: 3.5 // expected-note@#cwg329-b {{in instantiation of template class 'cwg329::A' requested here}} // expected-note@#cwg329-i {{previous definition is here}} }; - A a; + A a; A b; // #cwg329-b void test() { @@ -688,9 +688,9 @@ namespace cwg341 { // cwg341: sup 1708 namespace B { extern "C" int &cwg341_a = cwg341_a; // expected-error@-1 {{redefinition of 'cwg341_a'}} - // expected-note@#cwg341_a {{previous definition is here}} + // expected-note@#cwg341_a {{previous definition is here}} } - extern "C" void cwg341_b(); // #cwg341_b + extern "C" void cwg341_b(); // #cwg341_b } int cwg341_a; // expected-error@-1 {{declaration of 'cwg341_a' in global scope conflicts with declaration with C language linkage}} @@ -708,7 +708,7 @@ namespace cwg341 { // expected-error@-1 {{declaration of 'cwg341_d' with C language linkage conflicts with declaration in global scope}} // expected-note@#cwg341_d {{declared in global scope here}} - namespace A { extern "C" int cwg341_e; } // #cwg341_e + namespace A { extern "C" int cwg341_e; } // #cwg341_e namespace B { extern "C" void cwg341_e(); } // expected-error@-1 {{redefinition of 'cwg341_e' as different kind of symbol}} // expected-note@#cwg341_e {{previous definition is here}} @@ -960,6 +960,7 @@ namespace cwg354 { // cwg354: 3.1 c++11 // cxx11-14-error@#cwg354-p0 {{null non-type template argument must be cast to template parameter type 'int *'}} // cxx11-14-note@#cwg354-ptr {{template parameter is declared here}} // since-cxx17-error@#cwg354-p0 {{conversion from 'int' to 'int *' is not allowed in a converted constant expression}} + // since-cxx17-note@#cwg354-ptr {{template parameter is declared here}} ptr<(int*)0> p1; // cxx98-error@-1 {{non-type template argument does not refer to any declaration}} // cxx98-note@#cwg354-ptr {{template parameter is declared here}} @@ -969,12 +970,14 @@ namespace cwg354 { // cwg354: 3.1 c++11 // cxx11-14-error@#cwg354-p2 {{null non-type template argument of type 'float *' does not match template parameter of type 'int *'}} // cxx11-14-note@#cwg354-ptr {{template parameter is declared here}} // since-cxx17-error@#cwg354-p2 {{value of type 'float *' is not implicitly convertible to 'int *'}} + // since-cxx17-note@#cwg354-ptr {{template parameter is declared here}} ptr<(int S::*)0> p3; // #cwg354-p3 // cxx98-error@#cwg354-p3 {{non-type template argument does not refer to any declaration}} // cxx98-note@#cwg354-ptr {{template parameter is declared here}} // cxx11-14-error@#cwg354-p3 {{null non-type template argument of type 'int S::*' does not match template parameter of type 'int *'}} // cxx11-14-note@#cwg354-ptr {{template parameter is declared here}} // since-cxx17-error@#cwg354-p3 {{value of type 'int S::*' is not implicitly convertible to 'int *'}} + // since-cxx17-note@#cwg354-ptr {{template parameter is declared here}} template int both(); // #cwg354-both-int-ptr template int both(); // #cwg354-both-int @@ -991,6 +994,7 @@ namespace cwg354 { // cwg354: 3.1 c++11 // cxx11-14-error@#cwg354-m0 {{null non-type template argument must be cast to template parameter type 'int S::*'}} // cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}} // since-cxx17-error@#cwg354-m0 {{conversion from 'int' to 'int S::*' is not allowed in a converted constant expression}} + // since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}} ptr_mem<(int S::*)0> m1; // cxx98-error@-1 {{non-type template argument is not a pointer to member constant}} ptr_mem<(float S::*)0> m2; // #cwg354-m2 @@ -999,12 +1003,14 @@ namespace cwg354 { // cwg354: 3.1 c++11 // cxx11-14-error@#cwg354-m2 {{null non-type template argument of type 'float S::*' does not match template parameter of type 'int S::*'}} // cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}} // since-cxx17-error@#cwg354-m2 {{value of type 'float S::*' is not implicitly convertible to 'int S::*'}} + // since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}} ptr_mem<(int *)0> m3; // #cwg354-m3 // cxx98-error@#cwg354-m3 {{non-type template argument of type 'int *' cannot be converted to a value of type 'int S::*'}} // cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}} // cxx11-14-error@#cwg354-m3 {{null non-type template argument of type 'int *' does not match template parameter of type 'int S::*'}} // cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}} // since-cxx17-error@#cwg354-m3 {{value of type 'int *' is not implicitly convertible to 'int S::*'}} + // since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}} } // namespace cwg354 struct cwg355_S; // cwg355: 2.7 @@ -1116,7 +1122,7 @@ namespace cwg364 { // cwg364: 2.7 } // namespace cwg364 namespace cwg366 { // cwg366: 2.7 -#if "foo" // expected-error {{invalid token at start of a preprocessor expression}} +#if "foo" // expected-error {{invalid token at start of a preprocessor expression}} #endif } // namespace cwg366 diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp index 5bd70c5250b59..3eedef3cf7712 100644 --- a/clang/test/CXX/expr/expr.const/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify=expected,cxx11 %s +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify=expected,cxx17 %s // A converted constant expression of type T is a core constant expression, int nonconst = 8; // expected-note 3 {{here}} @@ -66,7 +66,8 @@ enum class EEE : unsigned short { e = 123456, // expected-error {{enumerator value evaluates to 123456, which cannot be narrowed to type 'unsigned short'}} f = -3 // expected-error {{enumerator value evaluates to -3, which cannot be narrowed to type 'unsigned short'}} }; -template using A = int; +template using A = int; // cxx17-note 2{{template parameter is declared here}} + using Int = A; using Int = A; // expected-error {{not implicitly convertible}} using Int = A<(int)EE::EE32>; @@ -78,6 +79,7 @@ using Int = A<-3>; // expected-error {{template argument evaluates to -3, which // integral conversions as well as boolean conversions. // FIXME: Per core issue 1407, this is not correct. template struct Val { static constexpr T value = v; }; +// cxx17-note@-1 2{{template parameter is declared here}} static_assert(Val::value == 1, ""); // ok static_assert(Val::value == 0, ""); // ok static_assert(Val::value == 1, ""); // ok diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp index 7fce615516924..629000d88acc3 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp @@ -8,7 +8,7 @@ // be one of: // -- an integral constant expression; or // -- the name of a non-type template-parameter ; or -#ifndef CPP11ONLY +#ifndef CPP11ONLY namespace non_type_tmpl_param { template struct X0 { X0(); }; @@ -31,15 +31,18 @@ namespace non_type_tmpl_param { // omitted if the name refers to a function or array and shall be omitted // if the corresopnding template-parameter is a reference; or namespace addr_of_obj_or_func { - template struct X0 { }; // precxx17-note 5{{here}} + template struct X0 { }; // expected-note 5{{here}} #if __cplusplus >= 201103L // precxx17-note@-2 2{{template parameter is declared here}} #endif - template struct X1 { }; - template struct X2 { }; // precxx17-note 4{{here}} - template struct X2k { }; // precxx17-note {{here}} - template struct X3 { }; // precxx17-note 4{{here}} + template struct X1 { }; // cxx17-note {{here}} +#if __cplusplus <= 199711L + // precxx17-note@-2 {{here}} +#endif + template struct X2 { }; // expected-note 4{{here}} + template struct X2k { }; // expected-note {{here}} + template struct X3 { }; // expected-note 4{{here}} int i = 42; #if __cplusplus >= 201103L diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp index 54fcfccad6f52..3caed045c6688 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp @@ -18,8 +18,9 @@ eval> eD; // expected-error{{implicit instantiation of undefined temp eval> eE; // expected-error{{implicit instantiation of undefined template 'eval>}} template< - template // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'void *')}} - class TT // expected-note {{previous template template parameter is here}} + template // expected-error {{cannot be narrowed from type 'int' to 'short'}} + // expected-error@-1 {{conversion from 'int' to 'void *' is not allowed in a converted constant expression}} + class TT // expected-note 2{{previous template template parameter is here}} > struct X0 { }; template struct X0a; @@ -31,12 +32,13 @@ template struct X0e; // expected-note{{template parameter is dec X0 inst_x0a; X0 inst_x0b; X0 inst_x0c; -X0 inst_x0d; +X0 inst_x0d; // expected-note {{has different template parameters}} X0 inst_x0e; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}} template // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('short' vs 'void *')}} - class TT // expected-note {{previous template template parameter is here}} + template // expected-error {{conversion from 'short' to 'void *' is not allowed in a converted constant expression}} + // expected-error@-1 {{cannot be narrowed from type 'int' to 'short'}} + class TT // expected-note 2{{previous template template parameter is here}} > struct X1 { }; template struct X1a; @@ -49,8 +51,8 @@ X1 inst_x1a; X1 inst_x1b; X1 inst_x1c; X1 inst_sx1d; -X1 inst_ix1d; -X1 inst_x1e; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}} +X1 inst_ix1d; // expected-note {{has different template parameters}} +X1 inst_x1e; // expected-note {{has different template parameters}} template class X2; // expected-note{{template is declared here}} \ // expected-note{{template is declared here}} diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index b197f319e0d15..f587af4beb7ce 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -40,7 +40,10 @@ void g() { template_param_kinds_1<0>(); // ok, from cxx-templates-a.h template_param_kinds_1(); // ok, from cxx-templates-b.h - template_param_kinds_2(); // ok, from cxx-templates-b.h + + template_param_kinds_2(); // expected-error {{no matching function for call}} + // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} template_param_kinds_2(); // expected-error {{ambiguous}} // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} diff --git a/clang/test/SemaObjCXX/noescape.mm b/clang/test/SemaObjCXX/noescape.mm index 999a91b87300b..4484e3b955ac0 100644 --- a/clang/test/SemaObjCXX/noescape.mm +++ b/clang/test/SemaObjCXX/noescape.mm @@ -77,12 +77,11 @@ -(void) m0:(int*) p {} void (*fnptr0)(int *); void (*fnptr1)(__attribute__((noescape)) int *); template struct S4 {}; -template struct S5 {}; - #if __cplusplus < 201406 - // expected-note@-4 {{template parameter is declared here}} - // expected-note@-4 {{template parameter is declared here}} +// expected-note@-2 {{template parameter is declared here}} #endif +template struct S5 {}; +// expected-note@-1 {{template parameter is declared here}} void test0() { fnptr0 = &func0; diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp index 21a1b89ce79b4..888ae59f687ef 100644 --- a/clang/test/SemaTemplate/cwg2398.cpp +++ b/clang/test/SemaTemplate/cwg2398.cpp @@ -362,15 +362,17 @@ namespace classes { namespace packs { namespace t1 { - // FIXME: This should be rejected template class> struct A {}; - // old-note@-1 {{previous non-type template parameter with type 'int' is here}} + // new-error@-1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}} + // new-note@-2 {{previous template template parameter is here}} + // old-note@-3 {{previous non-type template parameter with type 'int' is here}} template struct B; // old-note@-1 {{template non-type parameter has a different type 'char' in template argument}} template struct A; - // old-error@-1 {{has different template parameters}} + // new-note@-1 {{has different template parameters}} + // old-error@-2 {{has different template parameters}} } // namespace t1 namespace t2 { template class> struct A {}; @@ -383,15 +385,17 @@ namespace packs { // old-error@-1 {{has different template parameters}} } // namespace t2 namespace t3 { - // FIXME: This should be rejected template class> struct A {}; - // old-note@-1 {{previous non-type template parameter with type 'int' is here}} + // new-error@-1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}} + // new-note@-2 {{previous template template parameter is here}} + // old-note@-3 {{previous non-type template parameter with type 'int' is here}} template struct B; // old-note@-1 {{template non-type parameter has a different type 'char' in template argument}} template struct A; - // old-error@-1 {{has different template parameters}} + // new-note@-1 {{has different template parameters}} + // old-error@-2 {{has different template parameters}} } // namespace t3 namespace t4 { template class> struct A {}; @@ -648,3 +652,50 @@ namespace nttp_auto { // new-note@-1 {{different template parameters}} } // namespace t3 } // namespace nttp_auto + +namespace nttp_partial_order { + namespace t1 { + // FIXME: This should pick the second overload. + template class TT1> void f(TT1<0>); + // new-note@-1 {{here}} + template class TT2> void f(TT2<0>) {}; + // new-note@-1 {{here}} + template struct B {}; + template void f(B<0>); + // new-error@-1 {{ambiguous}} + } // namespace t1 + namespace t2 { + // FIXME: This should pick the second overload. + struct A {} a; + template class TT1> void f(TT1); + // new-note@-1 {{here}} + template class TT2> void f(TT2) {}; + // new-note@-1 {{here}} + template struct B {}; + template void f(B); + // new-error@-1 {{ambiguous}} + } // namespace t2 + namespace t3 { + // FIXME: This should pick the second overload. + struct A {} a; + template class TT1> void f(TT1<&a>); + // new-note@-1 {{here}} + template class TT2> void f(TT2<&a>) {}; + // new-note@-1 {{here}} + template struct B {}; + template void f(B<&a>); + // new-error@-1 {{ambiguous}} + } // namespace t3 + namespace t4 { + // FIXME: This should pick the second overload. + struct A {}; + using nullptr_t = decltype(nullptr); + template class TT2> void f(TT2); + // new-note@-1 {{here}} + template class TT1> void f(TT1) {}; + // new-note@-1 {{here}} + template struct B {}; + template void f(B); + // new-error@-1 {{ambiguous}} + } // namespace t4 +} // namespace nttp_partial_order diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp index 3b1fbda414c12..5ea34c0254ec1 100644 --- a/clang/test/SemaTemplate/default-arguments.cpp +++ b/clang/test/SemaTemplate/default-arguments.cpp @@ -52,20 +52,20 @@ struct X2 { template::type> // expected-error{{no type named 'type' in 'X1'}} \ // expected-error{{no type named 'type' in 'X1'}} struct Inner1 { }; // expected-note{{template is declared here}} - + template::value> // expected-error{{no member named 'value' in 'X1'}} \ // expected-error{{no member named 'value' in 'X1'}} struct NonType1 { }; // expected-note{{template is declared here}} - + template struct Inner2 { }; - + template struct Inner3 { template struct VeryInner { }; - - template struct NonType2 { }; }; @@ -89,11 +89,11 @@ struct is_same { static const bool value = false; }; template struct is_same { static const bool value = true; }; -int array1[is_same<__typeof__(vi), +int array1[is_same<__typeof__(vi), X2::Inner3::VeryInner >::value? 1 : -1]; int array2[is_same<__typeof(x2_deep_nontype), - X2::Inner3::NonType2::Inner3::NonType2 >::value? 1 : -1]; // Template template parameter defaults @@ -109,18 +109,20 @@ struct add_pointer { template class X = T::template apply> struct X4; -int array4[is_same, +int array4[is_same, X4 >::value? 1 : -1]; template struct X5 {}; -template struct X5b {}; -template class B = X5> +template struct X5b {}; +template class B = X5> // expected-error {{cannot be narrowed from type 'long long' to 'int'}} + // expected-note@-1 {{has different template parameters}} + // expected-note@-2 {{previous template template parameter is here}} struct X6 {}; X6 x6a; -X6 x6b; -X6 x6c; +X6 x6b; // expected-note {{while checking a default template argument used here}} +X6 x6c; template class X = B > struct X7; // expected-error{{must be a class template}} diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp index 39aeeb1c1a6a3..dce30aa2af4ee 100644 --- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp +++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -24,11 +24,13 @@ template struct B; template class X> // expected-error{{cannot have type 'float'}} + // expected-error@-1 {{cannot be narrowed from type 'long long' to 'int'}} + // expected-note@-2 {{previous template template parameter is here}} struct X0 { }; X0 x0b1; X0 x0b2; // expected-note{{while substituting}} -X0 x0b3; +X0 x0b3; // expected-note {{has different template parameters}} template class TT> struct X1 { }; diff --git a/clang/test/SemaTemplate/instantiation-default-2.cpp b/clang/test/SemaTemplate/instantiation-default-2.cpp index 99c25000bcb0b..ffa77cf1ee567 100644 --- a/clang/test/SemaTemplate/instantiation-default-2.cpp +++ b/clang/test/SemaTemplate/instantiation-default-2.cpp @@ -2,8 +2,10 @@ // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17,precxx20 -std=c++17 %s // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 %std_cxx20- %s -template struct Constant; // precxx17-note{{template parameter is declared here}} \ -// FIXME: bad location precxx20-error{{a non-type template parameter cannot have type 'float'}} +template struct Constant; +// FIXME: bad location precxx20-error@-1 {{a non-type template parameter cannot have type 'float'}} +// expected-note@-2 {{template parameter is declared here}} +// cxx20-note@-3 {{template parameter is declared here}} Constant *c1; diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp index a54992a397187..4d7f2d9c5c946 100644 --- a/clang/test/SemaTemplate/nested-template.cpp +++ b/clang/test/SemaTemplate/nested-template.cpp @@ -112,7 +112,9 @@ template struct X1::B; // Template template parameters template struct X2 { - template class> // expected-error{{cannot have type 'float'}} + template class> // expected-error {{cannot have type 'float'}} + // expected-error@-1 {{cannot be narrowed from type 'long long' to 'int'}} + // expected-note@-2 {{previous template template parameter is here}} struct Inner { }; }; @@ -121,7 +123,7 @@ template X2::Inner x2i1; X2 x2a; // expected-note{{instantiation}} -X2::Inner x2i3; +X2::Inner x2i3; // expected-note {{has different template parameters}} namespace PR10896 { template diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index 8d9356bb3201c..c35743b87adbc 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s -template struct A {}; +template struct A {}; // expected-note 3{{template parameter is declared here}} template constexpr bool is_same = false; template constexpr bool is_same = true; @@ -122,13 +122,13 @@ namespace DeduceDifferentType { int a_imp = a(A<3>()); // expected-error {{no matching function}} int a_exp = a<3>(A<3>()); - template struct B {}; + template struct B {}; // expected-note {{template parameter is declared here}} template int b(B

); // expected-error {{value of type 'int *' is not implicitly convertible to 'decltype(nullptr)'}} int b_imp = b(B()); // expected-error {{no matching function}} int b_exp = b(B()); // expected-error {{no matching function}} struct X { constexpr operator int() { return 0; } } x; - template struct C {}; + template struct C {}; // expected-note {{template parameter is declared here}} template int c(C); // expected-error {{value of type 'int' is not implicitly convertible to 'X &'}} int c_imp = c(C()); // expected-error {{no matching function}} int c_exp = c(C()); // expected-error {{no matching function}} @@ -448,7 +448,7 @@ namespace PR42108 { struct R {}; struct S { constexpr S() {} constexpr S(R) {} }; struct T { constexpr operator S() { return {}; } }; - template struct A {}; + template struct A {}; // expected-note {{template parameter is declared here}} void f() { A(); // expected-error {{would bind reference to a temporary}} A(); // expected-error {{reference to temporary object}} diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp index ad73daa8e214c..56ceb7af4ccd9 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp @@ -101,7 +101,7 @@ namespace ConvertedConstant { struct { int i : 2; } b; - template struct Y {}; + template struct Y {}; // expected-note {{template parameter is declared here}} void f(Y) {} // expected-error {{reference cannot bind to bit-field in converted constant expression}} } @@ -238,7 +238,7 @@ namespace UnnamedBitfield { } namespace Temporary { - template struct A {}; + template struct A {}; // expected-note {{template parameter is declared here}} A<0> a0; // expected-error {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}} A<(const int&)1> a1; // expected-error {{reference to temporary object is not allowed in a template argument}} diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp b/clang/test/SemaTemplate/temp_arg_template.cpp index 9908af5e78669..aa53dba652050 100644 --- a/clang/test/SemaTemplate/temp_arg_template.cpp +++ b/clang/test/SemaTemplate/temp_arg_template.cpp @@ -7,14 +7,13 @@ template class X> struct A; // #A template class X> struct B; // expected-note{{previous template template parameter is here}} template class X> struct C; -// precxx17-error@-1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'const int &')}} -// cxx17-error@-2 {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}} -// expected-note@-3 {{previous template template parameter is here}} +// expected-error@-1 {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}} +// expected-note@-2 {{previous template template parameter is here}} template struct X; // expected-note {{template is declared here}} template struct Y; // expected-note {{template parameter is declared here}} template struct Ylong; -template struct Yref; // precxx17-note {{template parameter is declared here}} +template struct Yref; // expected-note {{template parameter is declared here}} namespace N { template struct Z; diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp index dcfc7b5b27288..2e5a36ae6ed08 100644 --- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp +++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp @@ -66,8 +66,9 @@ namespace DependentType { using ok = Pt, tT0>; using err1 = tT0; // expected-error {{too few template arguments for class template 'ii'}} // expected-note@-1 {{different template parameters}} - using err2 = tT0; // FIXME: should this be OK? - using err2a = tT0; // FIXME: should this be OK (if long long is larger than int)? + using err2 = tT0; + using err2a = tT0; // expected-error@#tT0 {{cannot be narrowed from type 'long long' to 'int'}} + // expected-note@-1 {{different template parameters}} using err2b = tT0; // expected-error@#tT0 {{value of type 'void *' is not implicitly convertible to 'int'}} // expected-note@-1 {{different template parameters}} using err3 = tT0; // expected-error@#tT0 {{template argument for template type parameter must be a type}}