Skip to content

Commit df3282c

Browse files
committed
C++: Support C23 typeof and typeof_unqual
1 parent 97ca2af commit df3282c

File tree

6 files changed

+307
-12
lines changed

6 files changed

+307
-12
lines changed

cpp/ql/lib/semmle/code/cpp/Print.qll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,30 @@ private class DecltypeDumpType extends DumpType, Decltype {
176176
}
177177
}
178178

179+
private class TypeofDumpType extends DumpType, TypeofType {
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+
191+
private class IntrinsicTransformedDumpType extends DumpType, IntrinsicTransformedType {
192+
override string getTypeSpecifier() { result = this.getBaseType().(DumpType).getTypeSpecifier() }
193+
194+
override string getDeclaratorPrefix() {
195+
result = this.getBaseType().(DumpType).getDeclaratorPrefix()
196+
}
197+
198+
override string getDeclaratorSuffix() {
199+
result = this.getBaseType().(DumpType).getDeclaratorSuffix()
200+
}
201+
}
202+
179203
private class PointerIshDumpType extends DerivedDumpType {
180204
PointerIshDumpType() {
181205
this instanceof PointerType or

cpp/ql/lib/semmle/code/cpp/Type.qll

Lines changed: 220 additions & 8 deletions
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 TypeofType, 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 }
@@ -1117,18 +1118,20 @@ class DerivedType extends Type, @derivedtype {
11171118
* decltype(a) b;
11181119
* ```
11191120
*/
1120-
class Decltype extends Type, @decltype {
1121+
class Decltype extends Type {
1122+
Decltype() { decltypes(underlyingElement(this), _, 0, _, _) }
1123+
11211124
override string getAPrimaryQlClass() { result = "Decltype" }
11221125

11231126
/**
1124-
* The expression whose type is being obtained by this decltype.
1127+
* Gets 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
/**
1129-
* The type immediately yielded by this decltype.
1132+
* Gets 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,215 @@ class Decltype extends Type, @decltype {
11831186
}
11841187
}
11851188

1189+
/**
1190+
* An instance of the C23 `typeof` or `typeof_unqual` operator. For example:
1191+
* ```
1192+
* int a;
1193+
* typeof(a) b;
1194+
* typeof_unqual(const int) b;
1195+
* ```
1196+
*/
1197+
class TypeofType extends Type {
1198+
TypeofType() {
1199+
decltypes(underlyingElement(this), _, 1, _, _) or
1200+
type_operators(underlyingElement(this), _, 0, _)
1201+
}
1202+
1203+
/**
1204+
* Gets the type immediately yielded by this typeof.
1205+
*/
1206+
Type getBaseType() {
1207+
decltypes(underlyingElement(this), _, _, unresolveElement(result), _)
1208+
or
1209+
type_operators(underlyingElement(this), _, _, unresolveElement(result))
1210+
}
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 string toString() { result = "typeof(...)" }
1221+
1222+
override string getName() { none() }
1223+
1224+
override int getSize() { result = this.getBaseType().getSize() }
1225+
1226+
override int getAlignment() { result = this.getBaseType().getAlignment() }
1227+
1228+
override int getPointerIndirectionLevel() {
1229+
result = this.getBaseType().getPointerIndirectionLevel()
1230+
}
1231+
1232+
override string explain() {
1233+
result = "typeof resulting in {" + this.getBaseType().explain() + "}"
1234+
}
1235+
1236+
override predicate involvesReference() { this.getBaseType().involvesReference() }
1237+
1238+
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
1239+
1240+
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() }
1241+
1242+
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() }
1243+
1244+
override Specifier internal_getAnAdditionalSpecifier() {
1245+
result = this.getBaseType().getASpecifier()
1246+
}
1247+
}
1248+
1249+
/**
1250+
* An instance of the C23 `typeof` or `typeof_unqual` operator taking an expression
1251+
* as its argument. For example:
1252+
* ```
1253+
* int a;
1254+
* typeof(a) b;
1255+
* ```
1256+
*/
1257+
class TypeofExprType extends TypeofType {
1258+
TypeofExprType() { decltypes(underlyingElement(this), _, 1, _, _) }
1259+
1260+
override string getAPrimaryQlClass() { result = "TypeofExprType" }
1261+
1262+
/**
1263+
* Gets the expression whose type is being obtained by this typeof.
1264+
*/
1265+
Expr getExpr() { decltypes(underlyingElement(this), unresolveElement(result), _, _, _) }
1266+
1267+
override Location getLocation() { result = this.getExpr().getLocation() }
1268+
}
1269+
1270+
/**
1271+
* A type obtained by C23 `typeof` or `typeof_unqual` operator taking a type as its
1272+
* argument. For example:
1273+
* ```
1274+
* typeof_unqual(const int) b;
1275+
* ```
1276+
*/
1277+
class TypeofTypeType extends TypeofType {
1278+
TypeofTypeType() { type_operators(underlyingElement(this), _, 0, _) }
1279+
1280+
/**
1281+
* Gets the expression whose type is being obtained by this typeof.
1282+
*/
1283+
Type getType() { type_operators(underlyingElement(this), unresolveElement(result), _, _) }
1284+
1285+
override string getAPrimaryQlClass() { result = "TypeofTypeType" }
1286+
1287+
override string toString() { result = "typeof(...)" }
1288+
}
1289+
1290+
/**
1291+
* A type obtained by applying a type transforming intrinsic. For example:
1292+
* ```
1293+
* __make_unsigned(int) x;
1294+
* ```
1295+
*/
1296+
class IntrinsicTransformedType extends Type {
1297+
int intrinsic;
1298+
1299+
IntrinsicTransformedType() {
1300+
type_operators(underlyingElement(this), _, intrinsic, _) and
1301+
intrinsic in [1 .. 19]
1302+
}
1303+
1304+
override string getAPrimaryQlClass() { result = "IntrinsicTransformedType" }
1305+
1306+
override string toString() { result = this.getIntrinsicName() + "(...)" }
1307+
1308+
/**
1309+
* Gets the type immediately yielded by this transformation.
1310+
*/
1311+
Type getBaseType() { type_operators(underlyingElement(this), _, _, unresolveElement(result)) }
1312+
1313+
/**
1314+
* Gets the type that is transformed.
1315+
*/
1316+
Type getType() { type_operators(underlyingElement(this), unresolveElement(result), _, _) }
1317+
1318+
/**
1319+
* Gets the name of the intrinsic used to transform the type.
1320+
*/
1321+
string getIntrinsicName() {
1322+
intrinsic = 1 and result = "__underlying_type"
1323+
or
1324+
intrinsic = 2 and result = "__bases"
1325+
or
1326+
intrinsic = 3 and result = "__direct_bases"
1327+
or
1328+
intrinsic = 4 and result = "__add_lvalue_reference"
1329+
or
1330+
intrinsic = 5 and result = "__add_pointer"
1331+
or
1332+
intrinsic = 6 and result = "__add_rvalue_reference"
1333+
or
1334+
intrinsic = 7 and result = "__decay"
1335+
or
1336+
intrinsic = 8 and result = "__make_signed"
1337+
or
1338+
intrinsic = 9 and result = "__make_unsigned"
1339+
or
1340+
intrinsic = 10 and result = "__remove_all_extents"
1341+
or
1342+
intrinsic = 11 and result = "__remove_const"
1343+
or
1344+
intrinsic = 12 and result = "__remove_cv"
1345+
or
1346+
intrinsic = 13 and result = "__remove_cvref"
1347+
or
1348+
intrinsic = 14 and result = "__remove_extent"
1349+
or
1350+
intrinsic = 15 and result = "__remove_pointer"
1351+
or
1352+
intrinsic = 16 and result = "__remove_reference_t"
1353+
or
1354+
intrinsic = 17 and result = "__remove_restrict"
1355+
or
1356+
intrinsic = 18 and result = "__remove_volatile"
1357+
or
1358+
intrinsic = 19 and result = "__remove_reference"
1359+
}
1360+
1361+
override Type getUnderlyingType() { result = this.getBaseType().getUnderlyingType() }
1362+
1363+
override Type stripTopLevelSpecifiers() { result = this.getBaseType().stripTopLevelSpecifiers() }
1364+
1365+
override Type stripType() { result = this.getBaseType().stripType() }
1366+
1367+
override Type resolveTypedefs() { result = this.getBaseType().resolveTypedefs() }
1368+
1369+
override string getName() { none() }
1370+
1371+
override int getSize() { result = this.getBaseType().getSize() }
1372+
1373+
override int getAlignment() { result = this.getBaseType().getAlignment() }
1374+
1375+
override int getPointerIndirectionLevel() {
1376+
result = this.getBaseType().getPointerIndirectionLevel()
1377+
}
1378+
1379+
override string explain() {
1380+
result =
1381+
"application of " + this.getIntrinsicName() + " resulting in {" + this.getBaseType().explain()
1382+
+ "}"
1383+
}
1384+
1385+
override predicate involvesReference() { this.getBaseType().involvesReference() }
1386+
1387+
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
1388+
1389+
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() }
1390+
1391+
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() }
1392+
1393+
override Specifier internal_getAnAdditionalSpecifier() {
1394+
result = this.getBaseType().getASpecifier()
1395+
}
1396+
}
1397+
11861398
/**
11871399
* A C/C++ pointer type. See 4.9.1.
11881400
* ```

cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll

Lines changed: 2 additions & 0 deletions
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
)

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

Lines changed: 8 additions & 0 deletions
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.(TypeofType).getBaseType())
20+
or
21+
isDeeplyConst(t.(IntrinsicTransformedType).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.(TypeofType).getBaseType())
44+
or
45+
isDeeplyConstBelow(t.(IntrinsicTransformedType).getBaseType())
46+
or
3947
isDeeplyConst(t.(PointerType).getBaseType())
4048
or
4149
isDeeplyConst(t.(ReferenceType).getBaseType())

0 commit comments

Comments
 (0)