Skip to content

Commit 5bb48a2

Browse files
committed
C++: Support C23 typeof and typeof_unqual
1 parent 4ae49cf commit 5bb48a2

File tree

6 files changed

+204
-9
lines changed

6 files changed

+204
-9
lines changed

Diff for: cpp/ql/lib/semmle/code/cpp/Print.qll

+12
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,18 @@ private class DecltypeDumpType extends DumpType, Decltype {
176176
}
177177
}
178178

179+
private class TypeofExprDumpType extends DumpType, TypeofExprType {
180+
override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() }
181+
182+
override string getDeclaratorPrefix() {
183+
result = this.getBaseType().(DumpType).getDeclaratorPrefix()
184+
}
185+
186+
override string getDeclaratorSuffix() {
187+
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
188+
}
189+
}
190+
179191
private class PointerIshDumpType extends DerivedDumpType {
180192
PointerIshDumpType() {
181193
this instanceof PointerType or

Diff for: cpp/ql/lib/semmle/code/cpp/Type.qll

+129-5
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ class Type extends Locatable, @type {
9292
/**
9393
* Gets this type after typedefs have been resolved.
9494
*
95-
* The result of this predicate will be the type itself, except in the case of a TypedefType or a Decltype,
96-
* in which case the result will be type which results from (possibly recursively) resolving typedefs.
95+
* The result of this predicate will be the type itself, except in the case of a TypedefType, a Decltype,
96+
* or a TypeofExprType, in which case the result will be type which results from (possibly recursively)
97+
* resolving typedefs.
9798
*/
9899
pragma[nomagic]
99100
Type getUnderlyingType() { result = this }
@@ -1118,17 +1119,19 @@ class DerivedType extends Type, @derivedtype {
11181119
* ```
11191120
*/
11201121
class Decltype extends Type, @decltype {
1122+
Decltype() { decltypes(underlyingElement(this), _, 0, _, _) }
1123+
11211124
override string getAPrimaryQlClass() { result = "Decltype" }
11221125

11231126
/**
11241127
* The expression whose type is being obtained by this decltype.
11251128
*/
1126-
Expr getExpr() { decltypes(underlyingElement(this), unresolveElement(result), _, _) }
1129+
Expr getExpr() { decltypes(underlyingElement(this), unresolveElement(result), _, _, _) }
11271130

11281131
/**
11291132
* The type immediately yielded by this decltype.
11301133
*/
1131-
Type getBaseType() { decltypes(underlyingElement(this), _, unresolveElement(result), _) }
1134+
Type getBaseType() { decltypes(underlyingElement(this), _, _, unresolveElement(result), _) }
11321135

11331136
/**
11341137
* Whether an extra pair of parentheses around the expression would change the semantics of this decltype.
@@ -1142,7 +1145,7 @@ class Decltype extends Type, @decltype {
11421145
* ```
11431146
* Please consult the C++11 standard for more details.
11441147
*/
1145-
predicate parenthesesWouldChangeMeaning() { decltypes(underlyingElement(this), _, _, true) }
1148+
predicate parenthesesWouldChangeMeaning() { decltypes(underlyingElement(this), _, _, _, true) }
11461149

11471150
override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() }
11481151

@@ -1183,6 +1186,127 @@ class Decltype extends Type, @decltype {
11831186
}
11841187
}
11851188

1189+
/**
1190+
* An instance of the C23 `typeof` operator taking an expression as its argument.
1191+
* For example:
1192+
* ```
1193+
* int a;
1194+
* typeof(a) b;
1195+
* ```
1196+
*/
1197+
class TypeofExprType extends Type, @decltype {
1198+
TypeofExprType() { decltypes(underlyingElement(this), _, 1, _, _) }
1199+
1200+
override string getAPrimaryQlClass() { result = "TypeofExprType" }
1201+
1202+
/**
1203+
* The expression whose type is being obtained by this typeof.
1204+
*/
1205+
Expr getExpr() { decltypes(underlyingElement(this), unresolveElement(result), _, _, _) }
1206+
1207+
/**
1208+
* The type immediately yielded by this typeof.
1209+
*/
1210+
Type getBaseType() { decltypes(underlyingElement(this), _, _, unresolveElement(result), _) }
1211+
1212+
override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() }
1213+
1214+
override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() }
1215+
1216+
override Type stripType() { result = this.getBaseType().stripType() }
1217+
1218+
override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() }
1219+
1220+
override Location getLocation() { result = this.getExpr().getLocation() }
1221+
1222+
override string toString() { result = "typeof(...)" }
1223+
1224+
override string getName() { none() }
1225+
1226+
override int getSize() { result = this.getBaseType().getSize() }
1227+
1228+
override int getAlignment() { result = this.getBaseType().getAlignment() }
1229+
1230+
override int getPointerIndirectionLevel() {
1231+
result = this.getBaseType().getPointerIndirectionLevel()
1232+
}
1233+
1234+
override string explain() {
1235+
result = "typeof resulting in {" + this.getBaseType().explain() + "}"
1236+
}
1237+
1238+
override predicate involvesReference() { this.getBaseType().involvesReference() }
1239+
1240+
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
1241+
1242+
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() }
1243+
1244+
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() }
1245+
1246+
override Specifier internal_getAnAdditionalSpecifier() {
1247+
result = this.getBaseType().getASpecifier()
1248+
}
1249+
}
1250+
1251+
/**
1252+
* A type obtained by applying a type transforming intrinsic or the C23 `typeof`
1253+
* operator to a type.
1254+
* For example:
1255+
* ```
1256+
* __make_unsigned(int) x;
1257+
* typeof_unqual(const int) y;
1258+
* ```
1259+
*/
1260+
class TransformedType extends Type, @type_operator {
1261+
override string getAPrimaryQlClass() { result = "TransformedType" }
1262+
1263+
/**
1264+
* The type immediately yielded by this transformation.
1265+
*/
1266+
Type getBaseType() { type_operators(underlyingElement(this), _, _, unresolveElement(result)) }
1267+
1268+
/**
1269+
* The type transformed.
1270+
*/
1271+
Type getTransformedType() {
1272+
type_operators(underlyingElement(this), unresolveElement(result), _, _)
1273+
}
1274+
1275+
override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() }
1276+
1277+
override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() }
1278+
1279+
override Type stripType() { result = this.getBaseType().stripType() }
1280+
1281+
override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() }
1282+
1283+
override string getName() { none() }
1284+
1285+
override int getSize() { result = this.getBaseType().getSize() }
1286+
1287+
override int getAlignment() { result = this.getBaseType().getAlignment() }
1288+
1289+
override int getPointerIndirectionLevel() {
1290+
result = this.getBaseType().getPointerIndirectionLevel()
1291+
}
1292+
1293+
override string explain() {
1294+
result = "type transformation resulting in {" + this.getBaseType().explain() + "}"
1295+
}
1296+
1297+
override predicate involvesReference() { this.getBaseType().involvesReference() }
1298+
1299+
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
1300+
1301+
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() }
1302+
1303+
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() }
1304+
1305+
override Specifier internal_getAnAdditionalSpecifier() {
1306+
result = this.getBaseType().getASpecifier()
1307+
}
1308+
}
1309+
11861310
/**
11871311
* A C/C++ pointer type. See 4.9.1.
11881312
* ```

Diff for: cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll

+2
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ class Expr extends StmtParent, @expr {
310310
or
311311
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())
312312
or
313+
exists(TypeofExprType t | t.getExpr() = this.getParentWithConversions*())
314+
or
313315
exists(ConstexprIfStmt constIf |
314316
constIf.getControllingExpr() = this.getParentWithConversions*()
315317
)

Diff for: cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ private predicate isDeeplyConst(Type t) {
1616
or
1717
isDeeplyConst(t.(Decltype).getBaseType())
1818
or
19+
isDeeplyConst(t.(TypeofExprType).getBaseType())
20+
or
21+
isDeeplyConst(t.(TransformedType).getBaseType())
22+
or
1923
isDeeplyConst(t.(ReferenceType).getBaseType())
2024
or
2125
exists(SpecifiedType specType | specType = t |
@@ -36,6 +40,10 @@ private predicate isDeeplyConstBelow(Type t) {
3640
or
3741
isDeeplyConstBelow(t.(Decltype).getBaseType())
3842
or
43+
isDeeplyConstBelow(t.(TypeofExprType).getBaseType())
44+
or
45+
isDeeplyConstBelow(t.(TransformedType).getBaseType())
46+
or
3947
isDeeplyConst(t.(PointerType).getBaseType())
4048
or
4149
isDeeplyConst(t.(ReferenceType).getBaseType())

Diff for: cpp/ql/lib/semmlecode.cpp.dbscheme

+47-4
Original file line numberDiff line numberDiff line change
@@ -743,15 +743,17 @@ typedefbase(
743743
);
744744

745745
/**
746-
* An instance of the C++11 `decltype` operator. For example:
746+
* An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual`
747+
* operator taking an expression as its argument. For example:
747748
* ```
748749
* int a;
749750
* decltype(1+a) b;
751+
* typeof(1+a) c;
750752
* ```
751753
* Here `expr` is `1+a`.
752754
*
753755
* Sometimes an additional pair of parentheses around the expression
754-
* would change the semantics of this decltype, e.g.
756+
* changes the semantics of the decltype, e.g.
755757
* ```
756758
* struct A { double x; };
757759
* const A* a = new A();
@@ -761,14 +763,55 @@ typedefbase(
761763
* (Please consult the C++11 standard for more details).
762764
* `parentheses_would_change_meaning` is `true` iff that is the case.
763765
*/
766+
767+
/*
768+
case @decltype.kind of
769+
| 0 = @decltype
770+
| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
771+
;
772+
*/
773+
764774
#keyset[id, expr]
765775
decltypes(
766776
int id: @decltype,
767777
int expr: @expr ref,
778+
int kind: int ref,
768779
int base_type: @type ref,
769780
boolean parentheses_would_change_meaning: boolean ref
770781
);
771782

