mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
C++: Support C11 _Generic expressions
This commit is contained in:
4
cpp/ql/lib/change-notes/2024-08-30-c11-generics.md
Normal file
4
cpp/ql/lib/change-notes/2024-08-30-c11-generics.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a class `C11GenericExpr` to represent C11 generic selection expressions. The generic selection is represented as a `Conversion` on the expression that will be selected.
|
||||
@@ -385,6 +385,21 @@ class CastNode extends ConversionNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `C11GenericExpr`.
|
||||
*/
|
||||
class C11GenericNode extends ConversionNode {
|
||||
C11GenericExpr generic;
|
||||
|
||||
C11GenericNode() { generic = conv }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
result = super.getChildInternal(childIndex - count(generic.getAChild()))
|
||||
or
|
||||
result.getAst() = generic.getChild(childIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `StmtExpr`.
|
||||
*/
|
||||
@@ -860,6 +875,15 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(BuiltInVarArgsStart).getLastNamedParameter() = ele and pred = "getLastNamedParameter()"
|
||||
or
|
||||
expr.(C11GenericExpr).getControllingExpr() = ele and pred = "getControllingExpr()"
|
||||
or
|
||||
exists(int n |
|
||||
expr.(C11GenericExpr).getAssociationType(n) = ele.(TypeName).getType() and
|
||||
pred = "getAssociationType(" + n + ")"
|
||||
or
|
||||
expr.(C11GenericExpr).getAssociationExpr(n) = ele and pred = "getAssociationExpr(" + n + ")"
|
||||
)
|
||||
or
|
||||
expr.(Call).getQualifier() = ele and pred = "getQualifier()"
|
||||
or
|
||||
exists(int n | expr.(Call).getArgument(n) = ele and pred = "getArgument(" + n.toString() + ")")
|
||||
|
||||
@@ -632,6 +632,104 @@ class ParenthesisExpr extends Conversion, @parexpr {
|
||||
override string getAPrimaryQlClass() { result = "ParenthesisExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a C11 `_Generic` selection expression.
|
||||
*
|
||||
* For example:
|
||||
* ```
|
||||
* _Generic(e, int: "int", default: "unknown")
|
||||
* ```
|
||||
*/
|
||||
class C11GenericExpr extends Conversion, @c11_generic {
|
||||
int associationCount;
|
||||
|
||||
C11GenericExpr() { associationCount = (count(this.getAChild()) - 1) / 2 }
|
||||
|
||||
override string toString() { result = "_Generic" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "C11GenericExpr" }
|
||||
|
||||
/**
|
||||
* Gets the controlling expression of the generic selection.
|
||||
*
|
||||
* For example, for
|
||||
* ```
|
||||
* _Generic(e, int: "a", default: "b")
|
||||
* ```
|
||||
* the result is `e`.
|
||||
*/
|
||||
Expr getControllingExpr() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the type of the `n`th element in the association list of the generic selection.
|
||||
*
|
||||
* For example, for
|
||||
* ```
|
||||
* _Generic(e, int: "a", default: "b")
|
||||
* ```
|
||||
* the type of the 0th element is `int`. In the case of the default element the
|
||||
* type will an instance of `VoidType`.
|
||||
*/
|
||||
Type getAssociationType(int n) {
|
||||
n in [0 .. associationCount - 1] and
|
||||
result = this.getChild(n * 2 + 1).(TypeName).getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of an element in the association list of the generic selection.
|
||||
*/
|
||||
Type getAnAssociationType() { result = this.getAssociationType(_) }
|
||||
|
||||
/**
|
||||
* Gets the expression of the `n`th element in the association list of
|
||||
* the generic selection.
|
||||
*
|
||||
* For example, for
|
||||
* ```
|
||||
* _Generic(e, int: "a", default: "b")
|
||||
* ```
|
||||
* the expression for 0th element is `"a"`, and the expression for the
|
||||
* 1st element is `"b"`. For the selected expression, this predicate
|
||||
* will yield a `ReuseExpr`, such that
|
||||
* ```
|
||||
* this.getAssociationExpr(n).(ReuseExpr).getReusedExpr() = this.getExpr()
|
||||
* ```
|
||||
*/
|
||||
Expr getAssociationExpr(int n) {
|
||||
n in [0 .. associationCount - 1] and
|
||||
result = this.getChild(n * 2 + 2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression of an element in the association list of the generic selection.
|
||||
*/
|
||||
Expr getAnAssociationExpr() { result = this.getAssociationExpr(_) }
|
||||
|
||||
/**
|
||||
* Holds if the `n`th element of the association list of the generic selection is the
|
||||
* default element.
|
||||
*
|
||||
* For example, for
|
||||
* ```
|
||||
* _Generic(e, int: "a", default: "b")
|
||||
* ```
|
||||
* this holds for 1.
|
||||
*/
|
||||
predicate isDefaultAssociation(int n) { this.getAssociationType(n) instanceof VoidType }
|
||||
|
||||
/**
|
||||
* Holds if the `n`th element of the association list of the generic selection is the
|
||||
* one whose expression was selected.
|
||||
*
|
||||
* For example, with `e` of type `int` and
|
||||
* ```
|
||||
* _Generic(e, int: "a", default: "b")
|
||||
* ```
|
||||
* this holds for 0.
|
||||
*/
|
||||
predicate isSelectedAssociation(int n) { this.getAssociationExpr(n) instanceof ReuseExpr }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ expression that could not be resolved, or that can no longer be
|
||||
* represented due to a database upgrade or downgrade.
|
||||
@@ -668,6 +766,8 @@ class AssumeExpr extends Expr, @assume {
|
||||
|
||||
/**
|
||||
* A C/C++ comma expression.
|
||||
*
|
||||
* For example:
|
||||
* ```
|
||||
* int c = compute1(), compute2(), resulting_value;
|
||||
* ```
|
||||
|
||||
@@ -128,6 +128,9 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
|
||||
)
|
||||
or
|
||||
// The children of C11 _Generic expressions are just surface syntax.
|
||||
exists(C11GenericExpr generic | generic.getAChild() = expr)
|
||||
or
|
||||
// Do not translate implicit destructor calls for unnamed temporary variables that are
|
||||
// conditionally constructed (until we have a mechanism for calling these only when the
|
||||
// temporary's constructor was run)
|
||||
@@ -432,6 +435,9 @@ predicate ignoreLoad(Expr expr) {
|
||||
// The load is duplicated from the right operand.
|
||||
isExtractorFrontendVersion65OrHigher() and expr instanceof CommaExpr
|
||||
or
|
||||
// The load is duplicated from the chosen expression.
|
||||
expr instanceof C11GenericExpr
|
||||
or
|
||||
expr.(PointerDereferenceExpr).getOperand().getFullyConverted().getType().getUnspecifiedType()
|
||||
instanceof FunctionPointerType
|
||||
or
|
||||
|
||||
@@ -893,7 +893,8 @@ class TranslatedTransparentConversion extends TranslatedTransparentExpr {
|
||||
(
|
||||
expr instanceof ParenthesisExpr or
|
||||
expr instanceof ReferenceDereferenceExpr or
|
||||
expr instanceof ReferenceToExpr
|
||||
expr instanceof ReferenceToExpr or
|
||||
expr instanceof C11GenericExpr
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1210,6 +1210,7 @@ conversionkinds(
|
||||
| @reference_to
|
||||
| @ref_indirect
|
||||
| @temp_init
|
||||
| @c11_generic
|
||||
;
|
||||
|
||||
/*
|
||||
@@ -1792,6 +1793,7 @@ case @expr.kind of
|
||||
| 386 = @isscopedenum
|
||||
| 387 = @istriviallyrelocatable
|
||||
| 388 = @datasizeof
|
||||
| 389 = @c11_generic
|
||||
;
|
||||
|
||||
@var_args_expr = @vastartexpr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Expose C11 _Generics
|
||||
compatibility: backwards
|
||||
Reference in New Issue
Block a user