Skip to content

Commit ca844ab

Browse files
committed
Fix template instantiation of UDLs
Previously, we would instantiate the UDL by marking the function as referenced and potentially binding to a temporary; this skipped transforming the call when the UDL was dependent on a template parameter. Now, we defer all the work to instantiating the call expression for the UDL. This ensures that constant evaluation occurs at compile time rather than deferring until runtime. Fixes Issue 54578.
1 parent 44a14a6 commit ca844ab

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ C++20 Feature Support
189189
^^^^^^^^^^^^^^^^^^^^^
190190
- Diagnose consteval and constexpr issues that happen at namespace scope. This
191191
partially addresses `Issue 51593 <https://github.com/llvm/llvm-project/issues/51593>`_.
192+
- No longer attempt to evaluate a consteval UDL function call at runtime when
193+
it is called through a template instantiation. This fixes
194+
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
192195

193196
C++2b Feature Support
194197
^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/TreeTransform.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10513,9 +10513,7 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
1051310513
template<typename Derived>
1051410514
ExprResult
1051510515
TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) {
10516-
if (FunctionDecl *FD = E->getDirectCallee())
10517-
SemaRef.MarkFunctionReferenced(E->getBeginLoc(), FD);
10518-
return SemaRef.MaybeBindToTemporary(E);
10516+
return getDerived().TransformCallExpr(E);
1051910517
}
1052010518

1052110519
template<typename Derived>

clang/test/CodeGenCXX/cxx20-consteval-crash.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,35 @@ void f() { g(); }
2424
// CHECK: ret void
2525
// CHECK: }
2626
}
27+
28+
namespace Issue54578 {
29+
inline consteval unsigned char operator""_UC(const unsigned long long n) {
30+
return static_cast<unsigned char>(n);
31+
}
32+
33+
inline constexpr char f1(const auto octet) {
34+
return 4_UC;
35+
}
36+
37+
template <typename Ty>
38+
inline constexpr char f2(const Ty octet) {
39+
return 4_UC;
40+
}
41+
42+
int foo() {
43+
return f1('a') + f2('a');
44+
}
45+
46+
// Because the consteval functions are inline (implicitly as well as
47+
// explicitly), we need to defer the CHECK lines until this point to get the
48+
// order correct. We want to ensure there is no definition of the consteval
49+
// UDL function, and that the constexpr f1 and f2 functions both return a
50+
// constant value.
51+
52+
// CHECK-NOT: define{{.*}} zeroext i8 @_ZN10Issue54578li3_UCEy
53+
// CHECK: define{{.*}} i32 @_ZN10Issue545783fooEv(
54+
// CHECK: define{{.*}} signext i8 @_ZN10Issue545782f1IcEEcT_(
55+
// CHECK: ret i8 4
56+
// CHECK: define{{.*}} signext i8 @_ZN10Issue545782f2IcEEcT_(
57+
// CHECK: ret i8 4
58+
}

clang/test/SemaCXX/cxx2a-consteval.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,27 @@ T<int> t; // expected-error {{call to consteval function 'NamespaceScopeConsteva
721721
expected-note {{subobject of type 'int' is not initialized}}
722722

723723
} // namespace NamespaceScopeConsteval
724+
725+
namespace Issue54578 {
726+
// We expect the user-defined literal to be resovled entirely at compile time
727+
// despite being instantiated through a template.
728+
inline consteval unsigned char operator""_UC(const unsigned long long n) {
729+
return static_cast<unsigned char>(n);
730+
}
731+
732+
inline constexpr char f1(const auto octet) {
733+
return 4_UC;
734+
}
735+
736+
template <typename Ty>
737+
inline constexpr char f2(const Ty octet) {
738+
return 4_UC;
739+
}
740+
741+
void test() {
742+
static_assert(f1('a') == 4);
743+
static_assert(f2('a') == 4);
744+
constexpr int c = f1('a') + f2('a');
745+
static_assert(c == 8);
746+
}
747+
}

0 commit comments

Comments
 (0)