From 8210ac8a213a8409dc3b470fb295b70e8264934d Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Sun, 12 Jan 2025 14:45:24 -0300 Subject: [PATCH] [clang] disallow narrowing when matching template template parameters This fixes the core issue described in P3579, following the design intent of P0522 to not introduce any new cases where a template template parameter match is allowed for a template which is not valid for all possible uses. With this patch, narrowing conversions is disallowed for TTP matching. This reuses the existing machinery for diagnosing narrowing in a converted constant expression. Since P0522 is a DR and we apply it all the way back to C++98, this brings that machinery to use in older standards, in this very narrow scope of TTP matching. This still doesn't solve the ambiguity when partial ordering NTTPs of different integral types, this is blocked by a different bug which will be fixed in a subsequent patch. --- clang/docs/ReleaseNotes.rst | 3 + .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/include/clang/Sema/Sema.h | 3 + clang/lib/Sema/SemaLookup.cpp | 2 +- clang/lib/Sema/SemaOverload.cpp | 23 +++-- clang/lib/Sema/SemaTemplate.cpp | 44 +++++---- clang/lib/Sema/SemaTemplateDeduction.cpp | 4 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 7 +- clang/test/CXX/drs/cwg0xx.cpp | 6 +- clang/test/CXX/drs/cwg12xx.cpp | 2 + clang/test/CXX/drs/cwg3xx.cpp | 16 +++- clang/test/CXX/expr/expr.const/p3-0x.cpp | 8 +- .../CXX/temp/temp.arg/temp.arg.nontype/p1.cpp | 15 +-- .../temp/temp.arg/temp.arg.template/p3-0x.cpp | 16 ++-- clang/test/Modules/cxx-templates.cpp | 5 +- clang/test/SemaObjCXX/noescape.mm | 7 +- clang/test/SemaTemplate/cwg2398.cpp | 95 +++++++++++++++++-- clang/test/SemaTemplate/default-arguments.cpp | 28 +++--- .../instantiate-template-template-parm.cpp | 4 +- .../SemaTemplate/instantiation-default-2.cpp | 6 +- clang/test/SemaTemplate/nested-template.cpp | 6 +- .../SemaTemplate/temp_arg_nontype_cxx1z.cpp | 8 +- .../SemaTemplate/temp_arg_nontype_cxx20.cpp | 4 +- clang/test/SemaTemplate/temp_arg_template.cpp | 7 +- .../SemaTemplate/temp_arg_template_p0522.cpp | 5 +- 25 files changed, 230 insertions(+), 98 deletions(-) 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..1d35b574176a7 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 {}; @@ -427,6 +431,14 @@ namespace fun_tmpl_call { template struct A {}; void test() { f(A()); } } // namespace order_func_pack + namespace match_enum { + enum A {}; + template class TT1> void f(TT1<{}>) {} + // old-note@-1 {{invalid explicitly-specified argument}} + template struct B {}; + template void f(B<{}>); + // old-error@-1 {{does not refer to a function template}} + } // namespace match_enum namespace match_method { struct A { template