[clang] [clang] ignore value dependence for decltype (PR #190495)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 4 19:32:17 PDT 2026
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/190495
>From b5967a16be33c63d98724f4a3be486f5507cd93f Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sat, 4 Apr 2026 20:44:35 -0300
Subject: [PATCH] [clang] implement CWG2064: ignore value dependence for
decltype
The 'decltype' for a value-dependent (but non-type-dependent) should be known,
so this patch makes them non-opaque instead.
Readds a few test cases from da98651
Fixes #61818
---
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/AST/DependenceFlags.h | 2 +-
clang/lib/AST/ASTContext.cpp | 9 +++---
clang/lib/AST/ItaniumMangle.cpp | 15 +++++++---
clang/lib/AST/Type.cpp | 22 +++++++-------
clang/test/CXX/drs/cwg20xx.cpp | 17 +++++++++--
.../test/CXX/temp/temp.decls/temp.mem/p5.cpp | 2 +-
clang/test/CodeGenCXX/GH190495.cpp | 29 +++++++++++++++++++
clang/test/CodeGenCXX/mangle-subst.cpp | 13 ++++++++-
clang/test/Sema/invalid-bitwidth-expr.mm | 1 +
clang/test/SemaCXX/decltype.cpp | 15 +++++++++-
clang/test/SemaCXX/source_location.cpp | 7 ++++-
clang/test/SemaCXX/typeof.cpp | 2 +-
.../SemaTemplate/concepts-out-of-line-def.cpp | 6 ++--
clang/test/SemaTemplate/concepts.cpp | 9 ++++++
clang/test/SemaTemplate/deduction-guide.cpp | 23 +++++++--------
clang/test/SemaTemplate/dependent-expr.cpp | 8 ++---
.../SemaTemplate/temp_arg_template_p0522.cpp | 11 ++++++-
18 files changed, 145 insertions(+), 47 deletions(-)
create mode 100644 clang/test/CodeGenCXX/GH190495.cpp
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..e1e1b158c9aa1 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.
@@ -7005,8 +7010,9 @@ static bool hasMangledSubstitutionQualifiers(QualType T) {
bool CXXNameMangler::mangleSubstitution(QualType T) {
if (!hasMangledSubstitutionQualifiers(T)) {
- if (const auto *RD = T->getAsCXXRecordDecl())
- return mangleSubstitution(RD);
+ if (const auto *TT = dyn_cast<TagType>(T);
+ TT && (isa<RecordType>(TT) || isa<InjectedClassNameType>(TT)))
+ return mangleSubstitution(TT->getDecl());
}
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
@@ -7175,8 +7181,9 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
void CXXNameMangler::addSubstitution(QualType T) {
if (!hasMangledSubstitutionQualifiers(T)) {
- if (const auto *RD = T->getAsCXXRecordDecl()) {
- addSubstitution(RD);
+ if (const auto *TT = dyn_cast<TagType>(T);
+ TT && (isa<RecordType>(TT) || isa<InjectedClassNameType>(TT))) {
+ addSubstitution(TT->getDecl());
return;
}
}
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/drs/cwg20xx.cpp b/clang/test/CXX/drs/cwg20xx.cpp
index 75b4094283db0..f669d460f4d09 100644
--- a/clang/test/CXX/drs/cwg20xx.cpp
+++ b/clang/test/CXX/drs/cwg20xx.cpp
@@ -64,6 +64,19 @@ namespace cwg2061 { // cwg2061: 2.7
#endif // C++11
} // namespace cwg2061
+namespace cwg2064 { // cwg2064: 23
+#if __cplusplus >= 201103L
+ template<typename T> struct X {
+ template<typename U> struct Y {};
+ };
+ template<typename T> void g() {
+ X<decltype(sizeof(T))>::Y<int> y; // ok
+ return X<decltype(sizeof(T))>::f();
+ // expected-error at -1 {{no member named 'f' in 'cwg2064::X<unsigned long>'}}
+ }
+#endif
+}
+
namespace cwg2076 { // cwg2076: 13
#if __cplusplus >= 201103L
namespace std_example {
@@ -86,7 +99,7 @@ namespace cwg2076 { // cwg2076: 13
operator string_view() const;
};
- void foo(const string &); // #cwg2076-foo
+ void foo(const string &); // #cwg2076-foo
void bar(string_view); // #cwg2076-bar
void func(const string &arg) {
@@ -369,7 +382,7 @@ int f()
return 0;
}
} // namespace GH42233
-} // namespace cwg2091
+} // namespace cwg2091
namespace cwg2094 { // cwg2094: 5
struct A { int n; };
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/CodeGenCXX/GH190495.cpp b/clang/test/CodeGenCXX/GH190495.cpp
new file mode 100644
index 0000000000000..87984f8c34ac1
--- /dev/null
+++ b/clang/test/CodeGenCXX/GH190495.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++26 -emit-llvm %s -o - -triple=x86_64-apple-darwin9
+
+namespace std {
+class partial_ordering {};
+class strong_ordering {
+public:
+ operator partial_ordering();
+};
+using size_t = decltype(sizeof(int));
+template <size_t> struct __priority_tag {};
+namespace __partial_order {
+struct __fn {
+ template <class _Tp, class _Up>
+ constexpr auto __go(_Tp __t, _Up __u, __priority_tag<2>)
+ -> decltype(partial_ordering(partial_order(__t, __u))) {}
+ template <class _Tp, class _Up> auto operator()(_Tp __t, _Up __u) {
+ __go(__t, __u, __priority_tag<2>());
+ }
+};
+}
+auto partial_order = __partial_order::__fn{};
+namespace {
+struct A {};
+strong_ordering partial_order(A, A) {
+ A a;
+ std::partial_order(a, a);
+}
+}
+}
diff --git a/clang/test/CodeGenCXX/mangle-subst.cpp b/clang/test/CodeGenCXX/mangle-subst.cpp
index 524e0febe479a..67fe94177ecb4 100644
--- a/clang/test/CodeGenCXX/mangle-subst.cpp
+++ b/clang/test/CodeGenCXX/mangle-subst.cpp
@@ -69,7 +69,7 @@ namespace NS {
namespace NS {
// CHECK: @_ZN2NS1fERNS_1CE
- void f(C&) { }
+ void f(C&) { }
}
namespace Test1 {
@@ -123,3 +123,14 @@ struct Inst : public A::Impl<A::Wrap> {};
void Test() { Inst a; }
}
+
+namespace InstantiationDependentDecltype1 {
+ 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); }
+}
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 at -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..a41c8f6437452 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,19 @@ void test() { (void)C::XBitMask<0>; }
}
#endif
+namespace value_dependent {
+ template<int V> void f() {
+ decltype(V) x = nullptr;
+ // expected-error at -1 {{cannot initialize a variable of type 'decltype(V)' (aka 'int') with an rvalue of type 'std::nullptr_t'}}
+ }
+
+ // FIXME: Should be different overloads
+ template<typename T> decltype(int(T())) f() {}
+ // expected-note at -1 {{previous definition is here}}
+ template<typename T> decltype(int(T(0))) f() {}
+ // expected-error at -1 {{redefinition of 'f'}}
+} // 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 at -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 at -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 at -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..1d97deeb9214a 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -135,8 +135,17 @@ namespace Auto {
int n;
template<auto A, decltype(A) B = &n> struct SubstFailure;
- TInt<SubstFailure> isf; // FIXME: this should be ill-formed
+ // expected-error at -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 at -1 {{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
}
namespace GH62529 {
More information about the cfe-commits
mailing list