Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 223 additions & 4 deletions cpp/common/src/codingstandards/cpp/Extensions.qll
Original file line number Diff line number Diff line change
@@ -1,11 +1,230 @@
import cpp

/**
* Common base class for modeling compiler extensions.
* A usage of a compiler extension in C++ code, such as non-standard attributes or built-in function
* calls.
*/
abstract class CompilerExtension extends Locatable { }
abstract class CPPCompilerExtension extends Locatable {
abstract string getMessage();
}

/**
* Common base class for modeling compiler extensions in CPP.
* An `Attribute` that may be a `GnuAttribute` or `Declspec`, or `MicrosoftAttribute`, etc.
*
* There are language extensions such as GNU `__attribute__`, Microsoft `__declspec` or
* `[attribute]` syntax.
*/
abstract class CPPCompilerExtension extends CompilerExtension { }
class CPPAttributeExtension extends CPPCompilerExtension, Attribute {
CPPAttributeExtension() { not this instanceof StdAttribute and not this instanceof AlignAs }

override string getMessage() {
result =
"Use of attribute '" + getName() +
"' is a compiler extension and is not portable to other compilers."
}
}

/**
* A `StdAttribute` within a compiler specific namespace such as `[[gnu::weak]]`.
*/
class CppNamespacedStdAttributeExtension extends CPPCompilerExtension, StdAttribute {
CppNamespacedStdAttributeExtension() { exists(this.getNamespace()) and not getNamespace() = "" }

override string getMessage() {
result =
"Use of attribute '" + getName() + "' in namespace '" + getNamespace() +
"' is a compiler extension and is not portable to other compilers."
}
}

/**
* A `StdAttribute` with a name not recognized as part of the C++17 standard.
*
* Only the listed names are valid C++17. Namespaced attributes are handled by
* `CppNamespacedStdAttributeExtension` and not considered here.
*/
class CppUnrecognizedAttributeExtension extends CPPCompilerExtension, StdAttribute {
CppUnrecognizedAttributeExtension() {
Comment on lines +30 to +47
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CppNamespacedStdAttributeExtension / CppUnrecognizedAttributeExtension use a different Cpp... prefix than the rest of the newly introduced CPP... extension classes in this module. Align the naming (for example, consistently use CPP...) so the API is easier to discover and search.

Copilot uses AI. Check for mistakes.
not this instanceof CppNamespacedStdAttributeExtension and
not getName() in [
"maybe_unused", "nodiscard", "noreturn", "deprecated", "carries_dependency", "fallthrough"
]
}
Comment on lines +46 to +52
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These newly introduced classes are public (not marked private) but are missing QLDoc comments. The project guidelines require public declarations to be documented; add /** ... */ docs (or mark them private if they are intended for internal use only).

This issue also appears on line 198 of the same file.

Copilot uses AI. Check for mistakes.

override string getMessage() {
result = "Use of unrecognized or non-C++17 attribute '" + getName() + "'."
}
}

/**
* A `FunctionCall` of a compiler-specific builtin function.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
*/
class CPPBuiltinFunctionExtension extends CPPCompilerExtension, FunctionCall {
CPPBuiltinFunctionExtension() {
getTarget().getName().indexOf("__builtin_") = 0 or
getTarget().getName().indexOf("__sync_") = 0 or
getTarget().getName().indexOf("__atomic_") = 0
}

override string getMessage() {
result =
"Call to builtin function '" + getTarget().getName() +
"' is a compiler extension and is not portable to other compilers."
}
}

/**
* A `StmtExpr`, which uses `({ <stmts> })` syntax, which is a GNU extension.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
*/
class CPPStmtExprExtension extends CPPCompilerExtension, StmtExpr {
override string getMessage() {
result =
"Statement expressions are a compiler extension and are not portable to other compilers."
}
}

