Fix crash and rejects-valid when a later template parameter or default
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 20 Jun 2019 19:49:13 +0000 (19:49 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 20 Jun 2019 19:49:13 +0000 (19:49 +0000)
template argument contains a backreference to a dependently-typed
earlier parameter.

In a case like:
  template<typename T, T A, decltype(A) = A> struct X {};
  template<typename U> auto Y = X<U, 0>();
we previously treated both references to `A` in the third parameter as
being of type `int` when checking the template-id in `Y`. That`s wrong;
the type of `A` in these contexts is the dependent type `U`.

When we encounter a non-type template argument that we can't convert to
the parameter type because of type-dependence, we now insert a dependent
conversion node so that the SubstNonTypeTemplateParmExpr for the
template argument will have the parameter's type rather than whatever
type the argument had.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363972 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ItaniumMangle.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/resolve-single-template-id.cpp
test/SemaTemplate/temp_arg_nontype.cpp

index 031aac0dbee9b5a78f0f1151cd6389a3a13e708f..79be51cd9c8906dc7d4b8f7e424ee799f8532f5d 100644 (file)
@@ -4499,7 +4499,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
     // It's possible to end up with a DeclRefExpr here in certain
     // dependent cases, in which case we should mangle as a
     // declaration.
-    const Expr *E = A.getAsExpr()->IgnoreParens();
+    const Expr *E = A.getAsExpr()->IgnoreParenImpCasts();
     if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
       const ValueDecl *D = DRE->getDecl();
       if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
index d7a05e731ea5b2d74471763aaee188a4f5bd82a8..3941643893af61151fea68299e295eb864d680ea 100644 (file)
@@ -491,6 +491,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
     default:
       llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast "
                        "kind");
+    case CK_Dependent:
     case CK_LValueToRValue:
     case CK_ArrayToPointerDecay:
     case CK_FunctionToPointerDecay:
@@ -499,7 +500,8 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
       break;
     }
   }
-  assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue");
+  assert((VK == VK_RValue || Kind == CK_Dependent || !E->isRValue()) &&
+         "can't cast rvalue to lvalue");
 #endif
 
   diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getBeginLoc());
index 74a891bcb705eaed31b950784b31ee546f671d75..7b0a3a3e094cfba06371ec4a12e3de01edae9f8e 100644 (file)
@@ -4888,10 +4888,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
 
       TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
                                         Converted);
-      NTTPType = SubstType(NTTPType,
-                           MultiLevelTemplateArgumentList(TemplateArgs),
-                           NTTP->getLocation(),
-                           NTTP->getDeclName());
+
+      // If the parameter is a pack expansion, expand this slice of the pack.
+      if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
+                                                           ArgumentPackIndex);
+        NTTPType = SubstType(PET->getPattern(),
+                             MultiLevelTemplateArgumentList(TemplateArgs),
+                             NTTP->getLocation(),
+                             NTTP->getDeclName());
+      } else {
+        NTTPType = SubstType(NTTPType,
+                             MultiLevelTemplateArgumentList(TemplateArgs),
+                             NTTP->getLocation(),
+                             NTTP->getDeclName());
+      }
+
       // If that worked, check the non-type template parameter type
       // for validity.
       if (!NTTPType.isNull())
@@ -6310,9 +6322,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     // When checking a deduced template argument, deduce from its type even if
     // the type is dependent, in order to check the types of non-type template
     // arguments line up properly in partial ordering.
-    Optional<unsigned> Depth;
-    if (CTAK != CTAK_Specified)
-      Depth = Param->getDepth() + 1;
+    Optional<unsigned> Depth = Param->getDepth() + 1;
     if (DeduceAutoType(
             Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
             Arg, ParamType, Depth) == DAR_Failed) {
@@ -6367,9 +6377,24 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
   // If either the parameter has a dependent type or the argument is
   // type-dependent, there's nothing we can check now.
   if (ParamType->isDependentType() || Arg->isTypeDependent()) {
-    // FIXME: Produce a cloned, canonical expression?
-    Converted = TemplateArgument(Arg);
-    return Arg;
+    // Force the argument to the type of the parameter to maintain invariants.
+    auto *PE = dyn_cast<PackExpansionExpr>(Arg);
+    if (PE)
+      Arg = PE->getPattern();
+    ExprResult E = ImpCastExprToType(
+        Arg, ParamType.getNonLValueExprType(Context), CK_Dependent,
+        ParamType->isLValueReferenceType() ? VK_LValue :
+        ParamType->isRValueReferenceType() ? VK_XValue : VK_RValue);
+    if (E.isInvalid())
+      return ExprError();
+    if (PE) {
+      // Recreate a pack expansion if we unwrapped one.
+      E = new (Context)
+          PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(),
+                            PE->getNumExpansions());
+    }
+    Converted = TemplateArgument(E.get());
+    return E;
   }
 
   // The initialization of the parameter from the argument is
index bebca76c4f640198820a1f18cf5ffe539d60b21e..9562845a9a6e762defb90708a6c985e1e89981ff 100644 (file)
@@ -88,3 +88,15 @@ struct rdar9108698 {
 void test_rdar9108698(rdar9108698 x) {
   x.f<int>; // expected-error{{reference to non-static member function must be called}}
 }
+
+namespace GCC_PR67898 {
+  void f(int);
+  void f(float);
+  template<typename T, T F, T G, bool b = F == G> struct X {
+    static_assert(b, "");
+  };
+  template<typename T> void test1() { X<void(T), f, f>(); }
+  template<typename T> void test2() { X<void(*)(T), f, f>(); }
+  template void test1<int>();
+  template void test2<int>();
+}
index 8658fb006060e245d6358d16ea19ec7848af6f85..bdf7663312526a998065b055c13e2c6af9226f4d 100644 (file)
@@ -463,3 +463,22 @@ namespace pointer_to_char_array {
   T foo = "foo";
   void g() { A<&foo>().f(); }
 }
+
+namespace dependent_backreference {
+  struct Incomplete; // expected-note 2{{forward declaration}}
+  Incomplete f(int); // expected-note 2{{here}}
+  int f(short);
+
+  template<typename T, T Value, int(*)[sizeof(f(Value))]> struct X {}; // expected-error 2{{incomplete}}
+  int arr[sizeof(int)];
+  // When checking this template-id, we must not treat 'Value' as having type
+  // 'int'; its type is the dependent type 'T'.
+  template<typename T> void f() { X<T, 0, &arr> x; } // expected-note {{substituting}}
+  void g() { f<short>(); }
+  void h() { f<int>(); } // expected-note {{instantiation}}
+
+  // The second of these is OK to diagnose eagerly because 'Value' has the
+  // non-dependent type 'int'.
+  template<short S> void a() { X<short, S, &arr> x; }
+  template<short S> void b() { X<int, S, &arr> x; } // expected-note {{substituting}}
+}