[clang] [clang] add no-op __builtin_static_analysis_assume (PR #162939)
Florian Mayer via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 10 16:08:28 PDT 2025
https://github.com/fmayer created https://github.com/llvm/llvm-project/pull/162939
This builtin can be used by user code to communicate with static
analyis tools (e.g. clang-tidy or clang-static-analyzer). Because the
arguments are unevaluated, it is suitable for use in macros, where
evaluating the same expression multiple times can change program
semantics.
RFC: https://discourse.llvm.org/t/rfc-builtin-static-analysis-assume/88544
>From 8c84fe63aac839472e4dff7e5daca03c1cb4ab8f Mon Sep 17 00:00:00 2001
From: Florian Mayer <fmayer at google.com>
Date: Fri, 10 Oct 2025 16:08:14 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
=?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.4
---
clang/include/clang/Basic/Builtins.td | 6 +++++
clang/lib/CodeGen/CGBuiltin.cpp | 2 ++
.../test/AST/builtin-static-analysis-assume.c | 22 +++++++++++++++++++
.../CodeGen/builtin-static-analysis-assume.c | 17 ++++++++++++++
.../Sema/builtin-static-analysis-assume.cpp | 14 ++++++++++++
5 files changed, 61 insertions(+)
create mode 100644 clang/test/AST/builtin-static-analysis-assume.c
create mode 100644 clang/test/CodeGen/builtin-static-analysis-assume.c
create mode 100644 clang/test/Sema/builtin-static-analysis-assume.cpp
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 792e2e07ec594..4f0e9129d98aa 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5253,3 +5253,9 @@ def CountedByRef : Builtin {
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
}
+
+def StaticAnalysisAssume : Builtin {
+ let Spellings = ["__builtin_static_analysis_assume"];
+ let Attributes = [NoThrow, Const, Pure, UnevaluatedArguments];
+ let Prototype = "void(bool)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 9ee810c9d5775..34e6b512d20c6 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3733,6 +3733,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
+ case Builtin::BI__builtin_static_analysis_assume:
+ return RValue::get(nullptr);
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
// FIXME: Technically these constants should of type 'int', yes?
diff --git a/clang/test/AST/builtin-static-analysis-assume.c b/clang/test/AST/builtin-static-analysis-assume.c
new file mode 100644
index 0000000000000..ac544be49ab90
--- /dev/null
+++ b/clang/test/AST/builtin-static-analysis-assume.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -ast-dump -triple x86_64-linux-gnu %s \
+// RUN: | FileCheck %s --strict-whitespace --check-prefixes=CHECK
+//
+// Tests with serialization:
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -include-pch %t -ast-dump-all /dev/null \
+// RUN: | FileCheck %s --strict-whitespace
+
+int fun() {
+ int x = 0;
+ __builtin_static_analysis_assume(++x >= 1);
+ return x;
+}
+
+// CHECK: |-CallExpr {{.*}} <line:11:5, col:46> 'void'
+// CHECK: | |-ImplicitCastExpr {{.*}} <col:5> 'void (*)(_Bool)' <BuiltinFnToFnPtr>
+// CHECK: | | `-DeclRefExpr {{.*}} <col:5> '<builtin fn type>' Function {{.*}} '__builtin_static_analysis_assume' 'void (_Bool)'
+// CHECK: | `-ImplicitCastExpr {{.*}} <col:38, col:45> '_Bool' <IntegralToBoolean>
+// CHECK: | `-BinaryOperator {{.*}} <col:38, col:45> 'int' '>='
+// CHECK: | |-UnaryOperator {{.*}} <col:38, col:40> 'int' prefix '++'
+// CHECK: | | `-DeclRefExpr {{.*}} <col:40> 'int' lvalue Var {{.*}} 'x' 'int'
+// CHECK: | `-IntegerLiteral {{.*}} <col:45> 'int' 1
diff --git a/clang/test/CodeGen/builtin-static-analysis-assume.c b/clang/test/CodeGen/builtin-static-analysis-assume.c
new file mode 100644
index 0000000000000..e73c2371be3b9
--- /dev/null
+++ b/clang/test/CodeGen/builtin-static-analysis-assume.c
@@ -0,0 +1,17 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s \
+// RUN: | FileCheck --check-prefix CHECK %s
+
+// CHECK-LABEL: define dso_local i32 @fun(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 0, ptr [[X]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X]], align 4
+// CHECK-NEXT: ret i32 [[TMP0]]
+//
+int fun() {
+ int x = 0;
+ __builtin_static_analysis_assume(++x >= 1);
+ return x;
+}
diff --git a/clang/test/Sema/builtin-static-analysis-assume.cpp b/clang/test/Sema/builtin-static-analysis-assume.cpp
new file mode 100644
index 0000000000000..3293e2ab15c55
--- /dev/null
+++ b/clang/test/Sema/builtin-static-analysis-assume.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+
+void voidfn();
+
+class Foo{};
+
+int fun() {
+ int x = 0;
+ __builtin_static_analysis_assume(true);
+ __builtin_static_analysis_assume(x <= 0);
+ __builtin_static_analysis_assume(voidfn()); // expected-error{{cannot initialize a parameter of type 'bool' with an rvalue of type 'void}}
+ __builtin_static_analysis_assume(Foo()); // expected-error{{no viable conversion from 'Foo' to 'bool'}}
+ return x;
+}
More information about the cfe-commits
mailing list