Skip to content

Commit 2961468

Browse files
committed
C++: Add support for C23 _BitInts
1 parent 4812cdd commit 2961468

4 files changed

Lines changed: 147 additions & 54 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ private class BuiltInDumpType extends DumpType, BuiltInType {
148148
override string getTypeSpecifier() { result = this.toString() }
149149
}
150150

151-
private class IntegralDumpType extends BuiltInDumpType, IntegralType {
152-
override string getTypeSpecifier() { result = this.getCanonicalArithmeticType().toString() }
151+
private class IntegralDumpType extends BuiltInDumpType instanceof IntegralType {
152+
override string getTypeSpecifier() { result = super.getCanonicalArithmeticType().toString() }
153153
}
154154

155155
private class DerivedDumpType extends DumpType, DerivedType {

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

Lines changed: 128 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ class UnknownType extends BuiltInType {
349349
override string getAPrimaryQlClass() { result = "UnknownType" }
350350
}
351351

352-
private predicate isArithmeticType(@builtintype type, int kind) {
352+
private predicate isBuiltInArithmeticType(@builtintype type, int kind) {
353353
builtintypes(type, _, kind, _, _, _) and
354354
kind >= 4 and
355355
kind != 34 and // Exclude decltype(nullptr)
@@ -378,14 +378,50 @@ class ScalableVectorCount extends BuiltInType {
378378
* operations may be performed. Examples of arithmetic types include
379379
* `char`, `int`, `float`, and `bool`.
380380
*/
381-
class ArithmeticType extends BuiltInType {
382-
ArithmeticType() { isArithmeticType(underlyingElement(this), _) }
381+
abstract private class ArithmeticTypeImpl extends Type { }
383382

384-
override string getAPrimaryQlClass() { result = "ArithmeticType" }
383+
final class ArithmeticType = ArithmeticTypeImpl;
384+
385+
/**
386+
* A C/C++ arithmetic type that is not a bit-precise integer.
387+
*/
388+
class BuiltInArithmeticType extends ArithmeticTypeImpl, BuiltInType {
389+
BuiltInArithmeticType() { isBuiltInArithmeticType(underlyingElement(this), _) }
390+
391+
override string getAPrimaryQlClass() { result = "BuiltInArithmeticType" }
392+
}
393+
394+
/**
395+
* A C23 bit-precise integer (`_BitInt`).
396+
*/
397+
class BitPreciseArithmeticType extends ArithmeticTypeImpl {
398+
boolean isSigned;
399+
boolean isExplicitlySigned;
400+
int bitWidth;
401+
402+
BitPreciseArithmeticType() {
403+
bit_precise_types(underlyingElement(this), isSigned, isExplicitlySigned, bitWidth)
404+
}
405+
406+
override string toString() { result = this.getName() }
407+
408+
override string getName() {
409+
isSigned = true and isExplicitlySigned = true and result = "signed _BitInt(" + bitWidth + ")"
410+
or
411+
isSigned = true and isExplicitlySigned = false and result = "_BitInt(" + bitWidth + ")"
412+
or
413+
isSigned = false and result = "unsigned _BitInt(" + bitWidth + ")"
414+
}
415+
416+
override string explain() { result = this.getName() }
417+
418+
override predicate isDeeplyConstBelow() { any() } // No subparts
419+
420+
override string getAPrimaryQlClass() { result = "BitPreciseArithmeticType" }
385421
}
386422

387-
private predicate isIntegralType(@builtintype type, int kind) {
388-
isArithmeticType(type, kind) and
423+
private predicate isBuiltInIntegralType(@builtintype type, int kind) {
424+
isBuiltInArithmeticType(type, kind) and
389425
(
390426
kind < 24
391427
or
@@ -420,10 +456,13 @@ private predicate isIntegralType(@builtintype type, int kind) {
420456
class IntegralOrEnumType extends Type {
421457
IntegralOrEnumType() {
422458
// Integral type
423-
isIntegralType(underlyingElement(this), _)
459+
isBuiltInIntegralType(underlyingElement(this), _)
424460
or
425461
// Enum type
426462
usertypes(underlyingElement(this), _, [4, 13])
463+
or
464+
// Bit-precise integer type (`_BitInt`)
465+
bit_precise_types(underlyingElement(this), _, _, _)
427466
}
428467
}
429468

@@ -499,19 +538,54 @@ private predicate integralTypeMapping(int original, int canonical, int unsigned,
499538
* char c;
500539
* ```
501540
*/
502-
class IntegralType extends ArithmeticType, IntegralOrEnumType {
503-
int kind;
504-
505-
IntegralType() { isIntegralType(underlyingElement(this), kind) }
506-
541+
abstract private class IntegralTypeImpl extends ArithmeticTypeImpl, IntegralOrEnumType {
507542
/** Holds if this integral type is signed. */
508-
predicate isSigned() { builtintypes(underlyingElement(this), _, _, _, -1, _) }
543+
abstract predicate isSigned();
509544

510545
/** Holds if this integral type is unsigned. */
511-
predicate isUnsigned() { builtintypes(underlyingElement(this), _, _, _, 1, _) }
546+
abstract predicate isUnsigned();
512547

513548
/** Holds if this integral type is explicitly signed. */
514-
predicate isExplicitlySigned() {
549+
abstract predicate isExplicitlySigned();
550+
551+
/** Holds if this integral type is explicitly unsigned. */
552+
abstract predicate isExplicitlyUnsigned();
553+
554+
/** Holds if this integral type is implicitly signed. */
555+
abstract predicate isImplicitlySigned();
556+
557+
/**
558+
* Gets the unsigned type corresponding to this integral type. For
559+
* example on a `short`, this would give the type `unsigned short`.
560+
*/
561+
abstract IntegralType getUnsigned();
562+
563+
/**
564+
* Gets the canonical type corresponding to this integral type.
565+
*
566+
* For a plain type, this gives the same type (e.g. `short` -> `short`).
567+
* For an explicitly unsigned type, this gives the same type (e.g. `unsigned short` -> `unsigned short`).
568+
* For an explicitly signed type, this gives the plain version of that type (e.g. `signed short` -> `short`), except
569+
* that `signed char` -> `signed char`.
570+
*/
571+
abstract IntegralType getCanonicalArithmeticType();
572+
}
573+
574+
final class IntegralType = IntegralTypeImpl;
575+
576+
/**
577+
* A C/C++ integral type that is not a bit-precise integer.
578+
*/
579+
class BuiltInIntegralType extends IntegralTypeImpl, BuiltInArithmeticType {
580+
int kind;
581+
582+
BuiltInIntegralType() { isBuiltInIntegralType(underlyingElement(this), kind) }
583+
584+
override predicate isSigned() { builtintypes(underlyingElement(this), _, _, _, -1, _) }
585+
586+
override predicate isUnsigned() { builtintypes(underlyingElement(this), _, _, _, 1, _) }
587+
588+
override predicate isExplicitlySigned() {
515589
builtintypes(underlyingElement(this), _, 7, _, _, _) or
516590
builtintypes(underlyingElement(this), _, 10, _, _, _) or
517591
builtintypes(underlyingElement(this), _, 13, _, _, _) or
@@ -520,8 +594,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
520594
builtintypes(underlyingElement(this), _, 37, _, _, _)
521595
}
522596

523-
/** Holds if this integral type is explicitly unsigned. */
524-
predicate isExplicitlyUnsigned() {
597+
override predicate isExplicitlyUnsigned() {
525598
builtintypes(underlyingElement(this), _, 6, _, _, _) or
526599
builtintypes(underlyingElement(this), _, 9, _, _, _) or
527600
builtintypes(underlyingElement(this), _, 12, _, _, _) or
@@ -530,8 +603,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
530603
builtintypes(underlyingElement(this), _, 36, _, _, _)
531604
}
532605

533-
/** Holds if this integral type is implicitly signed. */
534-
predicate isImplicitlySigned() {
606+
override predicate isImplicitlySigned() {
535607
builtintypes(underlyingElement(this), _, 5, _, -1, _) or
536608
builtintypes(underlyingElement(this), _, 8, _, -1, _) or
537609
builtintypes(underlyingElement(this), _, 11, _, -1, _) or
@@ -540,33 +612,44 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
540612
builtintypes(underlyingElement(this), _, 35, _, -1, _)
541613
}
542614

543-
/**
544-
* Gets the unsigned type corresponding to this integral type. For
545-
* example on a `short`, this would give the type `unsigned short`.
546-
*/
547-
IntegralType getUnsigned() {
615+
override IntegralType getUnsigned() {
548616
exists(int unsignedKind |
549617
integralTypeMapping(kind, _, unsignedKind, _) and
550618
builtintypes(unresolveElement(result), _, unsignedKind, _, _, _)
551619
)
552620
}
553621

554-
/**
555-
* Gets the canonical type corresponding to this integral type.
556-
*
557-
* For a plain type, this gives the same type (e.g. `short` -> `short`).
558-
* For an explicitly unsigned type, this gives the same type (e.g. `unsigned short` -> `unsigned short`).
559-
* For an explicitly signed type, this gives the plain version of that type (e.g. `signed short` -> `short`), except
560-
* that `signed char` -> `signed char`.
561-
*/
562-
IntegralType getCanonicalArithmeticType() {
622+
override IntegralType getCanonicalArithmeticType() {
563623
exists(int canonicalKind |
564624
integralTypeMapping(kind, canonicalKind, _, _) and
565625
builtintypes(unresolveElement(result), _, canonicalKind, _, _, _)
566626
)
567627
}
568628
}
569629

630+
/**
631+
* A C23 bit-precise integer (`_BitInt`).
632+
*/
633+
class BitPreciseType extends IntegralTypeImpl, BitPreciseArithmeticType {
634+
override predicate isSigned() { isSigned = true }
635+
636+
override predicate isUnsigned() { not this.isSigned() }
637+
638+
override predicate isExplicitlySigned() { isExplicitlySigned = true }
639+
640+
override predicate isExplicitlyUnsigned() { this.isUnsigned() }
641+
642+
override predicate isImplicitlySigned() { not this.isExplicitlySigned() }
643+
644+
override IntegralType getUnsigned() {
645+
bit_precise_types(unresolveElement(result), false, false, bitWidth)
646+
}
647+
648+
override IntegralType getCanonicalArithmeticType() {
649+
bit_precise_types(unresolveElement(result), isSigned, false, bitWidth)
650+
}
651+
}
652+
570653
/**
571654
* The C/C++ boolean type. See 4.2. This is the C `_Bool` type
572655
* or the C++ `bool` type. For example:
@@ -575,7 +658,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
575658
* _Bool c, d; // C
576659
* ```
577660
*/
578-
class BoolType extends IntegralType {
661+
class BoolType extends BuiltInIntegralType {
579662
BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) }
580663

581664
override string getAPrimaryQlClass() { result = "BoolType" }
@@ -591,7 +674,7 @@ class BoolType extends IntegralType {
591674
* unsigned char e, f;
592675
* ```
593676
*/
594-
class CharType extends IntegralType {
677+
class CharType extends BuiltInIntegralType {
595678
CharType() { builtintypes(underlyingElement(this), _, [5, 6, 7], _, _, _) }
596679
}
597680

@@ -641,7 +724,7 @@ class SignedCharType extends CharType {
641724
* signed short ss;
642725
* ```
643726
*/
644-
class ShortType extends IntegralType {
727+
class ShortType extends BuiltInIntegralType {
645728
ShortType() {
646729
builtintypes(underlyingElement(this), _, 8, _, _, _) or
647730
builtintypes(underlyingElement(this), _, 9, _, _, _) or
@@ -658,7 +741,7 @@ class ShortType extends IntegralType {
658741
* unsigned int ui;
659742
* ```
660743
*/
661-
class IntType extends IntegralType {
744+
class IntType extends BuiltInIntegralType {
662745
IntType() {
663746
builtintypes(underlyingElement(this), _, 11, _, _, _) or
664747
builtintypes(underlyingElement(this), _, 12, _, _, _) or
@@ -675,7 +758,7 @@ class IntType extends IntegralType {
675758
* long l;
676759
* ```
677760
*/
678-
class LongType extends IntegralType {
761+
class LongType extends BuiltInIntegralType {
679762
LongType() {
680763
builtintypes(underlyingElement(this), _, 14, _, _, _) or
681764
builtintypes(underlyingElement(this), _, 15, _, _, _) or
@@ -692,7 +775,7 @@ class LongType extends IntegralType {
692775
* signed long long sll;
693776
* ```
694777
*/
695-
class LongLongType extends IntegralType {
778+
class LongLongType extends BuiltInIntegralType {
696779
LongLongType() {
697780
builtintypes(underlyingElement(this), _, 17, _, _, _) or
698781
builtintypes(underlyingElement(this), _, 18, _, _, _) or
@@ -710,7 +793,7 @@ class LongLongType extends IntegralType {
710793
* unsigned __int128 ui128;
711794
* ```
712795
*/
713-
class Int128Type extends IntegralType {
796+
class Int128Type extends BuiltInIntegralType {
714797
Int128Type() {
715798
builtintypes(underlyingElement(this), _, 35, _, _, _) or
716799
builtintypes(underlyingElement(this), _, 36, _, _, _) or
@@ -865,7 +948,7 @@ private predicate floatingPointTypeMapping(
865948
* fixed-size floating-point types like `_Float32`, and the extended-precision floating-point types
866949
* like `_Float64x`. It also includes the complex and imaginary versions of all of these types.
867950
*/
868-
class FloatingPointType extends ArithmeticType {
951+
class FloatingPointType extends BuiltInArithmeticType {
869952
final int base;
870953
final TypeDomain domain;
871954
final int realKind;
@@ -1003,7 +1086,7 @@ class VoidType extends BuiltInType {
10031086
* wchar_t wc;
10041087
* ```
10051088
*/
1006-
class WideCharType extends IntegralType {
1089+
class WideCharType extends BuiltInIntegralType {
10071090
WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) }
10081091

10091092
override string getAPrimaryQlClass() { result = "WideCharType" }
@@ -1015,7 +1098,7 @@ class WideCharType extends IntegralType {
10151098
* char8_t c8;
10161099
* ```
10171100
*/
1018-
class Char8Type extends IntegralType {
1101+
class Char8Type extends BuiltInIntegralType {
10191102
Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) }
10201103

10211104
override string getAPrimaryQlClass() { result = "Char8Type" }
@@ -1027,7 +1110,7 @@ class Char8Type extends IntegralType {
10271110
* char16_t c16;
10281111
* ```
10291112
*/
1030-
class Char16Type extends IntegralType {
1113+
class Char16Type extends BuiltInIntegralType {
10311114
Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) }
10321115

10331116
override string getAPrimaryQlClass() { result = "Char16Type" }
@@ -1039,7 +1122,7 @@ class Char16Type extends IntegralType {
10391122
* char32_t c32;
10401123
* ```
10411124
*/
1042-
class Char32Type extends IntegralType {
1125+
class Char32Type extends BuiltInIntegralType {
10431126
Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) }
10441127

10451128
override string getAPrimaryQlClass() { result = "Char32Type" }

‎cpp/ql/lib/semmle/code/cpp/commons/CommonType.qll‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ class Wchar_t extends Type {
372372
*
373373
* This class is meaningless if a Microsoft compiler was not used.
374374
*/
375-
class MicrosoftInt8Type extends IntegralType {
375+
class MicrosoftInt8Type extends BuiltInIntegralType {
376376
MicrosoftInt8Type() {
377377
this instanceof CharType and
378378
not this.isExplicitlyUnsigned() and
@@ -388,7 +388,7 @@ class MicrosoftInt8Type extends IntegralType {
388388
*
389389
* This class is meaningless if a Microsoft compiler was not used.
390390
*/
391-
class MicrosoftInt16Type extends IntegralType {
391+
class MicrosoftInt16Type extends BuiltInIntegralType {
392392
MicrosoftInt16Type() {
393393
this instanceof ShortType and
394394
not this.isExplicitlyUnsigned() and
@@ -404,7 +404,7 @@ class MicrosoftInt16Type extends IntegralType {
404404
*
405405
* This class is meaningless if a Microsoft compiler was not used.
406406
*/
407-
class MicrosoftInt32Type extends IntegralType {
407+
class MicrosoftInt32Type extends BuiltInIntegralType {
408408
MicrosoftInt32Type() {
409409
this instanceof IntType and
410410
not this.isExplicitlyUnsigned() and
@@ -420,7 +420,7 @@ class MicrosoftInt32Type extends IntegralType {
420420
*
421421
* This class is meaningless if a Microsoft compiler was not used.
422422
*/
423-
class MicrosoftInt64Type extends IntegralType {
423+
class MicrosoftInt64Type extends BuiltInIntegralType {
424424
MicrosoftInt64Type() {
425425
this instanceof LongLongType and
426426
not this.isExplicitlyUnsigned() and

0 commit comments

Comments
 (0)