llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

<details>
<summary>Changes</summary>

The 'decltype' for a value-dependent but non-type-dependent expression should 
be known, so this patch makes them non-opaque instead in that case.

Fixes #<!-- -->61818

---
Full diff: https://github.com/llvm/llvm-project/pull/190495.diff


15 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/include/clang/AST/DependenceFlags.h (+1-1) 
- (modified) clang/lib/AST/ASTContext.cpp (+4-5) 
- (modified) clang/lib/AST/ItaniumMangle.cpp (+5) 
- (modified) clang/lib/AST/Type.cpp (+12-10) 
- (modified) clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp (+1-1) 
- (modified) clang/test/Sema/invalid-bitwidth-expr.mm (+1) 
- (modified) clang/test/SemaCXX/decltype.cpp (+8-1) 
- (modified) clang/test/SemaCXX/source_location.cpp (+6-1) 
- (modified) clang/test/SemaCXX/typeof.cpp (+1-1) 
- (modified) clang/test/SemaTemplate/concepts-out-of-line-def.cpp (+3-3) 
- (modified) clang/test/SemaTemplate/concepts.cpp (+9) 
- (modified) clang/test/SemaTemplate/deduction-guide.cpp (+11-12) 
- (modified) clang/test/SemaTemplate/dependent-expr.cpp (+4-4) 
- (modified) clang/test/SemaTemplate/temp_arg_template_p0522.cpp (+4-1) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2fe76e60946f5..10996aefcd59b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -423,6 +423,7 @@ Bug Fixes to C++ Support
 - Fixed a crash when pack expansions are used as arguments for non-pack 
