-
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
Changes from all commits
84c674b
bc2f203
123f1d5
4a3350b
6ad342c
378f036
a74189f
a9e0f20
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 statements 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 | ||
--- | ||
* A new class `ConstevalIfStmt` was introduced, which represents the C++23 `if consteval` and `if ! consteval` statements. |
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 TranslatedConstevalIfStmt extends TranslatedStmt { | ||
override ConstevalIfStmt 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; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2152,6 +2152,8 @@ case @stmt.kind of | |
// ... 34 @stmt_finally_end deprecated | ||
| 35 = @stmt_constexpr_if | ||
| 37 = @stmt_co_return | ||
| 38 = @stmt_consteval_if | ||
| 39 = @stmt_not_consteval_if | ||
; | ||
|
||
type_vla( | ||
|
@@ -2194,6 +2196,18 @@ constexpr_if_else( | |
int else_id: @stmt ref | ||
); | ||
|
||
@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if; | ||
|
||
consteval_if_then( | ||
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. I think we should use 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. What I'm doing here is consistent with |
||
unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, | ||
int then_id: @stmt ref | ||
); | ||
|
||
consteval_if_else( | ||
unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, | ||
int else_id: @stmt ref | ||
); | ||
|
||
while_body( | ||
unique int while_stmt: @stmt_while ref, | ||
int body_id: @stmt ref | ||
|
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.
Here we allow both branches of the consteval if to be reached.