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
214 changes: 213 additions & 1 deletion cpp/common/src/codingstandards/cpp/Extensions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,216 @@ abstract class CompilerExtension extends Locatable { }
/**
* Common base class for modeling compiler extensions in CPP.
*/
abstract class CPPCompilerExtension extends CompilerExtension { }
abstract class CPPCompilerExtension extends CompilerExtension {
abstract string getMessage();
}

/**
* 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.
*/
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."
}
}

/**
* An `Attribute` 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."
}
}

class CppUnrecognizedAttributeExtension extends CPPCompilerExtension, StdAttribute {
CppUnrecognizedAttributeExtension() {
Comment on lines +34 to +45
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 +44 to +50
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() + "'."
}
}

/**
* Compiler-specific builtin functions.
* 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."
}
}

/**
* Statement expressions: ({ ... }) syntax.
* 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."
}
}

/**
* Ternary expressions with omitted middle operand: 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 +93 to +96
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.
}

/**
* Extended integer types: __int128, etc.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/__int128.html
*/
class CPPExtendedIntegerTypeExtension extends CPPCompilerExtension, DeclarationEntry {
CPPExtendedIntegerTypeExtension() { getType() instanceof Int128Type }

override string getMessage() {
result = "128-bit integers are a compiler extension and are not portable to other compilers."
}
}

/**
* Extended floating-point types: __float128, _Decimal32, etc.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html
*/
class CPPExtendedFloatTypeExtension extends CPPCompilerExtension, DeclarationEntry {
CPPExtendedFloatTypeExtension() {
getType() instanceof Decimal128Type or
getType() instanceof Decimal32Type or
getType() instanceof Decimal64Type or
getType() instanceof Float128Type
}

override string getMessage() {
result =
"Extended floating-point types are a compiler extension and are not portable to other compilers."
}
}

/**
* Zero-length arrays (flexible array members must be last).
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
*/
class CPPZeroLengthArraysExtension extends CPPCompilerExtension, DeclarationEntry {
CPPZeroLengthArraysExtension() { getType().(ArrayType).getArraySize() = 0 }

override string getMessage() {
result = "Zero length arrays are a compiler extension and are not portable to other compilers."
}
}

/**
* Variable-length arrays in struct members (not C++17 compliant).
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
*/
class CPPVariableLengthArraysExtension extends CPPCompilerExtension, Field {
CPPVariableLengthArraysExtension() {
getType() instanceof ArrayType and
not getType().(ArrayType).hasArraySize() and
// Not the final member of the struct, which is allowed in some contexts
not exists(int lastIndex, Class declaringStruct |
declaringStruct = getDeclaringType() and
lastIndex = count(declaringStruct.getACanonicalMember()) - 1 and
this = declaringStruct.getCanonicalMember(lastIndex)
)
}

override string getMessage() {
result =
"Variable length arrays are a compiler extension and are not portable to other compilers."
}
}

/**
* __alignof__ operator (use alignof from C++11 instead).
*/
class CPPAlignofExtension extends CPPCompilerExtension, AlignofExprOperator {
CPPAlignofExtension() { exists(getValueText().indexOf("__alignof__")) }

override string getMessage() {
result = "'__alignof__' is a compiler extension and is not portable to other compilers."
}
}

/**
* Preprocessor extensions for feature detection.
* 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."
}
}

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."
}
}

/**
* Built-in type traits and operations such as `__is_abstract`, `__is_same`, 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
25 changes: 25 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,25 @@
/**
* @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 CPPCompilerExtension e
where not isExcluded(e, Toolchain2Package::compilerLanguageExtensionsUsedQuery())
select MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e), e.getMessage()
Comment on lines +23 to +25
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 query is currently reporting a result whose primary location is inside the test standard-library stub (includes/standard-library/stdarg.h), which leads to machine-specific absolute file:///... paths and makes the test not correspond to a NON_COMPLIANT marker in test.cpp. Consider adjusting the reporting element (or adding a filter) so results are reported in user/test source files and not in includes/standard-library stubs (for example, mirror the standard-library exclusion pattern used elsewhere in cpp/common/src/codingstandards/cpp/Macro.qll).

Suggested change
from CPPCompilerExtension e
where not isExcluded(e, Toolchain2Package::compilerLanguageExtensionsUsedQuery())
select MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e), e.getMessage()
from CPPCompilerExtension e, Element report
where
not isExcluded(e, Toolchain2Package::compilerLanguageExtensionsUsedQuery()) and
(
report = MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e) and
not isExcluded(report, Toolchain2Package::compilerLanguageExtensionsUsedQuery())
or
report = e and
isExcluded(
MacroUnwrapper<CPPCompilerExtension>::unwrapElement(e),
Toolchain2Package::compilerLanguageExtensionsUsedQuery()
)
)
select report, e.getMessage()

Copilot uses AI. Check for mistakes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
| file:///Users/michaelrfairhurst/projects/codeql-coding-standards/cpp/common/test/includes/standard-library/stdarg.h:5:1:5:47 | #define va_start(v,l) __builtin_va_start(v, l) | Use of built-in operation '__builtin_va_start' is a compiler extension. |
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.

This expected result refers to a machine-local absolute file:///... path under cpp/common/test/includes/standard-library/.... Expected files should not contain developer-specific absolute paths, and results should ideally be reported against the test source (test.cpp) rather than the standard-library stubs; update the query/reporting element so this row becomes stable (or remove it if the rule should not flag standard va_start).

Suggested change
| file:///Users/michaelrfairhurst/projects/codeql-coding-standards/cpp/common/test/includes/standard-library/stdarg.h:5:1:5:47 | #define va_start(v,l) __builtin_va_start(v, l) | Use of built-in operation '__builtin_va_start' is a compiler extension. |

Copilot uses AI. Check for mistakes.
| 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 | 128-bit integers are a compiler extension and are 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 | Zero length arrays are 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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-4-1-1/CompilerLanguageExtensionsUsed.ql
Loading
Loading