[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