/**
* A `ConditionalExpr` using GNU-style omitted middle operand such as `x ?: y`.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html
*/
class CPPTerseTernaryExtension extends CPPCompilerExtension, ConditionalExpr {
CPPTerseTernaryExtension() { getCondition() = getElse() or getCondition() = getThen() }

override string getMessage() {
result =
"Ternaries with omitted middle operands are a compiler extension and are not portable to " +
"other compilers."
}
Comment on lines +98 to +102
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some message strings exceed the repo's 100-character line limit for CodeQL source/test files (for example, this line). Please wrap these strings across multiple lines to keep each source line ≤ 100 characters.

This issue also appears on line 123 of the same file.

Copilot uses AI. Check for mistakes.
}

/**
* A non-standard `Type` that is only available as a compiler extension, such as `__int128`,
* `_Decimal32`, `_Decimal64`, `_Decimal128`, or `__float128`.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html
*/
class CPPExtensionType extends Type {
CPPExtensionType() {
this instanceof Int128Type or
this instanceof Decimal128Type or
this instanceof Decimal32Type or
this instanceof Decimal64Type or
this instanceof Float128Type
}
}

/**
* A `DeclarationEntry` using an extended type such as `__int128`, `_Decimal32`, `_Decimal64`,
* `_Decimal128`, or `__float128`.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
*/
class CPPExtensionTypeUsage extends CPPCompilerExtension, DeclarationEntry {
CPPExtensionType extendedType;

CPPExtensionTypeUsage() { extendedType = getType() }

override string getMessage() {
result =
"Declaration '" + getName() + "' uses type '" + extendedType.getName() +
"' which is a compiler extension and is not portable to other compilers."
}
}

/**
* A `DeclarationEntry` using a zero-length array, which is a non-standard way to declare a flexible
* array member.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
*/
class CPPZeroLengthArraysExtension extends CPPCompilerExtension, DeclarationEntry {
ArrayType array;

CPPZeroLengthArraysExtension() {
array = getType() and
array.getArraySize() = 0
}

override string getMessage() {
result =
"Variable '" + getName() + "' is declared with a zero-length array (of '" +
array.getBaseType() + "') is a compiler extension and are not portable to other compilers."
}
}

/**
* A `Field` with a variable-length array type in a struct member (not C++17 compliant).
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
*/
class CPPVariableLengthArraysExtension extends CPPCompilerExtension, VlaDeclStmt {
override string getMessage() {
result =
"Variable length array (used in '" + this +
"') are a compiler extension and are not portable to other compilers."
}
}

/**
* A `PreprocessorIfdef` using a builtin preprocessor feature such as `__has_builtin`,
* `__has_include`, etc., which are non-standard clang extensions.
*
* Reference: https://clang.llvm.org/docs/LanguageExtensions.html
*/
class CPPConditionalDefineExtension extends CPPCompilerExtension, PreprocessorIfdef {
string feature;

CPPConditionalDefineExtension() {
feature =
[
"__has_builtin", "__has_constexpr_builtin", "__has_feature", "__has_extension",
"__has_attribute", "__has_declspec_attribute", "__is_identifier", "__has_include",
"__has_include_next", "__has_warning", "__has_cpp_attribute"
] and
exists(toString().indexOf(feature))
}

override string getMessage() {
result =
"Call to builtin preprocessor feature '" + feature +
"' is a compiler extension and is not portable to other compilers."
}
}

/**
* A `PreprocessorDirective` that is a non-standard compiler extension, such as `#pragma`, `#error`,
* or `#warning`.
*/
class CPPPreprocessorDirectiveExtension extends CPPCompilerExtension, PreprocessorDirective {
string kind;

CPPPreprocessorDirectiveExtension() {
this instanceof PreprocessorPragma and kind = "#pragma " + getHead()
or
this instanceof PreprocessorError and kind = "#error"
or
this instanceof PreprocessorWarning and kind = "#warning"
}

override string getMessage() {
result = "Use of non-standard preprocessor directive '" + kind + "' is a compiler extension."
}
}

