diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 019a54698b5543..7d18f4793a1507 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -279,6 +279,9 @@ C++20 Feature Support macros and is not affected by these changes. The ```` diagnostic can be disabled by defining the ``_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS`` macro prior to including the header. +- No longer attempt to evaluate a consteval UDL function call at runtime when + it is called through a template instantiation. This fixes + `Issue 54578 `_. C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5c37fcaaea13d9..ad18d27bebe06f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -10460,9 +10460,7 @@ TreeTransform::TransformCharacterLiteral(CharacterLiteral *E) { template ExprResult TreeTransform::TransformUserDefinedLiteral(UserDefinedLiteral *E) { - if (FunctionDecl *FD = E->getDirectCallee()) - SemaRef.MarkFunctionReferenced(E->getBeginLoc(), FD); - return SemaRef.MaybeBindToTemporary(E); + return getDerived().TransformCallExpr(E); } template diff --git a/clang/test/CodeGenCXX/cxx20-consteval-crash.cpp b/clang/test/CodeGenCXX/cxx20-consteval-crash.cpp index 19f02c4cf41d06..d37505b769bbcf 100644 --- a/clang/test/CodeGenCXX/cxx20-consteval-crash.cpp +++ b/clang/test/CodeGenCXX/cxx20-consteval-crash.cpp @@ -24,3 +24,35 @@ void f() { g(); } // CHECK: ret void // CHECK: } } + +namespace Issue54578 { +inline consteval unsigned char operator""_UC(const unsigned long long n) { + return static_cast(n); +} + +inline constexpr char f1(const auto octet) { + return 4_UC; +} + +template +inline constexpr char f2(const Ty octet) { + return 4_UC; +} + +int foo() { + return f1('a') + f2('a'); +} + +// Because the consteval functions are inline (implicitly as well as +// explicitly), we need to defer the CHECK lines until this point to get the +// order correct. We want to ensure there is no definition of the consteval +// UDL function, and that the constexpr f1 and f2 functions both return a +// constant value. + +// CHECK-NOT: define{{.*}} zeroext i8 @_ZN10Issue54578li3_UCEy +// CHECK: define{{.*}} i32 @_ZN10Issue545783fooEv( +// CHECK: define{{.*}} signext i8 @_ZN10Issue545782f1IcEEcT_( +// CHECK: ret i8 4 +// CHECK: define{{.*}} signext i8 @_ZN10Issue545782f2IcEEcT_( +// CHECK: ret i8 4 +} diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index e909f2f3037641..44a0365026800f 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -8,7 +8,7 @@ consteval int f1(int i) { return i; } -consteval constexpr int f2(int i) { +consteval constexpr int f2(int i) { //expected-error@-1 {{cannot combine}} return i; } @@ -195,7 +195,7 @@ auto ptr = ret1(0); struct A { consteval int f(int) { // expected-note@-1+ {{declared here}} - return 0; + return 0; } }; @@ -239,7 +239,7 @@ constexpr int f_c(int i) { int t = f(i); // expected-error@-1 {{is not a constant expression}} // expected-note@-2 {{function parameter}} - return f(0); + return f(0); } consteval int f_eval(int i) { @@ -255,7 +255,7 @@ auto l1 = [](int i) constexpr { int t = f(i); // expected-error@-1 {{is not a constant expression}} // expected-note@-2 {{function parameter}} - return f(0); + return f(0); }; } @@ -663,3 +663,27 @@ struct A { } }; } // PR48235 + +namespace Issue54578 { +// We expect the user-defined literal to be resovled entirely at compile time +// despite being instantiated through a template. +inline consteval unsigned char operator""_UC(const unsigned long long n) { + return static_cast(n); +} + +inline constexpr char f1(const auto octet) { + return 4_UC; +} + +template +inline constexpr char f2(const Ty octet) { + return 4_UC; +} + +void test() { + static_assert(f1('a') == 4); + static_assert(f2('a') == 4); + constexpr int c = f1('a') + f2('a'); + static_assert(c == 8); +} +}