-
Notifications
You must be signed in to change notification settings - Fork 77
Initial implementation of rule 4-1-1, must be standard C++17 #1106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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() { | ||
| not this instanceof CppNamespacedStdAttributeExtension and | ||
| not getName() in [ | ||
| "maybe_unused", "nodiscard", "noreturn", "deprecated", "carries_dependency", "fallthrough" | ||
| ] | ||
| } | ||
|
Comment on lines
+46
to
+52
|
||
|
|
||
| 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
|
||
| } | ||
|
|
||
| /** | ||
| * 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 |
|---|---|---|
| @@ -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())) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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
|
||||||||||||||||||||||||||||||||||||||
| 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; |
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CppNamespacedStdAttributeExtension/CppUnrecognizedAttributeExtensionuse a differentCpp...prefix than the rest of the newly introducedCPP...extension classes in this module. Align the naming (for example, consistently useCPP...) so the API is easier to discover and search.