/**
* A `BuiltInOperation` which describes certain non-standard syntax such as type trait operations,
* for example GNU `__is_abstract(T)`, `__is_same(T, U)`, etc.
*
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
*/
class CPPBuiltinOperationExtension extends CPPCompilerExtension, BuiltInOperation {
override string getMessage() {
result = "Use of built-in operation '" + toString() + "' is a compiler extension."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import Statements
import Strings
import Templates
import Toolchain
import Toolchain2
import Toolchain3
import Trigraph
import TrustBoundaries
Expand Down Expand Up @@ -191,6 +192,7 @@ newtype TCPPQuery =
TStringsPackageQuery(StringsQuery q) or
TTemplatesPackageQuery(TemplatesQuery q) or
TToolchainPackageQuery(ToolchainQuery q) or
TToolchain2PackageQuery(Toolchain2Query q) or
TToolchain3PackageQuery(Toolchain3Query q) or
TTrigraphPackageQuery(TrigraphQuery q) or
TTrustBoundariesPackageQuery(TrustBoundariesQuery q) or
Expand Down Expand Up @@ -290,6 +292,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isStringsQueryMetadata(query, queryId, ruleId, category) or
isTemplatesQueryMetadata(query, queryId, ruleId, category) or
isToolchainQueryMetadata(query, queryId, ruleId, category) or
isToolchain2QueryMetadata(query, queryId, ruleId, category) or
isToolchain3QueryMetadata(query, queryId, ruleId, category) or
isTrigraphQueryMetadata(query, queryId, ruleId, category) or
isTrustBoundariesQueryMetadata(query, queryId, ruleId, category) or
Expand Down
26 changes: 26 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Toolchain2.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype Toolchain2Query = TCompilerLanguageExtensionsUsedQuery()

predicate isToolchain2QueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `compilerLanguageExtensionsUsed` query
Toolchain2Package::compilerLanguageExtensionsUsedQuery() and
queryId =
// `@id` for the `compilerLanguageExtensionsUsed` query
"cpp/misra/compiler-language-extensions-used" and
ruleId = "RULE-4-1-1" and
category = "required"
}

module Toolchain2Package {
Query compilerLanguageExtensionsUsedQuery() {
//autogenerate `Query` type
result =
// `Query` type for `compilerLanguageExtensionsUsed` query
TQueryCPP(TToolchain2PackageQuery(TCompilerLanguageExtensionsUsedQuery()))
}
}
14 changes: 14 additions & 0 deletions cpp/common/test/includes/standard-library/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ template <typename T, unsigned int N> struct remove_extent<T[N]> {
typedef T type;
};

template <typename T> struct is_abstract {
const static bool value = false;
constexpr operator bool() { return value; }
};

template <typename T> bool is_abstract_v = is_abstract<T>::value;

template <typename T, typename U> struct is_same {
const static bool value = false;
constexpr operator bool() { return value; }
};

template <typename T, typename U> bool is_same_v = is_same<T, U>::value;
Comment on lines +70 to +77
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new _v variable templates are defined as non-constexpr non-inline variables, but this same header uses inline constexpr for other _v templates (for example is_literal_type_v). Update is_abstract_v/is_same_v to follow the same pattern to avoid ODR/linkage issues and keep the stub consistent.

Suggested change
template <typename T> bool is_abstract_v = is_abstract<T>::value;
template <typename T, typename U> struct is_same {
const static bool value = false;
constexpr operator bool() { return value; }
};
template <typename T, typename U> bool is_same_v = is_same<T, U>::value;
template <typename T>
inline constexpr bool is_abstract_v = is_abstract<T>::value;
template <typename T, typename U> struct is_same {
const static bool value = false;
constexpr operator bool() { return value; }
};
template <typename T, typename U>
inline constexpr bool is_same_v = is_same<T, U>::value;

Copilot uses AI. Check for mistakes.

template <class T> struct is_trivially_copy_constructible {
const static bool value = true;
constexpr operator bool() { return value; }
Expand Down
27 changes: 27 additions & 0 deletions cpp/misra/src/rules/RULE-4-1-1/CompilerLanguageExtensionsUsed.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @id cpp/misra/compiler-language-extensions-used
* @name RULE-4-1-1: A program shall conform to ISO/IEC 14882:2017 (C++17)
* @description Language extensions are compiler-specific features that are not part of the C++17
* standard. Using these extensions reduces portability and may lead to unpredictable
* behavior when code is compiled with different compilers or compiler versions.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-4-1-1
* scope/system
* maintainability
* portability
* external/misra/enforcement/undecidable
* external/misra/obligation/required
*/

import cpp
import codingstandards.cpp.misra
import codingstandards.cpp.Extensions
import codingstandards.cpp.AlertReporting

from Element unwrapped, CPPCompilerExtension e
where
not isExcluded([e, unwrapped], Toolchain2Package::compilerLanguageExtensionsUsedQuery()) and
unwrapped = MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e)
select unwrapped, e.getMessage()
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
| test.cpp:11:3:11:19 | maybe_unused | Use of attribute 'maybe_unused' in namespace 'gnu' is a compiler extension and is not portable to other compilers. |
| test.cpp:12:16:12:22 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. |
| test.cpp:13:16:13:21 | unused | Use of attribute 'unused' is a compiler extension and is not portable to other compilers. |
| test.cpp:14:21:14:28 | noreturn | Use of attribute 'noreturn' is a compiler extension and is not portable to other compilers. |
| test.cpp:15:3:15:17 | deprecated | Use of attribute 'deprecated' in namespace 'gnu' is a compiler extension and is not portable to other compilers. |
| test.cpp:16:3:16:23 | nonstandard_attribute | Use of unrecognized or non-C++17 attribute 'nonstandard_attribute'. |
| test.cpp:19:3:19:20 | call to __builtin_popcount | Call to builtin function '__builtin_popcount' is a compiler extension and is not portable to other compilers. |
| test.cpp:20:3:20:18 | call to __builtin_expect | Call to builtin function '__builtin_expect' is a compiler extension and is not portable to other compilers. |
| test.cpp:21:3:21:22 | call to __sync_fetch_and_add_4 | Call to builtin function '__sync_fetch_and_add_4' is a compiler extension and is not portable to other compilers. |
| test.cpp:23:3:23:20 | __is_abstract | Use of built-in operation '__is_abstract' is a compiler extension. |
| test.cpp:24:3:24:22 | __is_same | Use of built-in operation '__is_same' is a compiler extension. |
| test.cpp:30:3:33:4 | (statement expression) | Statement expressions are a compiler extension and are not portable to other compilers. |
| test.cpp:34:3:34:12 | ... ? ... : ... | Ternaries with omitted middle operands are a compiler extension and are not portable to other compilers. |
| test.cpp:36:12:36:13 | definition of l0 | Declaration 'l0' uses type '__int128' which is a compiler extension and is not portable to other compilers. |
| test.cpp:45:20:45:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. |
| test.cpp:47:7:47:22 | fallthrough | Use of attribute 'fallthrough' in namespace 'gnu' is a compiler extension and is not portable to other compilers. |
| test.cpp:55:3:55:29 | __builtin_va_start | Use of built-in operation '__builtin_va_start' is a compiler extension. |
| test.cpp:60:7:60:8 | definition of m1 | Variable 'm1' is declared with a zero-length array (of 'int') is a compiler extension and are not portable to other compilers. |
| test.cpp:64:31:64:41 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. |
| test.cpp:66:1:66:20 | #ifdef __has_builtin | Call to builtin preprocessor feature '__has_builtin' is a compiler extension and is not portable to other compilers. |
| test.cpp:72:1:72:12 | #pragma once | Use of non-standard preprocessor directive '#pragma once' is a compiler extension. |
| test.cpp:73:1:73:27 | #pragma GCC diagnostic push | Use of non-standard preprocessor directive '#pragma GCC diagnostic push' is a compiler extension. |
| test.cpp:74:1:74:28 | #warning "This is a warning" | Use of non-standard preprocessor directive '#warning' is a compiler extension. |
| test.cpp:76:1:76:41 | #warning "preceeding spaces is common" | Use of non-standard preprocessor directive '#warning' is a compiler extension. |
| test.cpp:81:7:81:7 | VLA declaration | Variable length array (used in 'VLA declaration') are a compiler extension and are not portable to other compilers. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-4-1-1/CompilerLanguageExtensionsUsed.ql
Loading
Loading