-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
C++: Support if consteval
and if ! consteval
#18502
base: main
Are you sure you want to change the base?
Changes from all commits
84c674b
bc2f203
123f1d5
4a3350b
6ad342c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
class Stmt extends @stmt { | ||
string toString() { none() } | ||
} | ||
|
||
class Location extends @location_stmt { | ||
string toString() { none() } | ||
} | ||
|
||
predicate isConstevalIf(Stmt stmt) { | ||
exists(int kind | stmts(stmt, kind, _) | kind = 38 or kind = 39) | ||
} | ||
|
||
from Stmt stmt, int kind, int kind_new, Location location | ||
where | ||
stmts(stmt, kind, location) and | ||
if isConstevalIf(stmt) then kind_new = 7 else kind_new = kind // Turns consteval if into a block with two block statement in it | ||
select stmt, kind_new, location |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
description: Support (not) consteval if | ||
compatibility: full | ||
consteval_if_then.rel: delete | ||
consteval_if_else.rel: delete | ||
stmts.rel: run stmts.qlo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: feature | ||
--- | ||
* New classes `ConstevalIfStmt` and `NotConstEvalIfStmt` were introduced, which represent the C++23 `if consteval` and `if ! consteval` statements. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -876,6 +876,25 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) { | |
p2.nodeAfter(n2, s) | ||
) | ||
or | ||
// ConstevalOrNotConstevalIfStmt -> { then, else } -> | ||
exists(ConstevalOrNotConstevalIfStmt s | | ||
p1.nodeAt(n1, s) and | ||
p2.nodeBefore(n2, s.getThen()) | ||
or | ||
p1.nodeAt(n1, s) and | ||
p2.nodeBefore(n2, s.getElse()) | ||
Comment on lines
+881
to
+885
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we allow both branches of the consteval if to be reached. |
||
or | ||
p1.nodeAt(n1, s) and | ||
not exists(s.getElse()) and | ||
p2.nodeAfter(n2, s) | ||
or | ||
p1.nodeAfter(n1, s.getThen()) and | ||
p2.nodeAfter(n2, s) | ||
or | ||
p1.nodeAfter(n1, s.getElse()) and | ||
p2.nodeAfter(n2, s) | ||
) | ||
or | ||
// WhileStmt -> condition ; body -> condition ; after dtors -> after | ||
exists(WhileStmt s | | ||
p1.nodeAt(n1, s) and | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1098,6 +1098,61 @@ class TranslatedConstExprIfStmt extends TranslatedIfLikeStmt { | |
override predicate hasElse() { exists(stmt.getElse()) } | ||
} | ||
|
||
class TranslatedConstevalOrNotConstevalIfStmt extends TranslatedStmt { | ||
override ConstevalOrNotConstevalIfStmt stmt; | ||
|
||
override Instruction getFirstInstruction(EdgeKind kind) { | ||
if not this.hasEvaluatedBranch() | ||
then | ||
kind instanceof GotoEdge and | ||
result = this.getInstruction(OnlyInstructionTag()) | ||
else result = this.getEvaluatedBranch().getFirstInstruction(kind) | ||
} | ||
|
||
override TranslatedElement getChildInternal(int id) { | ||
id = 0 and | ||
result = this.getThen() | ||
or | ||
id = 1 and | ||
result = this.getElse() | ||
} | ||
|
||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { | ||
not this.hasEvaluatedBranch() and | ||
opcode instanceof Opcode::NoOp and | ||
tag = OnlyInstructionTag() and | ||
resultType = getVoidType() | ||
} | ||
|
||
override Instruction getALastInstructionInternal() { | ||
if not this.hasEvaluatedBranch() | ||
then result = this.getInstruction(OnlyInstructionTag()) | ||
else result = this.getEvaluatedBranch().getALastInstruction() | ||
} | ||
|
||
override TranslatedElement getLastChild() { result = this.getEvaluatedBranch() } | ||
|
||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { | ||
tag = OnlyInstructionTag() and | ||
result = this.getParent().getChildSuccessor(this, kind) | ||
} | ||
|
||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { | ||
(child = this.getThen() or child = this.getElse()) and | ||
result = this.getParent().getChildSuccessor(this, kind) | ||
} | ||
|
||
TranslatedStmt getEvaluatedBranch() { | ||
result = getTranslatedStmt(stmt.getRuntimeEvaluatedBranch()) | ||
} | ||
Comment on lines
+1145
to
+1147
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We pick a single branch that can be reached. For now this is the branch that is taken at runtime, we can change this later if we see that using the compile time branch improves analysis quality. |
||
|
||
predicate hasEvaluatedBranch() { stmt.hasRuntimeEvaluatedBranch() } | ||
|
||
TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) } | ||
|
||
TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) } | ||
} | ||
|
||
abstract class TranslatedLoop extends TranslatedStmt, ConditionContext { | ||
override Loop stmt; | ||
|
||
|
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.