-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang] add no-op __builtin_static_analysis_assume #162939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[clang] add no-op __builtin_static_analysis_assume #162939
Conversation
Created using spr 1.3.4
I'm not exactly sure how deep you want to go in the first PR, but I'd consider arming the Clang CFG to expect this new builtin. I was reluctant to directly push to your branch given that this seems like an spr branch, so here is the git diff. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index e1a4005d1a89..db91ac2403d3 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3250,8 +3250,9 @@ private:
}
public:
- /// Return true if this is a call to __assume() or __builtin_assume() with
- /// a non-value-dependent constant parameter evaluating as false.
+ /// Return true if this is a call to __assume(), __builtin_assume() or
+ /// __builtin_static_analysis_assume() with a non-value-dependent constant
+ /// parameter evaluating as false.
bool isBuiltinAssumeFalse(const ASTContext &Ctx) const;
/// Used by Sema to implement MSVC-compatible delayed name lookup.
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 922d67940e22..9e1dd7723814 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2970,6 +2970,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_assume:
case Builtin::BI__assume:
+ case Builtin::BI__builtin_static_analysis_assume:
return interp__builtin_assume(S, OpPC, Frame, Call);
case Builtin::BI__builtin_strcmp:
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index f899b3c4bb79..913ebd4d2e06 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3557,7 +3557,8 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const {
unsigned BuiltinID = getBuiltinCallee();
if (BuiltinID != Builtin::BI__assume &&
- BuiltinID != Builtin::BI__builtin_assume)
+ BuiltinID != Builtin::BI__builtin_assume &&
+ BuiltinID != Builtin::BI__builtin_static_analysis_assume)
return false;
const Expr* Arg = getArg(0);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 35a866ea5010..909f31a7845a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -17675,6 +17675,7 @@ public:
switch (E->getBuiltinCallee()) {
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
+ case Builtin::BI__builtin_static_analysis_assume:
// The argument is not evaluated!
return true;
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index cdde849b0e02..5e8e5c529057 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -2793,7 +2793,8 @@ static bool isBuiltinAssumeWithSideEffects(const ASTContext &Ctx,
const CallExpr *CE) {
unsigned BuiltinID = CE->getBuiltinCallee();
if (BuiltinID != Builtin::BI__assume &&
- BuiltinID != Builtin::BI__builtin_assume)
+ BuiltinID != Builtin::BI__builtin_assume &&
+ BuiltinID != Builtin::BI__builtin_static_analysis_assume)
return false;
return CE->getArg(0)->HasSideEffects(Ctx);
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 4cfa91e09efb..654126673a11 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -221,6 +221,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_fabsf128:
return emitUnaryMaybeConstrainedFPBuiltin<cir::FAbsOp>(*this, *e);
+ // FIXME: BI__builtin_static_analysis_assume should be handled carefully here.
+ // Ideally, we would emit CIR for this builtin, but only for analysis
+ // purposes, so lowering it to LLVM IR should not generate code,
case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (e->getArg(0)->HasSideEffects(getContext()))
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 34e6b512d20c..34163fca6843 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3561,6 +3561,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Builder.CreateDereferenceableAssumption(PtrValue, SizeValue);
return RValue::get(nullptr);
}
+ // Not handling BI__builtin_static_analysis_assume here because that should
+ // not emit LLVM IR.
case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (E->getArg(0)->HasSideEffects(getContext()))
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 063db05665af..f46b478da9fe 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2785,6 +2785,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
+ case Builtin::BI__builtin_static_analysis_assume:
if (BuiltinAssume(TheCall))
return ExprError();
break;
diff --git a/clang/lib/StaticAnalyzer/Checkers/AssumeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/AssumeModeling.cpp
index 789c7772d123..6fb21d67c61f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AssumeModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AssumeModeling.cpp
@@ -58,7 +58,9 @@ bool AssumeModelingChecker::evalCall(const CallEvent &Call,
if (!FD)
return false;
- if (!llvm::is_contained({Builtin::BI__builtin_assume, Builtin::BI__assume},
+ if (!llvm::is_contained({Builtin::BI__builtin_assume,
+ Builtin::BI__builtin_static_analysis_assume,
+ Builtin::BI__assume},
FD->getBuiltinID())) {
return false;
}
diff --git a/clang/test/Analysis/builtin-assume-cfgs.c b/clang/test/Analysis/builtin-assume-cfgs.c
new file mode 100644
index 000000000000..ca448bb16ecc
--- /dev/null
+++ b/clang/test/Analysis/builtin-assume-cfgs.c
@@ -0,0 +1,52 @@
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s \
+// RUN: -analyzer-checker=core,debug.DumpCFG 2>&1 \
+// RUN: | FileCheck %s
+
+int intfn(void);
+
+int calling_builtin_static_analysis_assume(int x) {
+ __builtin_static_analysis_assume(++x >= intfn());
+ // expected-warning@-1 {{assumption is ignored because it contains (potential) side-effects}}
+ return x;
+}
+
+// CHECK: int calling_builtin_static_analysis_assume(int x)
+// CHECK-NEXT: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK-EMPTY:
+// CHECK-NEXT: [B1]
+// CHECK-NEXT: 1: __builtin_static_analysis_assume
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, BuiltinFnToFnPtr, void (*)(_Bool))
+// CHECK-NEXT: 3: [B1.2](++x >= intfn())
+// CHECK-NEXT: 4: x
+// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 6: return [B1.5];
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK-EMPTY:
+// CHECK-NEXT: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+
+
+int calling_builtin_assume(int x) {
+ __builtin_assume(++x >= intfn());
+ // expected-warning@-1 {{assumption is ignored because it contains (potential) side-effects}}
+ return x;
+}
+
+// CHECK: int calling_builtin_assume(int x)
+// CHECK-NEXT: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK-EMPTY:
+// CHECK-NEXT: [B1]
+// CHECK-NEXT: 1: __builtin_assume
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, BuiltinFnToFnPtr, void (*)(_Bool))
+// CHECK-NEXT: 3: [B1.2](++x >= intfn())
+// CHECK-NEXT: 4: x
+// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 6: return [B1.5];
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK-EMPTY:
+// CHECK-NEXT: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1 |
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}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also have an example of intfn()
too.
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}} | |
void voidfn(); | |
int intfn(); | |
class Foo{}; | |
int fun() { | |
int x = 0; | |
__builtin_static_analysis_assume(true); | |
__builtin_static_analysis_assume(x <= 0); | |
__builtin_static_analysis_assume(intfn()); | |
__builtin_static_analysis_assume(voidfn()); // expected-error{{cannot initialize a parameter of type 'bool' with an rvalue of type 'void}} |
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