-
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++: Add support for C++ requires expressions #17740
Conversation
ed70f88
to
db98433
Compare
What is the IR generated for |
There isn't any, because these are constant expressions, and they also have a value child. The value will occur in the IR, because that may be assigned to something. |
Note that the IR for the test I added in #17693 is not changed by this PR. |
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.
A few minor things but overall LGTM.
cpp/ql/lib/semmlecode.cpp.dbscheme
Outdated
@@ -1909,6 +1912,10 @@ case @expr.kind of | |||
| @istriviallyrelocatable | |||
; | |||
|
|||
compound_requirement_is_noexcept( | |||
unique int expr: @compound_requirement 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.
unique
is implicit here. Could an expression be possible here, similar to fun_decl_noexcept
? In that case, this predicate is compound_requirement_empty_noexcept
.
Another strategy could be to unite this predicate with fun_decl_noexcept
/fun_decl_empty_noexcept
, but that might be more work.
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.
unique
is implicit here
Do you mean that I can omit it?
Could an expression be possible here, similar to
fun_decl_noexcept
?
No, that's not allowed. It's just a keyword without any arguments.
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.
unique
is implicit hereDo you mean that I can omit it?
Yes I would think so. You can't have duplicated rows in a tuple.
Could an expression be possible here, similar to
fun_decl_noexcept
?No, that's not allowed. It's just a keyword without any arguments.
Ok.
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.
Dropped the unique
.
cpp/ql/lib/semmlecode.cpp.dbscheme
Outdated
@@ -2168,11 +2175,11 @@ stmt_decl_entry_bind( | |||
int decl_entry: @element ref | |||
); | |||
|
|||
@functionorblock = @function | @stmt_block; | |||
@functionorblockorrequiresexpr = @function | @stmt_block | @requires_expr; |
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.
Nit: could rename this to @block_parent
or something descriptive.
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.
Note that "block" has a special meaning here: https://clang.llvm.org/docs/BlockLanguageSpec.html
I'm open to a more sensible name though, just not sure what it should be.
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.
How about parameterized_element
?
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.
Replaced by parameterized_element
int index; | ||
|
||
Parameter() { params(this, function, index, _) } | ||
Parameter() { params(this, _, _, _) } |
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.
Is this line needed?
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.
I guess not. I mostly simplified this, because ql-for-ql started explaining, but didn't think beyond that.
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.
Dropped.
|
||
override string getAPrimaryQlClass() { result = "RequiresExpr" } | ||
|
||
/** | ||
* Gets a parameter of this requires expression. |
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.
* Gets a parameter of this requires expression. | |
* Gets a parameter of this requires expression, if any. |
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.
Done.
|
||
/** Gets the number of parameters of this requires expression. */ | ||
int getNumberOfParameters() { result = count(this.getAParameter()) } | ||
} |
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.
I would expect there to be a predicate to access the body as well. - getBlock()
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.
Oh, good point.
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.
getRequirement/1
getARequirement/0
and getNumberOfRequirements/0
added.
} | ||
|
||
/** | ||
* A C++ concept id expression |
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.
* A C++ concept id expression | |
* A C++ concept id expression. |
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.
Done.
#-----| Type = [BoolType] bool | ||
#-----| Value = [RequiresExpr] 1 | ||
#-----| ValueCategory = prvalue | ||
#-----| <params>: | ||
# 2692| getChild(0): [GTExpr,SimpleRequirementExpr] ... > ... |
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.
Accessing the body via getBlock()
might be nicer.
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.
Done, see above for the actual predicate name I used.
Expr getExpr() { result = this.getChild(0) } | ||
|
||
/** | ||
* Gets the return type requirement from the compound requirement (if any). |
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.
* Gets the return type requirement from the compound requirement (if any). | |
* Gets the return type requirement from the compound requirement, if any. |
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.
Done.
--- | ||
category: feature | ||
--- | ||
* Added classes `RequiresExpr`, `SimpleRequirementExpr`, `TypeRequirementExpr`, `CompoundRequirementExpr`, and `NestedRequirementExpr` to represent C++20 requires expressions and the simple, type, compound, and nested requirements that can occur in requires expressions. |
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.
* Added classes `RequiresExpr`, `SimpleRequirementExpr`, `TypeRequirementExpr`, `CompoundRequirementExpr`, and `NestedRequirementExpr` to represent C++20 requires expressions and the simple, type, compound, and nested requirements that can occur in requires expressions. | |
* Added classes `RequiresExpr`, `SimpleRequirementExpr`, `TypeRequirementExpr`, `CompoundRequirementExpr`, and `NestedRequirementExpr` to represent C++20 requires expressions and the simple, type, compound, and nested requirements that can occur in `require` expressions. |
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.
I assume you mean "requires
expressions"?
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.
Done.
override AstNode getChildInternal(int childIndex) { | ||
result.getAst() = expr.getChild(childIndex) | ||
override PrintAstNode getChildInternal(int childIndex) { | ||
result.(AstNode).getAst() = expr.getChild(childIndex) |
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.
Nit: Consider adding a predicatePrintAst::getAst() { none() }
.
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.
This in consistent with how this is done in other places in this library, so I'm going to leave this as-is for now.
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.
Left as-is.
*/ | ||
class RequiresExpr extends Expr, @requires_expr { | ||
override string toString() { result = "requires ..." } | ||
override string toString() { result = "requires(...) { ... }" } |
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.
Nit: Consider something like if exists(this.getAParameter()) then result = "requires(...) { ... }" else result = "requires { ... }" }
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.
Yes, I thought about that. However, I cannot really differentiate between empty and missing parameter lists, so I wasn't really sure about that.
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.
Done.
3acd474
to
0df5305
Compare
Apologies for force pushing the fixes. The schema changes made it very difficult to do something else and still end up with a reasonable history. |
* A C/C++ function parameter or catch block parameter. For example the | ||
* function parameter `p` and the catch block parameter `e` in the following | ||
* A C/C++ function parameter, catch block parameter, or requires expression parameter. | ||
* For example the function parameter `p` and the catch block parameter `e` in the following |
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.
Note that these changes are new.
* For catch block parameters, there is a one-to-one correspondence between | ||
* the `Parameter` and its `ParameterDeclarationEntry`. | ||
* For catch block parameters and expression , there is a one-to-one | ||
* correspondence between the `Parameter` and its `VariableDeclarationEntry`. |
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.
These changes are new.
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.
Great work!
Pull Request checklist
All query authors
.qhelp
. See the documentation in this repository.Internal query authors only
.ql
,.qll
, or.qhelp
files. See the documentation (internal access required).