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

Nico Weber via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 27 17:07:59 PDT 2020


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 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/6566f753/attachment-0001.html>


More information about the cfe-commits mailing list