783+
/*
784+
case @type_operator.kind of
785+
| 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual
786+
| 1 = @underlying_type
787+
| 2 = @bases
788+
| 3 = @direct_bases
789+
| 4 = @add_lvalue_reference
790+
| 5 = @add_pointer
791+
| 6 = @add_rvalue_reference
792+
| 7 = @decay
793+
| 8 = @make_signed
794+
| 9 = @make_unsigned
795+
| 10 = @remove_all_extents
796+
| 11 = @remove_const
797+
| 12 = @remove_cv
798+
| 13 = @remove_cvref
799+
| 14 = @remove_extent
800+
| 15 = @remove_pointer
801+
| 16 = @remove_reference_t
802+
| 17 = @remove_restrict
803+
| 18 = @remove_volatile
804+
| 19 = @remove_reference
805+
;
806+
*/
807+
808+
type_operators(
809+
unique int id: @type_operator,
810+
int arg_type: @type ref,
811+
int kind: int ref,
812+
int base_type: @type ref
813+
)
814+
772815
/*
773816
case @usertype.kind of
774817
| 0 = @unknown_usertype
@@ -1103,10 +1146,10 @@ stmtattributes(
11031146
@type = @builtintype
11041147
| @derivedtype
11051148
| @usertype
1106-
/* TODO | @fixedpointtype */
11071149
| @routinetype
11081150
| @ptrtomember
1109-
| @decltype;
1151+
| @decltype
1152+
| @type_operator;
11101153

11111154
unspecifiedtype(
11121155
unique int type_id: @type ref,

Diff for: cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToMemset.ql

+6
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,17 @@ Type stripType(Type t) {
4747
or
4848
result = stripType(t.(Decltype).getBaseType())
4949
or
50+
result = stripType(t.(TypeofExprType).getBaseType())
51+
or
52+
result = stripType(t.(TransformedType).getBaseType())
53+
or
5054
not t instanceof TypedefType and
5155
not t instanceof ArrayType and
5256
not t instanceof ReferenceType and
5357
not t instanceof SpecifiedType and
5458
not t instanceof Decltype and
59+
not t instanceof TypeofExprType and
60+
not t instanceof TransformedType and
5561
result = t
5662
}
5763

0 commit comments

Comments
 (0)