[clang] e97e985 - [c++20] For P0732R2: permit class template argument deduction for non-type template parameters.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 27 17:49:29 PDT 2020


On Tue, 27 Oct 2020 at 17:08, Nico Weber <thakis at 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 at 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 at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20201027/f40b1e8d/attachment-0001.html>


More information about the cfe-commits mailing list