[clang] ff929a2 - [Sema] Guard transformed loop-hint expression before use (#182752)

via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 24 09:38:14 PST 2026


Author: Tommy Chiang
Date: 2026-02-24T17:38:08Z
New Revision: ff929a21e95cd637ddf6ec9b1036eeaa4ce395d5

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

LOG: [Sema] Guard transformed loop-hint expression before use (#182752)

`TransformLoopHintAttr` called `TransformExpr(...).get()` without
checking that the transformed expression was usable.

For `#pragma GCC unroll v()` instantiated with `v = int`, expression
transformation fails and Clang can assert while validating the loop
hint.

Check `ExprResult::isUsable()` before calling `get()` and keep the
original attribute on failure.

Fixes https://github.com/llvm/llvm-project/issues/49502

Added: 
    

Modified: 
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/test/Sema/unroll-template-value-crash.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 37309d057fbe7..b4d8158525f04 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2166,10 +2166,11 @@ TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) {
 
 const LoopHintAttr *
 TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
-  Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();
-
-  if (TransformedExpr == LH->getValue())
+  ExprResult TransformedExprResult = getDerived().TransformExpr(LH->getValue());
+  if (!TransformedExprResult.isUsable() ||
+      TransformedExprResult.get() == LH->getValue())
     return LH;
+  Expr *TransformedExpr = TransformedExprResult.get();
 
   // Generate error if there is a problem with the value.
   if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation(),

diff  --git a/clang/test/Sema/unroll-template-value-crash.cpp b/clang/test/Sema/unroll-template-value-crash.cpp
index cda4b897509b9..05c81959b52f2 100644
--- a/clang/test/Sema/unroll-template-value-crash.cpp
+++ b/clang/test/Sema/unroll-template-value-crash.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -x c++ -verify %s
-// expected-no-diagnostics
 
 template <int Unroll> void foo() {
   #pragma unroll Unroll
@@ -33,3 +32,40 @@ void use(T t) {
 void test() {
   use(val());
 }
+
+template <typename T> void pr49502(T v) {
+#pragma GCC unroll v() // expected-error {{called object type 'int' is not a function or function pointer}}
+  for (;;) {
+  }
+}
+
+void pr49502_caller() {
+  pr49502(0); // expected-note {{in instantiation of function template specialization 'pr49502<int>' requested here}}
+}
+
+template <typename T, typename U> struct pr49502_partial;
+
+template <typename T> struct pr49502_partial<T, T> {
+  static void dependent(T v) {
+#pragma GCC unroll v() // expected-error {{called object type 'int' is not a function or function pointer}}
+    for (;;) {
+    }
+  }
+
+  static void mixed(T v) {
+#pragma GCC unroll v() + 1 // expected-error {{called object type 'int' is not a function or function pointer}}
+    for (;;) {
+    }
+  }
+
+  static void non_dependent(int v) {
+#pragma GCC unroll v() // expected-error {{called object type 'int' is not a function or function pointer}}
+    for (;;) {
+    }
+  }
+};
+
+void pr49502_partial_caller() {
+  pr49502_partial<int, int>::dependent(0); // expected-note {{in instantiation of member function 'pr49502_partial<int, int>::dependent' requested here}}
+  pr49502_partial<int, int>::mixed(0); // expected-note {{in instantiation of member function 'pr49502_partial<int, int>::mixed' requested here}}
+}


        


More information about the cfe-commits mailing list