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