gcc points out that DTST is unused in + if (auto *DTST = dyn_cast<DeducedTemplateSpecializationType>(DeducedT)) {
Should it be used? Or should we delete the lhs of that assignment? On Wed, Oct 21, 2020 at 6:03 PM Richard Smith via cfe-commits < cfe-commits@lists.llvm.org> wrote: > > Author: Richard Smith > Date: 2020-10-21T15:03:22-07:00 > New Revision: e97e9851b227e98e39c27c4c8f5558e331cde8b4 > > URL: > https://github.com/llvm/llvm-project/commit/e97e9851b227e98e39c27c4c8f5558e331cde8b4 > DIFF: > https://github.com/llvm/llvm-project/commit/e97e9851b227e98e39c27c4c8f5558e331cde8b4.diff > > LOG: [c++20] For P0732R2: permit class template argument deduction for > non-type template parameters. > > Added: > clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p2.cpp > clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-cxx20.cpp > > Modified: > clang/lib/Sema/SemaTemplate.cpp > clang/lib/Sema/SemaTemplateDeduction.cpp > clang/lib/Sema/SemaType.cpp > clang/test/SemaTemplate/deduction.cpp > clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp > > Removed: > > > > > ################################################################################ > diff --git a/clang/lib/Sema/SemaTemplate.cpp > b/clang/lib/Sema/SemaTemplate.cpp > index 8bff982d66be..d23ad9f7d91d 100644 > --- a/clang/lib/Sema/SemaTemplate.cpp > +++ b/clang/lib/Sema/SemaTemplate.cpp > @@ -23,6 +23,7 @@ > #include "clang/Basic/Stack.h" > #include "clang/Basic/TargetInfo.h" > #include "clang/Sema/DeclSpec.h" > +#include "clang/Sema/Initialization.h" > #include "clang/Sema/Lookup.h" > #include "clang/Sema/Overload.h" > #include "clang/Sema/ParsedTemplate.h" > @@ -6807,14 +6808,15 @@ ExprResult > Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, > SourceLocation StartLoc = Arg->getBeginLoc(); > > // If the parameter type somehow involves auto, deduce the type now. > - if (getLangOpts().CPlusPlus17 && ParamType->isUndeducedType()) { > + DeducedType *DeducedT = ParamType->getContainedDeducedType(); > + if (getLangOpts().CPlusPlus17 && DeducedT && !DeducedT->isDeduced()) { > // During template argument deduction, we allow 'decltype(auto)' to > // match an arbitrary dependent argument. > // FIXME: The language rules don't say what happens in this case. > // FIXME: We get an opaque dependent type out of decltype(auto) if the > // expression is merely instantiation-dependent; is this enough? > if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) { > - auto *AT = dyn_cast<AutoType>(ParamType); > + auto *AT = dyn_cast<AutoType>(DeducedT); > if (AT && AT->isDecltypeAuto()) { > Converted = TemplateArgument(Arg); > return Arg; > @@ -6828,14 +6830,26 @@ ExprResult > Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, > Expr *DeductionArg = Arg; > if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg)) > DeductionArg = PE->getPattern(); > - if (DeduceAutoType( > - Context.getTrivialTypeSourceInfo(ParamType, > Param->getLocation()), > - DeductionArg, ParamType, Depth, > - // We do not check constraints right now because the > - // immediately-declared constraint of the auto type is also an > - // associated constraint, and will be checked along with the > other > - // associated constraints after checking the template > argument list. > - /*IgnoreConstraints=*/true) == DAR_Failed) { > + TypeSourceInfo *TSI = > + Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()); > + if (auto *DTST = > dyn_cast<DeducedTemplateSpecializationType>(DeducedT)) { > + InitializedEntity Entity = > + InitializedEntity::InitializeTemplateParameter(ParamType, > Param); > + InitializationKind Kind = InitializationKind::CreateForInit( > + DeductionArg->getBeginLoc(), /*DirectInit*/false, DeductionArg); > + Expr *Inits[1] = {DeductionArg}; > + ParamType = > + DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, > Inits); > + if (ParamType.isNull()) > + return ExprError(); > + } else if (DeduceAutoType( > + TSI, DeductionArg, ParamType, Depth, > + // We do not check constraints right now because the > + // immediately-declared constraint of the auto type is > also > + // an associated constraint, and will be checked along > with > + // the other associated constraints after checking the > + // template argument list. > + /*IgnoreConstraints=*/true) == DAR_Failed) { > Diag(Arg->getExprLoc(), > diag::err_non_type_template_parm_type_deduction_failure) > << Param->getDeclName() << Param->getType() << Arg->getType() > @@ -6870,9 +6884,9 @@ ExprResult > Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, > // FIXME: If the argument type contains 'auto', we carry on and fail > the > // type check in order to force specific types to be more specialized > than > // 'auto'. It's not clear how partial ordering with 'auto' is > supposed to > - // work. > + // work. Similarly for CTAD, when comparing 'A<x>' against 'A'. > if ((ParamType->isDependentType() || Arg->isTypeDependent()) && > - !Arg->getType()->getContainedAutoType()) { > + !Arg->getType()->getContainedDeducedType()) { > Converted = TemplateArgument(Arg); > return Arg; > } > > diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp > b/clang/lib/Sema/SemaTemplateDeduction.cpp > index 1c20ca619138..886377108e3f 100644 > --- a/clang/lib/Sema/SemaTemplateDeduction.cpp > +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp > @@ -1615,14 +1615,18 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, > return Sema::TDK_Success; > } > } else if (!Param->isDependentType()) { > - CanQualType ParamUnqualType = CanParam.getUnqualifiedType(), > - ArgUnqualType = CanArg.getUnqualifiedType(); > - bool Success = > - (TDF & TDF_AllowCompatibleFunctionType) > - ? S.isSameOrCompatibleFunctionType(ParamUnqualType, > ArgUnqualType) > - : ParamUnqualType == ArgUnqualType; > - if (Success) > + if (!(TDF & TDF_SkipNonDependent)) { > + CanQualType ParamUnqualType = CanParam.getUnqualifiedType(), > + ArgUnqualType = CanArg.getUnqualifiedType(); > + bool Success = > + (TDF & TDF_AllowCompatibleFunctionType) > + ? S.isSameOrCompatibleFunctionType(ParamUnqualType, > ArgUnqualType) > + : ParamUnqualType == ArgUnqualType; > + if (Success) > + return Sema::TDK_Success; > + } else { > return Sema::TDK_Success; > + } > } > > switch (Param->getTypeClass()) { > > diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp > index 4d156634bf48..1ba1869e0fe5 100644 > --- a/clang/lib/Sema/SemaType.cpp > +++ b/clang/lib/Sema/SemaType.cpp > @@ -3375,8 +3375,9 @@ static QualType > GetDeclSpecTypeForDeclarator(TypeProcessingState &state, > Error = 7; // Exception declaration > break; > case DeclaratorContext::TemplateParamContext: > - if (isa<DeducedTemplateSpecializationType>(Deduced)) > - Error = 19; // Template parameter > + if (isa<DeducedTemplateSpecializationType>(Deduced) && > + !SemaRef.getLangOpts().CPlusPlus20) > + Error = 19; // Template parameter (until C++20) > else if (!SemaRef.getLangOpts().CPlusPlus17) > Error = 8; // Template parameter (until C++17) > break; > > diff --git > a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p2.cpp > b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p2.cpp > new file mode 100644 > index 000000000000..8468731a3cb0 > --- /dev/null > +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p2.cpp > @@ -0,0 +1,23 @@ > +// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx17 %s > +// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20 %s > + > +template<typename T> struct A { constexpr A(T) {} }; // expected-note > 1+{{here}} > + > +A a = 0; > +A b(0); > +A c = A(0); > +A d = A{0}; > +auto *p = new A(0); > +A *q = new A(0); // expected-error {{cannot form pointer to deduced class > template specialization type}} > + > +struct B { > + operator A() { // expected-error {{argument deduction not allowed in > conversion function type}} > + return A(0); > + } > +}; > + > +void f(A a); // expected-error {{argument deduction not allowed in > function prototype}} > +A f(); // expected-error {{argument deduction not allowed in function > return type}} > + > +template<A a> // cxx17-error {{argument deduction not allowed in template > parameter}} > +void f(); > > diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-cxx20.cpp > b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-cxx20.cpp > new file mode 100644 > index 000000000000..d6d2ad742d0e > --- /dev/null > +++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-cxx20.cpp > @@ -0,0 +1,23 @@ > +// RUN: %clang_cc1 -std=c++20 %s -verify > + > +using size_t = __SIZE_TYPE__; > + > +namespace CTAD { > + template<typename T> struct A { constexpr A(T) {} }; > + template<A a> using DeducedA = decltype(a); > + > + using ATest1 = DeducedA<A(0)>; > + using ATest1 = A<int>; // expected-note {{previous}} > + using ATest1 = void; // expected-error {{ > diff erent}} > + > + using ATest2 = DeducedA<A(0.0)>; > + using ATest2 = A<double>; > + > + template <size_t N> struct B { > + constexpr B(const char (&r)[N]) { __builtin_memcpy(text, r, N); } > + char text[N]; > + }; > + > + template<B b> constexpr const char *str() { return b.text; } > + static_assert(__builtin_strcmp("hello world", str<"hello world">()) == > 0); > +} > > diff --git a/clang/test/SemaTemplate/deduction.cpp > b/clang/test/SemaTemplate/deduction.cpp > index a068bcaea048..b9a1f0dccb24 100644 > --- a/clang/test/SemaTemplate/deduction.cpp > +++ b/clang/test/SemaTemplate/deduction.cpp > @@ -312,6 +312,13 @@ namespace nullptr_deduction { > f(X<nullptr_t, nullptr>()); // expected-note {{instantiation of}} > } > > + template<template<typename T, T> class X, typename T, int *P> > + void f0(X<T, P>) {} // expected-note {{deduced non-type template > argument does not have the same type as the corresponding template > parameter ('nullptr_t' vs 'int *')}} > + void h0() { > + f0(X<int*, nullptr>()); > + f0(X<nullptr_t, nullptr>()); // expected-error {{no matching > function}} > + } > + > template<template<typename T, T> class X, typename T, typename U, int > *P> > void f1(X<T, P>, X<U, P>) {} // expected-note 2{{values of > conflicting types}} > void h() { > > diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp > b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp > index d0ace9b2b2b5..1d9fefb6cbe5 100644 > --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp > +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp > @@ -124,8 +124,7 @@ namespace StableAddress { > // FIXME: Deduction guide not needed with P1816R0. > template<size_t N> str(const char (&)[N]) -> str<N>; > > - // FIXME: Explicit size not needed. > - template<str<15> s> constexpr int sum() { > + template<str s> constexpr int sum() { > int n = 0; > for (char c : s.arr) > n += c; > @@ -184,3 +183,21 @@ namespace Diags { > template<A a> struct X { static_assert(a.n == a.m); }; // > expected-error {{static_assert failed due to requirement 'Diags::A{1, 2}.n > == Diags::A{1, 2}.m'}} > template struct X<A{1, 2}>; // expected-note {{in instantiation of > template class 'Diags::X<{1, 2}>' requested here}} > } > + > +namespace CTADPartialOrder { > + template<int> struct A {}; > + template<typename T, typename U, A a> struct X; // expected-note > {{declared here}} > + template<typename T, A a> struct X<T, int, a> { static constexpr int n > = 1; }; // expected-note {{matches}} > + template<typename T, A a> struct X<T *, int, a> { static constexpr int > n = 2; }; > + template<typename T, A a> struct X<T, T, a> { static constexpr int n = > 3; }; // expected-note {{matches}} > + > + A<0> a; > + static_assert(X<void, int, a>::n == 1); > + static_assert(X<int*, int, a>::n == 2); > + static_assert(X<void, void, a>::n == 3); > + static_assert(X<int, int, a>::n == -1); // expected-error {{ambiguous}} > + static_assert(X<int*, void, a>::n == 2); // expected-error {{undefined}} > + > + template<typename T, A<0> a> struct X<T, T, a> { static constexpr int n > = 4; }; > + static_assert(X<float, float, a>::n == 4); > +} > > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits