On Tue, 27 Oct 2020 at 17:08, Nico Weber <tha...@chromium.org> wrote:
> 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? > The latter. Done in af2f5f99bd144ae2f70e21d53b23fc18a3d9d7d0. > 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