https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/190495
>From 156f911690650d4864b783e04a74071525c49e8d Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <[email protected]> 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..54f0993f80186 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); + isa_and_nonnull<RecordType, 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); + isa_and_nonnull<RecordType, 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@-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..fa59ca2dfb3d0 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 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); } +} 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..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@-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@-1 {{previous definition is here}} + template<typename T> decltype(int(T(0))) f() {} + // expected-error@-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@-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..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@-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; + + 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 { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