parameters of built-in templates. (#GH180307)
 - Fixed a bug where captured variables in non-mutable lambdas were incorrectly 
treated as mutable 
   when used inside decltype in the return type. (#GH180460)
+- `decltype(expr)` now ignores value-dependence on the expression. (#GH61818)
 - Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type 
vectors in ``constexpr``. (#GH180044)
 - Fixed a crash when `explicit(bool)` is used with an incomplete enumeration. 
(#GH183887)
 - Fixed a crash on ``typeid`` of incomplete local types during template 
instantiation. (#GH63242), (#GH176397)
diff --git a/clang/include/clang/AST/DependenceFlags.h 
b/clang/include/clang/AST/DependenceFlags.h
index c4395259f0758..2f003af925d79 100644
--- a/clang/include/clang/AST/DependenceFlags.h
+++ b/clang/include/clang/AST/DependenceFlags.h
@@ -194,7 +194,7 @@ class Dependence {
   TypeDependence type() const {
     return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) |
            translate(V, Instantiation, TypeDependence::Instantiation) |
-           translate(V, Dependent, TypeDependence::Dependent) |
+           translate(V, Type, TypeDependence::Dependent) |
            translate(V, Error, TypeDependence::Error) |
            translate(V, VariablyModified, TypeDependence::VariablyModified);
   }
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ee7f823b014b2..36978548ca171 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6691,12 +6691,11 @@ QualType ASTContext::getReferenceQualifiedType(const 
Expr *E) const {
 /// expression, and would not give a significant memory saving, since there
 /// is an Expr tree under each such type.
 QualType ASTContext::getDecltypeType(Expr *E, QualType UnderlyingType) const {
-  // 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).
+  // C++26 [temp.type]p4: 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 ([temp.over.link]).
   QualType CanonType;
-  if (!E->isInstantiationDependent()) {
+  if (!E->isTypeDependent()) {
     CanonType = getCanonicalType(UnderlyingType);
   } else if (!UnderlyingType.isNull()) {
     CanonType = getDecltypeType(E, QualType());
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index d21faaa87558d..46e8b75633d54 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3008,6 +3008,11 @@ void CXXNameMangler::mangleType(QualType T) {
         if (!TST->isTypeAlias())
           break;
 
+      // instantiation-dependent decltypes are mangled through their
+      // expressions.
+      if (T->isInstantiationDependentType() && isa<DecltypeType>(T))
+        break;
+
       // FIXME: We presumably shouldn't strip off ElaboratedTypes with
       // instantation-dependent qualifiers. See
       // https://github.com/itanium-cxx-abi/cxx-abi/issues/114.
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 78983fd38410d..b8362f25ec5d2 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -428,9 +428,16 @@ BitIntType::BitIntType(bool IsUnsigned, unsigned NumBits)
       NumBits(NumBits) {}
 
 DependentBitIntType::DependentBitIntType(bool IsUnsigned, Expr *NumBitsExpr)
+    // DependentBitIntType must always be type-dependent.
+    // The expression must be value-dependent, so will also be
+    // instantiation-dependent.
     : Type(DependentBitInt, QualType{},
-           toTypeDependence(NumBitsExpr->getDependence())),
-      ExprAndUnsigned(NumBitsExpr, IsUnsigned) {}
+           toTypeDependence(NumBitsExpr->getDependence()) |
+               TypeDependence::Dependent),
+      ExprAndUnsigned(NumBitsExpr, IsUnsigned) {
+  assert(NumBitsExpr->isValueDependent() &&
+         "NumBitsExpr must be value-dependent");
+}
 
 bool DependentBitIntType::isUnsigned() const {
   return ExprAndUnsigned.getInt();
@@ -4219,15 +4226,10 @@ 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)),
-      E(E), UnderlyingType(underlyingType) {}
+    : Type(Decltype, can, toTypeDependence(E->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())
diff --git a/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp 
b/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp
index 65d8345ecc3aa..a0c9e931c3298 100644
--- a/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.mem/p5.cpp
@@ -92,7 +92,7 @@ template X0::operator B<0>() const; // expected-error 
{{undefined function templ
 // index expression as non-canonical is extra bad.
 template X0::operator C<int[1]>() const; // expected-error {{undefined 
function template 'operator C<type-parameter-0-0[V]>'}}
 #if __cplusplus >= 201103L
-template X0::operator D<int, 0>() const; // expected-error {{undefined 
function template 'operator D<decltype(value-parameter-0-0), 
value-parameter-0-0>'}}
+template X0::operator D<int, 0>() const; // expected-error {{undefined 
function template 'operator D<int, value-parameter-0-0>'}}
 #endif
 
 void test_X0(X0 x0, const X0 &x0c) {
diff --git a/clang/test/Sema/invalid-bitwidth-expr.mm 
b/clang/test/Sema/invalid-bitwidth-expr.mm
index 9e577300eb1c8..25930e5d4ef7e 100644
--- a/clang/test/Sema/invalid-bitwidth-expr.mm
+++ b/clang/test/Sema/invalid-bitwidth-expr.mm
@@ -26,6 +26,7 @@ auto func() {
 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 {
diff --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp
index 45a4c4cf1ac86..78bcbbe6b6489 100644
--- a/clang/test/SemaCXX/decltype.cpp
+++ b/clang/test/SemaCXX/decltype.cpp
@@ -135,7 +135,7 @@ namespace GH97646 {
   template<bool B>
   void f() {
     decltype(B) x = false;
-    !x;
+    !x; // expected-warning {{expression result unused}}
   }
 }
 
@@ -241,6 +241,13 @@ void test() { (void)C::XBitMask<0>; }
 }
 #endif
 
+namespace value_dependent {
+  template<int V> void f() {
+    decltype(V) x = nullptr;
+    // expected-error@-1 {{cannot initialize a variable of type 'decltype(V)' 
(aka 'int') with an rvalue of type 'std::nullptr_t'}}
+  }
+} // namespace value_dependent
+
 template<typename>
 class conditional {
 };
diff --git a/clang/test/SemaCXX/source_location.cpp 
b/clang/test/SemaCXX/source_location.cpp
index eaa6cb04c5d1c..13846553421ce 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -9,7 +9,9 @@
 // RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT 
-fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
 // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS 
-fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP 
-fms-compatibility -verify %s
 // RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS 
-DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter 
-DNEW_INTERP -verify -fms-compatibility %s
+#ifndef MS
 // expected-no-diagnostics
+#endif
 
 #define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
 #define CURRENT_FROM_MACRO() SL::current()
@@ -1088,6 +1090,9 @@ namespace GH178324 {
     using e = int;
   };
   void current(const char * = __builtin_FUNCSIG());
-  template <class> void c() { decltype(a(current()))::e; }
+  template <class> void c() {
+    decltype(a(current()))::e;
+    // expected-warning@-1 {{declaration does not declare anything}}
+  }
 } // namespace GH178324
 #endif
diff --git a/clang/test/SemaCXX/typeof.cpp b/clang/test/SemaCXX/typeof.cpp
index 421cfc59f5311..e6d3dbccf7321 100644
--- a/clang/test/SemaCXX/typeof.cpp
+++ b/clang/test/SemaCXX/typeof.cpp
@@ -8,6 +8,6 @@ namespace GH97646 {
   template<bool B>
   void f() {
     __typeof__(B) x = false;
-    !x;
+    !x; // expected-warning {{expression result unused}}
   }
 }
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp 
b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 9811b18f4301b..0939a2a7fbb5f 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -533,12 +533,12 @@ template <class T>
 void X<T>::foo() requires requires { requires is_not_same_v<T, int>; } {} // ok
 
 template <class T>
-void X<T>::bar(decltype(requires { requires something_interesting<T>; })) {}
-// expected-error@-1{{definition of 'bar' does not match any declaration}}
-// expected-note@#defined-here{{defined here}}
+void X<T>::bar(decltype(requires { requires something_interesting<T>; })) {} 
// #GH74314-bar-prev-def-here
 
 template <class T>
 void X<T>::bar(decltype(requires { requires is_not_same_v<T, int>; })) {}
+// expected-error@-1 {{redefinition of 'bar'}}
+// expected-note@#GH74314-bar-prev-def-here {{previous definition is here}}
 } // namespace GH74314
 
 namespace GH56482 {
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index 429df756c1c4f..4e89c814e20b1 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1824,3 +1824,12 @@ namespace GH176402 {
     recursiveLambda(recursiveLambda, 5);
   }
 }
+
+namespace GH61818 {
+  template <typename T> concept C = true;
+  template <typename T> struct A;
+  template <> struct A<bool> { using type = bool; };
+
+  template <typename T>
+  void f(A<decltype(C<T>)>::type); // OK, no 'typename' needed
+} // namespace GH61818
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp 
b/clang/test/SemaTemplate/deduction-guide.cpp
index 9e5756ffec3fc..29693e1918263 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -854,17 +854,17 @@ CC c{};
 
 // CHECK-LABEL: Dumping GH133132::<deduction guide for CC>:
 // CHECK-NEXT:  FunctionTemplateDecl {{.+}} implicit <deduction guide for CC>
-// CHECK-NEXT:  |-NonTypeTemplateParmDecl {{.+}} 'int' depth 0 index 0 N
-// CHECK-NEXT:  | `-TemplateArgument {{.+}} expr '42'
-// CHECK-NEXT:  |   `-IntegerLiteral {{.+}} 'int' 42
-// CHECK-NEXT:  |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
-// CHECK-NEXT:  | `-TemplateArgument type 'A<decltype(N)>'
-// CHECK-NEXT:  |   `-TemplateSpecializationType {{.+}} 'A<decltype(N)>' 
dependent
+// CHECK-NEXT:  |-TemplateTypeParmDecl {{.+}} class depth 0 index 0 U
+// CHECK-NEXT:  | `-TemplateArgument type 'A<decltype(N)>':'GH133132::A<int>'
+// CHECK-NEXT:  |   `-TemplateSpecializationType {{.+}} 'A<decltype(N)>' sugar 
instantiation_dependent
 // CHECK-NEXT:  |     |-name: 'A':'GH133132::A' qualified
 // CHECK-NEXT:  |     | `-ClassTemplateDecl {{.+}} A
-// CHECK-NEXT:  |     `-TemplateArgument type 'decltype(N)'
-// CHECK-NEXT:  |       `-DecltypeType {{.+}} 'decltype(N)' dependent
-// CHECK-NEXT:  |         `-DeclRefExpr {{.+}} 'int' NonTypeTemplateParm 
{{.+}} 'N' 'int'
+// CHECK-NEXT:  |     |-TemplateArgument type 'decltype(N)':'int'
+// CHECK-NEXT:  |     | `-DecltypeType {{.+}} 'decltype(N)' sugar 
instantiation_dependent
+// CHECK-NEXT:  |     |   |-DeclRefExpr {{.+}} 'int' NonTypeTemplateParm 
{{.+}} 'N' 'int'
+// CHECK-NEXT:  |     |   `-BuiltinType {{.+}} 'int'
+// CHECK-NEXT:  |     `-RecordType {{.+}} 'GH133132::A<int>' canonical
+// CHECK-NEXT:  |       `-ClassTemplateSpecialization {{.+}} 'A'
 // CHECK-NEXT:  |-TypeTraitExpr {{.+}} 'bool' __is_deducible
 // CHECK-NEXT:  | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::CC' 
dependent
 // CHECK-NEXT:  | | `-name: 'GH133132::CC'
@@ -872,14 +872,13 @@ CC c{};
 // CHECK-NEXT:  | `-TemplateSpecializationType {{.+}} 'GH133132::A<U>' 
dependent
 // CHECK-NEXT:  |   |-name: 'GH133132::A'
 // CHECK-NEXT:  |   | `-ClassTemplateDecl {{.+}} A
-// CHECK-NEXT:  |   `-TemplateArgument type 'U':'type-parameter-0-1'
+// CHECK-NEXT:  |   `-TemplateArgument type 'U':'type-parameter-0-0'
 // CHECK-NEXT:  |     `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent 
class depth 0 index 0 _Ty
 // CHECK-NEXT:  |       |-FunctionTemplate {{.+}} '<deduction guide for A>'
-// CHECK-NEXT:  |       `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 
index 1
+// CHECK-NEXT:  |       `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 
index 0
 // CHECK-NEXT:  |         `-TemplateTypeParm {{.+}} 'U'
 // CHECK-NEXT:  |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for 
CC> 'auto () -> GH133132::A<U>'
 // CHECK-NEXT:  `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide 
for CC> 'auto () -> GH133132::A<GH133132::A<int>>' implicit_instantiation
-// CHECK-NEXT:    |-TemplateArgument integral '42'
 // CHECK-NEXT:    `-TemplateArgument type 'GH133132::A<int>'
 // CHECK-NEXT:      `-RecordType {{.+}} 'GH133132::A<int>'
 // CHECK-NEXT:        `-ClassTemplateSpecialization {{.+}} 'A'
diff --git a/clang/test/SemaTemplate/dependent-expr.cpp 
b/clang/test/SemaTemplate/dependent-expr.cpp
index ce210d9b74f6d..31ee43ab9501c 100644
--- a/clang/test/SemaTemplate/dependent-expr.cpp
+++ b/clang/test/SemaTemplate/dependent-expr.cpp
@@ -13,12 +13,12 @@ namespace PR6045 {
     static const unsigned int member = r;
     void f();
   };
-  
+
   template<unsigned int r>
   const unsigned int A<r>::member;
-  
+
   template<unsigned int r>
-  void A<r>::f() 
+  void A<r>::f()
   {
     unsigned k;
     (void)(k % member);
@@ -129,7 +129,7 @@ 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> auto g() {
     auto c = [](auto, int) -> decltype(({})) {};
diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp 
b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index bde811c3bf685..73b2be2c72f11 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -135,7 +135,10 @@ namespace Auto {
 
   int n;
   template<auto A, decltype(A) B = &n> struct SubstFailure;
-  TInt<SubstFailure> isf; // FIXME: this should be ill-formed
+  // expected-error@-1 {{value of type 'int *' is not implicitly convertible 
to 'decltype(value-parameter-0-0)' (aka 'int')}}
+  // expected-note@#TInt {{while checking a default template argument used 
here}}
+  TInt<SubstFailure> isf;
+  // expected-note@-1 {{template template argument has different template 
parameters than its corresponding template template parameter}}
   TIntPtr<SubstFailure> ipsf;
 }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/190495
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to