[clang] ca844ab - Fix template instantiation of UDLs

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 28 11:47:02 PDT 2022


Author: Aaron Ballman
Date: 2022-03-28T14:46:53-04:00
New Revision: ca844ab01c3f9410ceca967c09f809400950beae

URL: https://github.com/llvm/llvm-project/commit/ca844ab01c3f9410ceca967c09f809400950beae
DIFF: https://github.com/llvm/llvm-project/commit/ca844ab01c3f9410ceca967c09f809400950beae.diff

LOG: 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.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/TreeTransform.h
    clang/test/CodeGenCXX/cxx20-consteval-crash.cpp
    clang/test/SemaCXX/cxx2a-consteval.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3f37dfe6027a4..951dd68bf15bf 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -189,6 +189,9 @@ C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 - Diagnose consteval and constexpr issues that happen at namespace scope. This
   partially addresses `Issue 51593 <https://github.com/llvm/llvm-project/issues/51593>`_.
+- No longer attempt to evaluate a consteval UDL function call at runtime when
+  it is called through a template instantiation. This fixes
+  `Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
 
 C++2b Feature Support
 ^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 4b9b48293b629..e27ac97cf2177 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -10513,9 +10513,7 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) {
-  if (FunctionDecl *FD = E->getDirectCallee())
-    SemaRef.MarkFunctionReferenced(E->getBeginLoc(), FD);
-  return SemaRef.MaybeBindToTemporary(E);
+  return getDerived().TransformCallExpr(E);
 }
 
 template<typename Derived>

diff  --git a/clang/test/CodeGenCXX/cxx20-consteval-crash.cpp b/clang/test/CodeGenCXX/cxx20-consteval-crash.cpp
index 19f02c4cf41d0..d37505b769bbc 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<unsigned char>(n);
+}
+
+inline constexpr char f1(const auto octet) {
+  return 4_UC;
+}
+
+template <typename Ty>
+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 275e5df766fa3..6b6f8d22cdb89 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -721,3 +721,27 @@ T<int> t; // expected-error {{call to consteval function 'NamespaceScopeConsteva
              expected-note {{subobject of type 'int' is not initialized}}
 
 } // namespace NamespaceScopeConsteval
+
+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<unsigned char>(n);
+}
+
+inline constexpr char f1(const auto octet) {
+  return 4_UC;
+}
+
+template <typename Ty>
+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);
+}
+}


        


More information about the cfe-commits mailing list