DR2064: decltype(E) is only a dependent type if E is type-dependent, not
authorRichard Smith <richard@metafoo.co.uk>
Thu, 17 Dec 2020 22:36:26 +0000 (14:36 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Tue, 19 Jan 2021 05:05:01 +0000 (21:05 -0800)
if E is merely instantiation-dependent.

Previously reverted in 34e72a146111dd986889a0f0ec8767b2ca6b2913;
re-committed with a fix to an issue that caused name mangling to assert.

clang/include/clang/AST/DependenceFlags.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/Type.cpp
clang/test/CXX/drs/dr20xx.cpp
clang/test/CodeGenCXX/mangle-subst.cpp
clang/test/Sema/invalid-bitwidth-expr.mm
clang/test/SemaCXX/invalid-template-base-specifier.cpp
clang/test/SemaTemplate/dependent-expr.cpp
clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp
clang/www/cxx_dr_status.html

index ca96b65..8c47047 100644 (file)
@@ -255,6 +255,12 @@ inline TypeDependence toTypeDependence(TemplateNameDependence D) {
 inline TypeDependence toTypeDependence(TemplateArgumentDependence D) {
   return Dependence(D).type();
 }
+/// Compute the dependence of a type that depends on the type of an expression,
+/// given the dependence of that expression and of its type.
+inline TypeDependence typeToTypeDependence(ExprDependence ED, TypeDependence TD) {
+  return Dependence(ED & ~ExprDependence::Value).type() |
+         (TD & TypeDependence::VariablyModified);
+}
 
 inline NestedNameSpecifierDependence
 toNestedNameSpecifierDependendence(TypeDependence D) {
index 44545f0..0190573 100644 (file)
@@ -5383,10 +5383,10 @@ QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
   DecltypeType *dt;
 
   // C++11 [temp.type]p2:
-  //   If an expression e involves a template parameter, decltype(e) denotes a
-  //   unique dependent type. Two such decltype-specifiers refer to the same
-  //   type only if their expressions are equivalent (14.5.6.1).
-  if (e->isInstantiationDependent()) {
+  //   If an expression e is type-dependent, decltype(e) denotes a unique
+  //   dependent type. Two such decltype-specifiers refer to the same type only
+  //   if their expressions are equivalent (14.5.6.1).
+  if (e->isTypeDependent()) {
     llvm::FoldingSetNodeID ID;
     DependentDecltypeType::Profile(ID, *this, e);
 
index 73c8f17..1f8c11f 100644 (file)
@@ -2578,6 +2578,11 @@ void CXXNameMangler::mangleType(QualType T) {
         if (!TST->isTypeAlias())
           break;
 
+      // Don't desugar instantiation-dependent decltype / typeof types. We need
+      // to mangle the expression as written.
+      if (isa<DecltypeType, TypeOfType>(T))
+        break;
+
       QualType Desugared
         = T.getSingleStepDesugaredType(Context.getASTContext());
       if (Desugared == T)
@@ -5568,12 +5573,11 @@ static bool hasMangledSubstitutionQualifiers(QualType T) {
 
 bool CXXNameMangler::mangleSubstitution(QualType T) {
   if (!hasMangledSubstitutionQualifiers(T)) {
-    if (const RecordType *RT = T->getAs<RecordType>())
+    if (const RecordType *RT = dyn_cast<RecordType>(T))
       return mangleSubstitution(RT->getDecl());
   }
 
   uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
-
   return mangleSubstitution(TypePtr);
 }
 
@@ -5732,7 +5736,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
 
 void CXXNameMangler::addSubstitution(QualType T) {
   if (!hasMangledSubstitutionQualifiers(T)) {
-    if (const RecordType *RT = T->getAs<RecordType>()) {
+    if (const RecordType *RT = dyn_cast<RecordType>(T)) {
       addSubstitution(RT->getDecl());
       return;
     }
index 034e175..5dec80b 100644 (file)
@@ -125,8 +125,7 @@ ArrayType::ArrayType(TypeClass tc, QualType et, QualType can,
     //   template<int ...N> int arr[] = {N...};
     : Type(tc, can,
            et->getDependence() |
-               (sz ? toTypeDependence(
-                         turnValueToTypeDependence(sz->getDependence()))
+               (sz ? toTypeDependence(sz->getDependence())
                    : TypeDependence::None) |
                (tc == VariableArray ? TypeDependence::VariablyModified
                                     : TypeDependence::None) |
@@ -3396,9 +3395,8 @@ QualType MacroQualifiedType::getModifiedType() const {
 
 TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
     : Type(TypeOfExpr, can,
-           toTypeDependence(E->getDependence()) |
-               (E->getType()->getDependence() &
-                TypeDependence::VariablyModified)),
+           typeToTypeDependence(E->getDependence(),
+                                E->getType()->getDependence())),
       TOExpr(E) {}
 
 bool TypeOfExprType::isSugared() const {
@@ -3418,18 +3416,12 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
 }
 
 DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
-    // C++11 [temp.type]p2: "If an expression e involves a template parameter,
-    // decltype(e) denotes a unique dependent type." Hence a decltype type is
-    // type-dependent even if its expression is only instantiation-dependent.
     : Type(Decltype, can,
-           toTypeDependence(E->getDependence()) |
-               (E->isInstantiationDependent() ? TypeDependence::Dependent
-                                              : TypeDependence::None) |
-               (E->getType()->getDependence() &
-                TypeDependence::VariablyModified)),
+           typeToTypeDependence(E->getDependence(),
+                                E->getType()->getDependence())),
       E(E), UnderlyingType(underlyingType) {}
 
-bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); }
+bool DecltypeType::isSugared() const { return !E->isTypeDependent(); }
 
 QualType DecltypeType::desugar() const {
   if (isSugared())
index 56cc116..6e1c050 100644 (file)
@@ -49,6 +49,18 @@ namespace dr2026 { // dr2026: 11
   }
 }
 
+namespace dr2064 { // dr2064: 12
+#if __cplusplus >= 201103L
+  template<typename T> struct X {
+    template<typename U> struct Y {};
+  };
+  template<typename T> void f() {
+    X<decltype(sizeof(T))>::Y<int> y; // ok
+    return X<decltype(sizeof(T))>::f(); // expected-error {{no member named 'f' in 'dr2064::X<unsigned}}
+  }
+#endif
+}
+
 namespace dr2082 { // dr2082: 11
   void test1(int x, int = sizeof(x)); // ok
 #if __cplusplus >= 201103L
index 20f33a7..78b1408 100644 (file)
@@ -96,3 +96,14 @@ typename X<T>::template Y<T>::type f(typename X<T>::template Y<T>::type2) { retu
 // CHECK: @_ZN12ManglePrefix1fIiEENS_1XIT_E1YIS2_E4typeENS5_5type2E
 template int f<int>(int);
 }
+
+namespace InstantiationDependentDecltype {
+  struct a { a(char); };
+  struct b { a c(); };
+  // FIXME: This mangling is incorrect; the second decltype type should be a
+  // substitution for the first.
+  // CHECK: @_ZN30InstantiationDependentDecltype1fINS_1bEEEvDTcvNS_1aEcldtcvT__E1cEEDTcvS2_cldtcvS3__E1cEES3_S3_S2_S2_
+  // FIXME: @_ZN30InstantiationDependentDecltype1fINS_1bEEEvDTcvNS_1aEcldtcvT__E1cEES4_S3_S3_S2_S2_
+  template<typename d> void f(decltype(a(d().c())), decltype(a(d().c())), d, d, a, a);
+  void g(a a, b b) { f(a, a, b, b, a, a); }
+}
index 41ca949..8ce498f 100644 (file)
@@ -26,6 +26,7 @@ template <typename T>
 auto func() {
   // error-bit should be propagated from TemplateArgument to NestNameSpecifier.
   class Base<decltype(Foo(T()))>::type C; // expected-error {{no matching function for call to 'Foo'}}
+  // expected-error@-1 {{no class named 'type' in 'Base<bool>'}}
   return C;
 }
 struct Z {
index 7a1a7f8..7760140 100644 (file)
@@ -12,11 +12,11 @@ void test() { Crash<int>(); } // expected-note {{in instantiation of template cl
 template <typename T>
 using Alias = decltype(Foo(T())); // expected-error {{no matching function for call to 'Foo'}}
 template <typename T>
-struct Crash2 : decltype(Alias<T>()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}}
+struct Crash2 : decltype(Alias<T>()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}} expected-error {{base specifier must name a class}}
   Crash2(){};
 };
 
-void test2() { Crash2<int>(); } // expected-note {{in instantiation of template class 'Crash2<int>' requested here}}
+void test2() { Crash2<int>(); } // expected-note 2{{in instantiation of template class 'Crash2<int>' requested here}}
 
 template <typename T>
 class Base {};
index abdb8e9..dace7e2 100644 (file)
@@ -129,7 +129,12 @@ namespace PR45083 {
   template<typename> void f() {
     decltype(({})) x; // expected-error {{incomplete type}}
   }
-  template void f<int>(); // expected-note {{instantiation of}}
+  template void f<int>();
+
+  template<typename T> void f2() {
+    decltype(({T();})) x; // expected-error {{incomplete type}}
+  }
+  template void f2<void>(); // expected-note {{instantiation of}}
 
   template<typename> auto g() {
     auto c = [](auto, int) -> decltype(({})) {};
index 03ef78f..b9a1c93 100644 (file)
@@ -115,6 +115,12 @@ namespace Auto {
 
   int n;
   template<auto A, decltype(A) B = &n> struct SubstFailure;
-  TInt<SubstFailure> isf; // FIXME: this should be ill-formed
+  TInt<SubstFailure> isf; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
   TIntPtr<SubstFailure> ipsf;
+
+  template<template<auto A, auto B, decltype(A)> typename C> struct TAutoAutoFirst {};
+  template<auto A, auto B, decltype(A)> struct AutoAutoFirst;
+  template<auto A, auto B, decltype(B)> struct AutoAutoSecond;
+  TAutoAutoFirst<AutoAutoFirst> aaf;
+  TAutoAutoFirst<AutoAutoSecond> aas; // FIXME: this should be rejected due to parameter mismatch
 }
index f2f711b..f85bc49 100755 (executable)
@@ -12198,7 +12198,7 @@ and <I>POD class</I></td>
     <td><a href="https://wg21.link/cwg2064">2064</a></td>
     <td>CD4</td>
     <td>Conflicting specifications for dependent <I>decltype-specifier</I>s</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 12</td>
   </tr>
   <tr class="open" id="2065">
     <td><a href="https://wg21.link/cwg2065">2065</a></td>