[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
jj-marr wrote: I'm still working on this. It seems like I broke the assertion tests. I'm unsure why, but it should be fixed if I figure out a better way of evaluating the macro. https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr converted_to_draft https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 >From d06c5ab5c30e535893335af798df339b0e9c6878 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH] Explain which assertion failed during consteval --- .../clang/Basic/DiagnosticSemaKinds.td| 2 ++ clang/lib/AST/ExprConstant.cpp| 11 ++ clang/test/SemaCXX/consteval-assert.cpp | 20 +++ 3 files changed, 33 insertions(+) create mode 100644 clang/test/SemaCXX/consteval-assert.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 4c96142e28134..58f32066f5da5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -162,6 +162,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed in constant evaluation: '%0'">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f2e49b9ea669e..3467a4d71acd5 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8409,6 +8409,17 @@ class ExprEvaluatorBase return false; } +// If an assertion fails during constant evaluation, give a specific note explaining that +if (FD->getName() == "__assert_fail") { + const Expr *AssertionExpr = E->getArg(0); + const StringLiteral *AssertionText = dyn_cast(AssertionExpr->IgnoreParens()->IgnoreParenImpCasts()); + + Info.FFDiag(E->getBeginLoc(), diag::note_constexpr_assert_failed) + << (AssertionText ? AssertionText->getString() : ""); + + return false; +} + SmallVector CovariantAdjustmentPath; if (This) { auto *NamedMember = dyn_cast(FD); diff --git a/clang/test/SemaCXX/consteval-assert.cpp b/clang/test/SemaCXX/consteval-assert.cpp new file mode 100644 index 0..d253db2a3ddde --- /dev/null +++ b/clang/test/SemaCXX/consteval-assert.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif +extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + +#define assert(cond) \ + ((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed in constant evaluation: 'result == 42'}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expected-error {{call to consteval function 'square' is not a constant expression}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr created https://github.com/llvm/llvm-project/pull/130458 Take this piece of code: ```cpp #include consteval int square(int x) { int result = x * x; assert(result == 42); return result; } void test() { auto val = square(2); } ``` The assertion will fail, and `clang++` will output (https://godbolt.org/z/hjz3KbTTv): ```cpp :10:14: error: call to consteval function 'square' is not a constant expression 10 | auto val = square(2); | ^ :5:3: note: non-constexpr function '__assert_fail' cannot be used in a constant expression 5 | assert(result == 42); | ^ /usr/include/assert.h:95:9: note: expanded from macro 'assert' 95 | : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) | ^ :10:14: note: in call to 'square(2)' 10 | auto val = square(2); | ^ /usr/include/assert.h:69:13: note: declared here 69 | extern void __assert_fail (const char *__assertion, const char *__file, | ^ 1 error generated. Compiler returned: 1 ``` This is confusing because it implies that the issue was using an assertion in a constant-evaluted context, and not that the assertion failed (`assert()` is OK in constant evaluation). This PR changes the error message to: ```cpp test.cpp:10:14: error: call to consteval function 'square' is not a constant expression 10 | auto val = square(2); | ^ test.cpp:5:3: note: assertion failed in consteval context: 'result == 42' 5 | assert(result == 42); | ^ /nix/store/lw21wr626v5sdcaxxkv2k4zf1121hfc9-glibc-2.40-36-dev/include/assert.h:102:9: note: expanded from macro 'assert' 102 | : __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE, \ | ^ test.cpp:10:14: note: in call to 'square(2)' 10 | auto val = square(2); | ^ 1 error generated.``` >From 8a09c78d3fdb151c86785822da6cb451025b4654 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH 1/2] Explain which assertion failed during consteval --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/AST/ExprConstant.cpp | 11 +++ 2 files changed, 13 insertions(+) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 21be7c358a61d..ff5f88d6ac572 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -107,6 +107,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed in consteval context: '%0'">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d9a1e5bb42343..7013f0b143a0a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8361,6 +8361,17 @@ class ExprEvaluatorBase return false; } +// If an assertion fails during constant evaluation, give a specific note explaining that +if (FD->getName() == "__assert_fail") { + const Expr *AssertionExpr = E->getArg(0); + const StringLiteral *AssertionText = dyn_cast(AssertionExpr->IgnoreParens()->IgnoreParenImpCasts()); + + Info.FFDiag(E->getBeginLoc(), diag::note_constexpr_assert_failed) + << (AssertionText ? AssertionText->getString() : ""); + + return false; +} + SmallVector CovariantAdjustmentPath; if (This) { auto *NamedMember = dyn_cast(FD); >From c8fe23e62a6a0090ef050a3ca3ac9abe549b0aa6 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:36:26 -0500 Subject: [PATCH 2/2] Add unit test --- clang/test/SemaCXX/consteval_assert.cpp | 20 1 file changed, 20 insertions(+) create mode 100644 clang/test/SemaCXX/consteval_assert.cpp diff --git a/clang/test/SemaCXX/consteval_assert.cpp b/clang/test/SemaCXX/consteval_assert.cpp new file mode 100644 index 0..94ca9ffd4888d --- /dev/null +++ b/clang/test/SemaCXX/consteval_assert.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif +extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + +#define assert(cond) \ + ((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed in consteval context: 'result == 42'}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expec
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 >From d61892d8546944000118ad0312886da75cd6509b Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH] Explain which assertion failed during consteval --- .../clang/Basic/DiagnosticSemaKinds.td| 2 ++ clang/lib/AST/ExprConstant.cpp| 11 ++ clang/test/SemaCXX/consteval_assert.cpp | 20 +++ 3 files changed, 33 insertions(+) create mode 100644 clang/test/SemaCXX/consteval_assert.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 21be7c358a61d..ff5f88d6ac572 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -107,6 +107,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed in consteval context: '%0'">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d9a1e5bb42343..7013f0b143a0a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8361,6 +8361,17 @@ class ExprEvaluatorBase return false; } +// If an assertion fails during constant evaluation, give a specific note explaining that +if (FD->getName() == "__assert_fail") { + const Expr *AssertionExpr = E->getArg(0); + const StringLiteral *AssertionText = dyn_cast(AssertionExpr->IgnoreParens()->IgnoreParenImpCasts()); + + Info.FFDiag(E->getBeginLoc(), diag::note_constexpr_assert_failed) + << (AssertionText ? AssertionText->getString() : ""); + + return false; +} + SmallVector CovariantAdjustmentPath; if (This) { auto *NamedMember = dyn_cast(FD); diff --git a/clang/test/SemaCXX/consteval_assert.cpp b/clang/test/SemaCXX/consteval_assert.cpp new file mode 100644 index 0..94ca9ffd4888d --- /dev/null +++ b/clang/test/SemaCXX/consteval_assert.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif +extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + +#define assert(cond) \ + ((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed in consteval context: 'result == 42'}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expected-error {{call to consteval function 'square' is not a constant expression}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
@@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif +extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + +#define assert(cond) \ + ((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed in consteval context: 'result == 42'}} jj-marr wrote: Perhaps it should say "during constant evaluation". Both `constexpr` and `consteval` functions can be constant evaluated (i.e. evaluated at compile-time), but it's also possible for a `constexpr` function to be used at runtime, in which case the assertion would _not_ be triggered. https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 >From 0cba377eb8693657b7688cd1feb1cc9c5734f307 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH] Explain which assertion failed during consteval --- .../clang/Basic/DiagnosticSemaKinds.td| 2 ++ clang/lib/AST/ExprConstant.cpp| 11 ++ clang/test/SemaCXX/consteval_assert.cpp | 20 +++ 3 files changed, 33 insertions(+) create mode 100644 clang/test/SemaCXX/consteval_assert.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 21be7c358a61d..0c8ee08117058 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -107,6 +107,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed in constant evaluation: '%0'">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d9a1e5bb42343..7013f0b143a0a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8361,6 +8361,17 @@ class ExprEvaluatorBase return false; } +// If an assertion fails during constant evaluation, give a specific note explaining that +if (FD->getName() == "__assert_fail") { + const Expr *AssertionExpr = E->getArg(0); + const StringLiteral *AssertionText = dyn_cast(AssertionExpr->IgnoreParens()->IgnoreParenImpCasts()); + + Info.FFDiag(E->getBeginLoc(), diag::note_constexpr_assert_failed) + << (AssertionText ? AssertionText->getString() : ""); + + return false; +} + SmallVector CovariantAdjustmentPath; if (This) { auto *NamedMember = dyn_cast(FD); diff --git a/clang/test/SemaCXX/consteval_assert.cpp b/clang/test/SemaCXX/consteval_assert.cpp new file mode 100644 index 0..d253db2a3ddde --- /dev/null +++ b/clang/test/SemaCXX/consteval_assert.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif +extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + +#define assert(cond) \ + ((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed in constant evaluation: 'result == 42'}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expected-error {{call to consteval function 'square' is not a constant expression}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr ready_for_review https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 >From 3b6d28e4f74c1fda73abe3b5972d5ac2a43576de Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH] Explain which assertion failed during consteval --- clang/docs/ReleaseNotes.rst | 4 +++ .../clang/Basic/DiagnosticSemaKinds.td| 2 ++ clang/lib/AST/ExprConstant.cpp| 10 -- clang/test/SemaCXX/consteval-assert.cpp | 34 +++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/consteval-assert.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index eb2e8f2b8a6c0..4c719ebc19221 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -419,6 +419,10 @@ Improvements to Clang's diagnostics - ``-Winitializer-overrides`` and ``-Wreorder-init-list`` are now grouped under the ``-Wc99-designator`` diagnostic group, as they also are about the behavior of the C99 feature as it was introduced into C++20. Fixes #GH47037 + +- Explanatory note is printed when ``assert`` fails during evaluation of a + constant expression. Prior to this, the error inaccurately implied that assert + could not be used at all in a constant expression (#GH130458) Improvements to Clang's time-trace -- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 4c96142e28134..87e982e9c491c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -162,6 +162,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed during evaluation of constant expression">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f2e49b9ea669e..3ee355d6570ed 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5975,9 +5975,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Definition->hasAttr( return true; - if (Info.getLangOpts().CPlusPlus11) { -const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + if (CallLoc.isMacroID() && (DiagDecl->getName() == "__assert_rtn" || + DiagDecl->getName() == "__assert_fail" || + DiagDecl->getName() == "_wassert")) { +Info.FFDiag(CallLoc, diag::note_constexpr_assert_failed); +return false; + } + if (Info.getLangOpts().CPlusPlus11) { // If this function is not constexpr because it is an inherited // non-constexpr constructor, diagnose that directly. auto *CD = dyn_cast(DiagDecl); diff --git a/clang/test/SemaCXX/consteval-assert.cpp b/clang/test/SemaCXX/consteval-assert.cpp new file mode 100644 index 0..b54a38ff26105 --- /dev/null +++ b/clang/test/SemaCXX/consteval-assert.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_LINUX %s +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_WINDOWS %s +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_DARWIN %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif + +#if defined(TEST_LINUX) + extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + #define assert(cond) \ +((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) +#elif defined(TEST_DARWIN) + void __assert_rtn(const char *, const char *, int, const char *); + #define assert(cond) \ + (__builtin_expect(!(cond), 0) ? __assert_rtn(__func__, __FILE__, __LINE__, #cond) : (void)0) +#elif defined(TEST_WINDOWS) + void /*__cdecl*/ _wassert(const wchar_t*, const wchar_t*, unsigned); + #define _CRT_WIDE_(s) L ## s + #define _CRT_WIDE(s) _CRT_WIDE_(s) + #define assert(cond) \ +(void)((!!(cond)) || (_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0)) +#endif + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed during evaluation of constant expression}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expected-error {{call to consteval function 'square' is not a constant expression}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
@@ -5975,9 +5975,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Definition->hasAttr( return true; - if (Info.getLangOpts().CPlusPlus11) { -const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + if (CallLoc.isMacroID() && (DiagDecl->getName() == "__assert_rtn" || jj-marr wrote: Done for both. https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
jj-marr wrote: > LGTM modulo nit. > > Are you happy with the current state? @cor3ntin @Sirraide Shouldn't CI be passing? I can't figure out why there are failures. https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
@@ -5975,9 +5975,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Definition->hasAttr( return true; - if (Info.getLangOpts().CPlusPlus11) { -const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + if (CallLoc.isMacroID() && (DiagDecl->getName() == "__assert_rtn" || jj-marr wrote: I have no idea how to improve this, otherwise I'd do it. How would I get access to the preprocessor from here? https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
@@ -5975,9 +5975,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Definition->hasAttr( return true; - if (Info.getLangOpts().CPlusPlus11) { -const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + // Special note for the assert() macro, as the normal error message falsely + // implies we cannot use an assertion during constant evaluation. + if (CallLoc.isMacroID() && DiagDecl->getIdentifier()) { +// FIXME: Instead of checking for an implementation-defined function, +// check and evaluate the assert() macro. jj-marr wrote: I have no idea how to access the preprocessor from this method and I am too inexperienced to know where to start. If you can give me a hint on where to look I would appreciate that. Do I just do a big refactor and pass it in as a parameter to the function? Or is there some method on an object I already have? https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 >From 64eb62576dc1ecf0e696f2448e410c2fd77575de Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH] Explain which assertion failed during consteval --- clang/docs/ReleaseNotes.rst | 4 +++ .../clang/Basic/DiagnosticSemaKinds.td| 2 ++ clang/lib/AST/ExprConstant.cpp| 17 -- clang/test/SemaCXX/consteval-assert.cpp | 34 +++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/consteval-assert.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2c3c75b88a9fe..01a4f96404681 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -523,6 +523,10 @@ Improvements to Clang's diagnostics - An error is now emitted when OpenMP ``collapse`` and ``ordered`` clauses have an argument larger than what can fit within a 64-bit integer. + +- Explanatory note is printed when ``assert`` fails during evaluation of a + constant expression. Prior to this, the error inaccurately implied that assert + could not be used at all in a constant expression (#GH130458) Improvements to Clang's time-trace -- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3efe9593b8633..a84f84b4653de 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -164,6 +164,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed during evaluation of constant expression">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 500d43accb082..c09afef9c4bf9 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5975,9 +5975,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Definition->hasAttr( return true; - if (Info.getLangOpts().CPlusPlus11) { -const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + // Special note for the assert() macro, as the normal error message falsely + // implies we cannot use an assertion during constant evaluation. + if (CallLoc.isMacroID() && DiagDecl->getIdentifier()) { +// FIXME: Instead of checking for an implementation-defined function, +// check and evaluate the assert() macro. +StringRef Name = DiagDecl->getName(); +bool AssertFailed = +Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert"; +if (AssertFailed) { + Info.FFDiag(CallLoc, diag::note_constexpr_assert_failed); + return false; +} + } + if (Info.getLangOpts().CPlusPlus11) { // If this function is not constexpr because it is an inherited // non-constexpr constructor, diagnose that directly. auto *CD = dyn_cast(DiagDecl); diff --git a/clang/test/SemaCXX/consteval-assert.cpp b/clang/test/SemaCXX/consteval-assert.cpp new file mode 100644 index 0..b54a38ff26105 --- /dev/null +++ b/clang/test/SemaCXX/consteval-assert.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_LINUX %s +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_WINDOWS %s +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_DARWIN %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif + +#if defined(TEST_LINUX) + extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + #define assert(cond) \ +((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) +#elif defined(TEST_DARWIN) + void __assert_rtn(const char *, const char *, int, const char *); + #define assert(cond) \ + (__builtin_expect(!(cond), 0) ? __assert_rtn(__func__, __FILE__, __LINE__, #cond) : (void)0) +#elif defined(TEST_WINDOWS) + void /*__cdecl*/ _wassert(const wchar_t*, const wchar_t*, unsigned); + #define _CRT_WIDE_(s) L ## s + #define _CRT_WIDE(s) _CRT_WIDE_(s) + #define assert(cond) \ +(void)((!!(cond)) || (_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0)) +#endif + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed during evaluation of constant expression}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expected-error {{call
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 >From 67984fbf0374fa40fd7b73431b17baddc301290f Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 8 Mar 2025 22:00:45 -0500 Subject: [PATCH] Explain which assertion failed during consteval --- clang/docs/ReleaseNotes.rst | 4 +++ .../clang/Basic/DiagnosticSemaKinds.td| 2 ++ clang/lib/AST/ExprConstant.cpp| 17 -- clang/test/SemaCXX/consteval-assert.cpp | 34 +++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/consteval-assert.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bc13d02e2d20b..6ff370004d6ab 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -523,6 +523,10 @@ Improvements to Clang's diagnostics - An error is now emitted when OpenMP ``collapse`` and ``ordered`` clauses have an argument larger than what can fit within a 64-bit integer. + +- Explanatory note is printed when ``assert`` fails during evaluation of a + constant expression. Prior to this, the error inaccurately implied that assert + could not be used at all in a constant expression (#GH130458) Improvements to Clang's time-trace -- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3efe9593b8633..a84f84b4653de 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -164,6 +164,8 @@ def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +def note_constexpr_assert_failed : Note< + "assertion failed during evaluation of constant expression">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 500d43accb082..c09afef9c4bf9 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5975,9 +5975,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Definition->hasAttr( return true; - if (Info.getLangOpts().CPlusPlus11) { -const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; + // Special note for the assert() macro, as the normal error message falsely + // implies we cannot use an assertion during constant evaluation. + if (CallLoc.isMacroID() && DiagDecl->getIdentifier()) { +// FIXME: Instead of checking for an implementation-defined function, +// check and evaluate the assert() macro. +StringRef Name = DiagDecl->getName(); +bool AssertFailed = +Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert"; +if (AssertFailed) { + Info.FFDiag(CallLoc, diag::note_constexpr_assert_failed); + return false; +} + } + if (Info.getLangOpts().CPlusPlus11) { // If this function is not constexpr because it is an inherited // non-constexpr constructor, diagnose that directly. auto *CD = dyn_cast(DiagDecl); diff --git a/clang/test/SemaCXX/consteval-assert.cpp b/clang/test/SemaCXX/consteval-assert.cpp new file mode 100644 index 0..b54a38ff26105 --- /dev/null +++ b/clang/test/SemaCXX/consteval-assert.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_LINUX %s +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_WINDOWS %s +// RUN: %clang_cc1 -std=c++23 -verify=expected,cxx20_plus -DTEST_DARWIN %s + +#ifdef __ASSERT_FUNCTION +#undef __ASSERT_FUNCTION +#endif + +#if defined(TEST_LINUX) + extern "C" void __assert_fail(const char*, const char*, unsigned, const char*); + #define assert(cond) \ +((cond) ? (void)0 : __assert_fail(#cond, __FILE__, __LINE__, __func__)) +#elif defined(TEST_DARWIN) + void __assert_rtn(const char *, const char *, int, const char *); + #define assert(cond) \ + (__builtin_expect(!(cond), 0) ? __assert_rtn(__func__, __FILE__, __LINE__, #cond) : (void)0) +#elif defined(TEST_WINDOWS) + void /*__cdecl*/ _wassert(const wchar_t*, const wchar_t*, unsigned); + #define _CRT_WIDE_(s) L ## s + #define _CRT_WIDE(s) _CRT_WIDE_(s) + #define assert(cond) \ +(void)((!!(cond)) || (_wassert(_CRT_WIDE(#cond), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0)) +#endif + +consteval int square(int x) { + int result = x * x; + assert(result == 42); // expected-note {{assertion failed during evaluation of constant expression}} + return result; +} + +void test() { + auto val = square(2); // expected-note {{in call to 'square(2)'}} \ + // expected-error {{call
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/130458 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
jj-marr wrote: > @jj-marr Thanks. Do you want us to merge that for you? Is it something I can actually do myself? https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Better diagnostics when assertion fails in `consteval` (PR #130458)
jj-marr wrote: OK, merge whenever. https://github.com/llvm/llvm-project/pull/130458 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add modernize-use-span linter check (PR #140001)
jj-marr wrote: Thinking more, this is not a good check at this time. https://github.com/llvm/llvm-project/pull/140001 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add modernize-use-span linter check (PR #140001)
https://github.com/jj-marr closed https://github.com/llvm/llvm-project/pull/140001 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add modernize-use-span linter check (PR #140001)
jj-marr wrote: `std::span` has a capability gap with a const reference to a `std::vector` until C++26 as `std::span` cannot be constructed from an initializer list. Should this be a C++26 check? https://github.com/llvm/llvm-project/pull/140001 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][bytecode] Diagnose failed constexpr assertions differently (PR #140000)
@@ -851,6 +851,19 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { if (F->isLambdaStaticInvoker()) return true; + // Diagnose failed assertions specially. + if (S.Current->getLocation(OpPC).isMacroID() && + F->getDecl()->getIdentifier()) { +StringRef Name = F->getDecl()->getName(); +bool AssertFailed = +Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert"; jj-marr wrote: I actually want to fix it at some point since I wrote the original code. My skillset is bad though which is why I couldn't figure it out. I'll make the GitHub issue and assign it to myself. https://github.com/llvm/llvm-project/pull/14 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][bytecode] Diagnose failed constexpr assertions differently (PR #140000)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/14 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
jj-marr wrote: @vbvictor It makes sense to provide an autofix for `float`/`double`, since I have never heard of them being anything other than IEEE754 32-bit binary floats or IEEE754 64-bit binary floats respectively. `char8_t` will always be `unsigned char` so a fix from `unsigned char` to `char8_t` could make sense as well. Is an autofix from `char` or `signed char` to `char8_t` is a good idea? https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/146970 >From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 1/6] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++ .../AvoidFundamentalIntegerTypesCheck.h | 46 + .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: +return true; + default: +return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); + + // Match function declarations with fundamental integer return types + Finder->addMatcher( + functionDecl().bind("func_decl"), + this); + + // Match function parameters with fundamental integer types + Finder->addMatcher( + parmVarDecl().bind("param_decl"), + this); + + // Match field declarations with fundamental integer types + Finder->addMatcher( + fieldDecl().bind("field_decl"), + this); + + // Match typedef declarations if not ignoring them + if (!IgnoreTypedefs) { +Finder->addMatcher( +typedefDecl().bind("typedef_decl"), +this); + +Finder->addMatcher( +typeAliasDecl().bind("alias_decl"), +this); + } +} + +void AvoidFundamentalIntegerTypesCheck::check( +const MatchFinder::MatchResult &Result) { + SourceLocation Loc; + QualType QT; + std::string DeclType; + + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { +Loc = VD->getLocation(); +QT = VD->getType(); +DeclType = "variable"; +
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/146970 >From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 1/8] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++ .../AvoidFundamentalIntegerTypesCheck.h | 46 + .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: +return true; + default: +return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); + + // Match function declarations with fundamental integer return types + Finder->addMatcher( + functionDecl().bind("func_decl"), + this); + + // Match function parameters with fundamental integer types + Finder->addMatcher( + parmVarDecl().bind("param_decl"), + this); + + // Match field declarations with fundamental integer types + Finder->addMatcher( + fieldDecl().bind("field_decl"), + this); + + // Match typedef declarations if not ignoring them + if (!IgnoreTypedefs) { +Finder->addMatcher( +typedefDecl().bind("typedef_decl"), +this); + +Finder->addMatcher( +typeAliasDecl().bind("alias_decl"), +this); + } +} + +void AvoidFundamentalIntegerTypesCheck::check( +const MatchFinder::MatchResult &Result) { + SourceLocation Loc; + QualType QT; + std::string DeclType; + + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { +Loc = VD->getLocation(); +QT = VD->getType(); +DeclType = "variable"; +
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,181 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context) {} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: +return true; + default: +return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); jj-marr wrote: Done. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/146970 >From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 1/9] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++ .../AvoidFundamentalIntegerTypesCheck.h | 46 + .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: +return true; + default: +return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); + + // Match function declarations with fundamental integer return types + Finder->addMatcher( + functionDecl().bind("func_decl"), + this); + + // Match function parameters with fundamental integer types + Finder->addMatcher( + parmVarDecl().bind("param_decl"), + this); + + // Match field declarations with fundamental integer types + Finder->addMatcher( + fieldDecl().bind("field_decl"), + this); + + // Match typedef declarations if not ignoring them + if (!IgnoreTypedefs) { +Finder->addMatcher( +typedefDecl().bind("typedef_decl"), +this); + +Finder->addMatcher( +typeAliasDecl().bind("alias_decl"), +this); + } +} + +void AvoidFundamentalIntegerTypesCheck::check( +const MatchFinder::MatchResult &Result) { + SourceLocation Loc; + QualType QT; + std::string DeclType; + + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { +Loc = VD->getLocation(); +QT = VD->getType(); +DeclType = "variable"; +
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
jj-marr wrote: I will add the `float` component of the check tomorrow. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/146970 >From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 01/10] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++ .../AvoidFundamentalIntegerTypesCheck.h | 46 + .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: +return true; + default: +return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); + + // Match function declarations with fundamental integer return types + Finder->addMatcher( + functionDecl().bind("func_decl"), + this); + + // Match function parameters with fundamental integer types + Finder->addMatcher( + parmVarDecl().bind("param_decl"), + this); + + // Match field declarations with fundamental integer types + Finder->addMatcher( + fieldDecl().bind("field_decl"), + this); + + // Match typedef declarations if not ignoring them + if (!IgnoreTypedefs) { +Finder->addMatcher( +typedefDecl().bind("typedef_decl"), +this); + +Finder->addMatcher( +typeAliasDecl().bind("alias_decl"), +this); + } +} + +void AvoidFundamentalIntegerTypesCheck::check( +const MatchFinder::MatchResult &Result) { + SourceLocation Loc; + QualType QT; + std::string DeclType; + + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { +Loc = VD->getLocation(); +QT = VD->getType(); +DeclType = "variable"; +
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/146970 >From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 01/14] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++ .../AvoidFundamentalIntegerTypesCheck.h | 46 + .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: +return true; + default: +return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); + + // Match function declarations with fundamental integer return types + Finder->addMatcher( + functionDecl().bind("func_decl"), + this); + + // Match function parameters with fundamental integer types + Finder->addMatcher( + parmVarDecl().bind("param_decl"), + this); + + // Match field declarations with fundamental integer types + Finder->addMatcher( + fieldDecl().bind("field_decl"), + this); + + // Match typedef declarations if not ignoring them + if (!IgnoreTypedefs) { +Finder->addMatcher( +typedefDecl().bind("typedef_decl"), +this); + +Finder->addMatcher( +typeAliasDecl().bind("alias_decl"), +this); + } +} + +void AvoidFundamentalIntegerTypesCheck::check( +const MatchFinder::MatchResult &Result) { + SourceLocation Loc; + QualType QT; + std::string DeclType; + + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { +Loc = VD->getLocation(); +QT = VD->getType(); +DeclType = "variable"; +
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,43 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy ---*- C++ +//-*-===// jj-marr wrote: Done. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,111 @@ +.. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types + +portability-avoid-platform-specific-fundamental-types += + +Finds fundamental types and recommends using typedefs or fixed-width types instead. + +This check detects fundamental integer types (``int``, ``short``, ``long``, ``long long``, and their +``unsigned`` variants) and warns against their use due to non-standard platform-dependent behavior. +For example, ``long`` is 64 bits on Linux but 32 bits on Windows. There is no standard rationale or +intent for the sizes of these types. + +Instead of fundamental types, use fixed-width types such as ``int32_t`` or implementation-defined +types with standard semantics, e.g. ``int_fast32_t`` for the fastest integer type greater than or jj-marr wrote: Done locally. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
jj-marr wrote: > Have you looked at google-runtime-int? It should be doing the same thing > (maybe small differences) I haven't before now. I still think a new check is necessary. `google-runtime-int` isn't as strict because it is coupled to the Google coding guidelines. That means it doesn't flag `int`, `float`, `double`, etc. That behaviour shouldn't change as Google's coding guidelines explicitly recommend using `int` for loop counters as well as `float`, `double` for IEEE754 floats. This check will encompass usage of almost all fundamental types that are implementation-defined, including `float`, `double`, `int`, and (potentially) `char`. The main exception is `bool` because it doesn't suffer from the same overflow issues as other types. This is a significant change and goes against Google's coding guidelines. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,43 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy ---*- C++ +//-*-===// jj-marr wrote: This requires turning off `clang-format` since line 1 is too long. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
jj-marr wrote: > You could make a universal option to configure autofixes. Make > semicolon-separated list of key-value pairs, e.g. > `int=int32_t;float=float32_t;char=char8_t`. User could specify any type he > wants, and remove/add fixes for `int`, `char` and so on. > > By default, we could even put fixes for all common types and let the user > delete/modify what doesn't like. This is a good idea but even the basic configuration I wanted to do adds a lot of scope to the PR. Autofix for `float` is implemented because it's easy to figure out w/o much ambiguity. Float/double/etc means "I want IEEE754" most of the time, with the only exception being `bfloat16`. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,246 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { + +AvoidPlatformSpecificFundamentalTypesCheck:: +AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", false)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( +const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( +const BuiltinType *BT, ASTContext &Context) const { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { +switch (Width) { +// This is ambiguous by default since it could be bfloat16 or float16 +case 16U: + return ""; +case 32U: + return "float32_t"; +case 64U: + return "float64_t"; +case 128U: + return "float128_t"; +default: + return ""; +} + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: +return "bfloat16_t"; + case BuiltinType::Half: +return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: +return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: +return GetReplacementType(Target.getDoubleWidth()); + default: +return ""; + } +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( +MatchFinder *Finder) { + // Build the list of type strings to match + std::vector TypeStrings = {"short", + "short int", + "signed short", + "signed short int", + "unsigned short", + "unsigned short int", + "int", + "signed", + "signed int", + "unsigned", + "unsigned int", + "long", + "long int", + "signed long", + "signed long int", + "unsigned long", + "unsigned long int", + "long long", + "long long int", + "signed long long", + "signed long long int", + "unsigned long long", + "unsigned long long int"}; + + // Add float types if the option is enabled + if (WarnOnFloats) { +TypeStrings.push_back("half"); +TypeStrings.push_back("__bf16"); +TypeStrings.push_back("float"); +TypeStrings.push_back("double"); +TypeStrings.push_back("long double"); + } + + // Create the matcher dynamically + auto TypeMatcher = asString(TypeStrings[0]); + for (size_t i = 1; i < TypeStrings.size(); ++i) { +TypeMatcher = anyOf(TypeMatcher, asString(TypeStrings[i])); + } + + auto PlatformSpecificFundamentalType = qualType(allOf( + // Must be a builtin type directly (not through typedef) + builtinType(), + // Match the specific fundamental types we care about + TypeMatcher)); + + // Match variable declarations with platform-specific fundamental types + Finder->addMatcher( + varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), this); + + // Match function declarations
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr commented: comments for myself https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
https://github.com/jj-marr edited https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,246 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { + +AvoidPlatformSpecificFundamentalTypesCheck:: +AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", false)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( +const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( +const BuiltinType *BT, ASTContext &Context) const { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { +switch (Width) { +// This is ambiguous by default since it could be bfloat16 or float16 +case 16U: + return ""; +case 32U: + return "float32_t"; +case 64U: + return "float64_t"; +case 128U: + return "float128_t"; +default: + return ""; +} + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: +return "bfloat16_t"; + case BuiltinType::Half: +return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: +return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: +return GetReplacementType(Target.getDoubleWidth()); + default: +return ""; + } +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( +MatchFinder *Finder) { + // Build the list of type strings to match + std::vector TypeStrings = {"short", jj-marr wrote: warn on int should also be a config option. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,260 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { + +AvoidPlatformSpecificFundamentalTypesCheck:: +AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", true)), + WarnOnInts(Options.get("WarnOnInts", true)), + WarnOnChars(Options.get("WarnOnChars", true)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( +const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "WarnOnInts", WarnOnInts); + Options.store(Opts, "WarnOnChars", WarnOnChars); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( +const BuiltinType *BT, ASTContext &Context) const { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { +switch (Width) { +// This is ambiguous by default since it could be bfloat16 or float16 +case 16U: + return ""; +case 32U: + return "float32_t"; +case 64U: + return "float64_t"; +case 128U: + return "float128_t"; +default: + return ""; +} + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: +return "bfloat16_t"; + case BuiltinType::Half: +return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: +return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: +return GetReplacementType(Target.getDoubleWidth()); + default: +return ""; + } +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( +MatchFinder *Finder) { + // Build the list of type strings to match + std::vector TypeStrings; + + // Add integer types if the option is enabled + if (WarnOnInts) { +TypeStrings.insert(TypeStrings.end(), {"short", jj-marr wrote: This makes more sense. I was thinking I couldn't check the type itself because `typedef`s don't create a new type, but if it works for the Google check I suppose it'll work for this one. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
jj-marr wrote: > Please remove unnecessary comments that tell the same as code itself, > speaking mostly about comments in `registerMatchers`. They mostly don't give > any more information that matchers themselves. To be honest, this is because I coded 98% of this with AI (except for the `.rst` documentation text which I mostly wrote myself). I am still getting used to stripping out useless comments and also how `llvm`/compilers in general work. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,52 @@ +//==-- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//====// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/IncludeInserter.h" + +namespace clang::tidy::portability { + +/// Find fundamental platform-dependent types and recommend using typedefs or +/// fixed-width types. +/// +/// Detects fundamental types (int, short, long, long long, char, float, etc) +/// and warns against their use due to platform-dependent behavior. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.html +class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { +public: + AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context); + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { +return LangOpts.CPlusPlus11; + } + std::optional getCheckTraversalKind() const override { +return TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool WarnOnFloats; + const bool WarnOnInts; + const bool WarnOnChars; + utils::IncludeInserter IncludeInserter; + std::string getFloatReplacement(const BuiltinType *BT, + ASTContext &Context) const; jj-marr wrote: I'm used to having linters flag this (along with missed `const` declarations). https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add modernize-avoid-fundamental-integer-types (PR #146970)
https://github.com/jj-marr created https://github.com/llvm/llvm-project/pull/146970 The fundamental types are widely recognized to be flawed because they're of implementation-defined sizes without a common purpose. For example, `long int` is a footgun since its 32 bits on Windows and 64 bits on most 64-bit Unixes. On Windows, backwards compatibility has it frozen at 32 bits while on Unix, it is implementation-defined to be the processor's word size. To address this, C/C++ introduced the `stdint.h`/`cstdint` headers that provide standard types of a specific number of bits. The language also introduced implementation-defined types such as `size_t` or `int_fast32_t`, which unlike `int`, have a clear specification of intent in the standard and can change size based on standardized aspects of the implementation (maximum size of objects, "fastest" type). TODO: - [ ] Decide whether to provide an autofix. I have chosen not to, because it will depend on the context one is using a type in. - [ ] Decide whether `char` should be linted. I have chosen not to lint `char` by default because it can be used to convey "1 byte" regardless of the size of the byte. However, I might add this as an option defaulted to "Yes", because on virtually every platform people actually use C++20/C23 on, `char` can be safely replaced with `char8_t` as 1 byte is 8 bits. -- If [P3477](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3477r5.html) is adopted, `CHAR_BIT=8` on all conforming C++ implementations. - [ ] Decide whether `float` and `double` should be linted in favour of [stdfloat types](https://en.cppreference.com/w/cpp/types/floating-point.html) or whether this should be a separate check. >From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 1/3] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++ .../AvoidFundamentalIntegerTypesCheck.h | 46 + .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +StringRef Name, ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->getAs(); + if (!BT) +return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: +return true; + default: +return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) +return false; + + const auto *BT = T->get
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,100 @@ +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: true}]}" -header-filter=.* -- -std=c++23 + +// Mock fixed-width float types +// In reality, these types are aliases to "extended floating point types", and +// are not typedefs. However, there isn't a good way to mock extended floats as +// they are not fundamental types. +// NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) +typedef float float32_t; +typedef double float64_t; +// NOLINTEND(portability-avoid-platform-specific-fundamental-types) + +// Test floating point types that should trigger warnings when WarnOnFloats is enabled +float global_float = 3.14f; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] +// CHECK-FIXES: float32_t global_float = 3.14f; jj-marr wrote: Not done. I want to make this another check, maybe "`readability-inconsistent-literal-suffix`". https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,190 @@ +.. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types + +portability-avoid-platform-specific-fundamental-types += + +Finds fundamental types (e.g. `int`, `float`) and recommends using typedefs +or fixed-width types instead to improve portability across different platforms. + +This check detects fundamental types (``int``, ``short``, ``long``, ``float``, +``char`` and their ``unsigned`` or ``signed`` variants) and warns against their +use due to non-standard platform-dependent behavior. For example, ``long`` is +64 bits on Linux but 32 bits on Windows. There is no standard rationale or +intent for the sizes of these types. + +Instead of fundamental types, use fixed-width types such as ``int32_t`` or +implementation-defined types with standard semantics, e.g. ``int_fast32_t`` for +the fastest integer type greater than or equal to 32 bits. + +Examples + + +.. code-block:: c++ + + // Bad: platform-dependent fundamental types + int global_int = 42; + short global_short = 10; + long global_long = 100L; + unsigned long global_unsigned_long = 100UL; + + void function_with_int_param(int param) { +// ... + } + + int function_returning_int() { +return 42; + } + + struct MyStruct { +int member_int; +long member_long; + }; + +.. code-block:: c++ + + // Good: use fixed-width types or typedefs + #include + + int32_t global_int32 = 42; + int16_t global_int16 = 10; + int64_t global_int64 = 100L; + uint64_t global_uint64 = 100UL; + + void function_with_int32_param(int32_t param) { +// ... + } + + int32_t function_returning_int32() { +return 42; + } + + struct MyStruct { +int32_t member_int32; +int64_t member_int64; + }; + +The check will also warn about typedef declarations that use fundamental types +as their underlying type: + +.. code-block:: c++ + + // Bad: typedef using fundamental type + typedef long long MyLongType; + using MyIntType = int; + +.. code-block:: c++ + + // Good: use descriptive names or fixed-width types + typedef int64_t TimestampType; + using CounterType = uint32_t; + +Rationale +- + +Fundamental types have platform-dependent sizes and behavior: + +- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be + 16 bits by the spec +- ``long int`` is 32 bits on Windows but 64 bits on most Unix systems +- ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU (e.g. certain Arduinos) it can be 32 bits +- ``char`` is signed on ARM and unsigned on x86 + +The C++ specification does not define these types beyond their minimum sizes. +That means they can communicate intent in non-standard ways and are often +needlessly incompatible. For example, ``int``was traditionally the word size of +a given processor in 16-bit and 32-bit computing and was a reasonable default +for performance. This is no longer true on modern 64-bit computers, but the +size of ``int`` remains fixed at 32 bits for backwards compatibility with code +that relied on a 32-bit implementation of ``int``. + +If code is explicitly relying on the size of an ``int`` being 32 bits, it is +better to say so in the typename with ``int32_t``. Otherwise, use an +appropriate implementation-defined type such as ``fast_int32_t`` or +``least_int32_t`` that communicates the appropriate time/space tradeoff. + +Likewise, ``float`` and ``double`` should be replaced by ``float32_t`` and +``float64_t`` which are guaranteed to be standard IEEE754 floats for a given +size. + +``char`` should be replaced by ``char8_t`` when used in the representation of +Unicode text. When used to represent a byte on a given platform, ``std::byte`` +is an appropriate replacement. + +Types Not Flagged +- + +The following types are intentionally not flagged: + +- ``bool`` (boolean type) +- Standard library typedefs like ``size_t``, ``ptrdiff_t``, or ``uint32_t``. +- Already typedef'd types, though the check will flag the typedef itself + +``bool`` is excluded because it can only be true or false, and is not vulnerable to overflow or +narrowing issues that occur as a result of using implementation-defined types. + +Options +--- + +.. option:: WarnOnFloats + + When `true`, the check will warn about floating point types (``float`` and ``double``). + When `false` (default), floating point types are not flagged. + + Floating point types can have platform-dependent behavior: + + - ``float`` is typically 32-bit IEEE754, but can vary on some platforms + - ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU it can be 32 bits + + When this option is enabled, the check will suggest using ``float32_t`` and ``float64_t`` + instead of ``float`` and ``double`` respectively, when the target platform supports + standard IEEE754 sizes. + +
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,190 @@ +.. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types + +portability-avoid-platform-specific-fundamental-types += + +Finds fundamental types (e.g. `int`, `float`) and recommends using typedefs +or fixed-width types instead to improve portability across different platforms. + +This check detects fundamental types (``int``, ``short``, ``long``, ``float``, +``char`` and their ``unsigned`` or ``signed`` variants) and warns against their +use due to non-standard platform-dependent behavior. For example, ``long`` is +64 bits on Linux but 32 bits on Windows. There is no standard rationale or +intent for the sizes of these types. + +Instead of fundamental types, use fixed-width types such as ``int32_t`` or +implementation-defined types with standard semantics, e.g. ``int_fast32_t`` for +the fastest integer type greater than or equal to 32 bits. + +Examples + + +.. code-block:: c++ + + // Bad: platform-dependent fundamental types + int global_int = 42; + short global_short = 10; + long global_long = 100L; + unsigned long global_unsigned_long = 100UL; + + void function_with_int_param(int param) { +// ... + } + + int function_returning_int() { +return 42; + } + + struct MyStruct { +int member_int; +long member_long; + }; + +.. code-block:: c++ + + // Good: use fixed-width types or typedefs + #include + + int32_t global_int32 = 42; + int16_t global_int16 = 10; + int64_t global_int64 = 100L; + uint64_t global_uint64 = 100UL; + + void function_with_int32_param(int32_t param) { +// ... + } + + int32_t function_returning_int32() { +return 42; + } + + struct MyStruct { +int32_t member_int32; +int64_t member_int64; + }; + +The check will also warn about typedef declarations that use fundamental types +as their underlying type: + +.. code-block:: c++ + + // Bad: typedef using fundamental type + typedef long long MyLongType; + using MyIntType = int; + +.. code-block:: c++ + + // Good: use descriptive names or fixed-width types + typedef int64_t TimestampType; + using CounterType = uint32_t; + +Rationale +- + +Fundamental types have platform-dependent sizes and behavior: + +- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be + 16 bits by the spec +- ``long int`` is 32 bits on Windows but 64 bits on most Unix systems +- ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU (e.g. certain Arduinos) it can be 32 bits +- ``char`` is signed on ARM and unsigned on x86 + +The C++ specification does not define these types beyond their minimum sizes. +That means they can communicate intent in non-standard ways and are often +needlessly incompatible. For example, ``int``was traditionally the word size of +a given processor in 16-bit and 32-bit computing and was a reasonable default +for performance. This is no longer true on modern 64-bit computers, but the +size of ``int`` remains fixed at 32 bits for backwards compatibility with code +that relied on a 32-bit implementation of ``int``. + +If code is explicitly relying on the size of an ``int`` being 32 bits, it is +better to say so in the typename with ``int32_t``. Otherwise, use an +appropriate implementation-defined type such as ``fast_int32_t`` or +``least_int32_t`` that communicates the appropriate time/space tradeoff. + +Likewise, ``float`` and ``double`` should be replaced by ``float32_t`` and +``float64_t`` which are guaranteed to be standard IEEE754 floats for a given +size. + +``char`` should be replaced by ``char8_t`` when used in the representation of +Unicode text. When used to represent a byte on a given platform, ``std::byte`` +is an appropriate replacement. + +Types Not Flagged +- + +The following types are intentionally not flagged: + +- ``bool`` (boolean type) +- Standard library typedefs like ``size_t``, ``ptrdiff_t``, or ``uint32_t``. +- Already typedef'd types, though the check will flag the typedef itself + +``bool`` is excluded because it can only be true or false, and is not vulnerable to overflow or +narrowing issues that occur as a result of using implementation-defined types. + +Options jj-marr wrote: no WarnOnInt option documentation https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,190 @@ +.. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types + +portability-avoid-platform-specific-fundamental-types += + +Finds fundamental types (e.g. `int`, `float`) and recommends using typedefs +or fixed-width types instead to improve portability across different platforms. + +This check detects fundamental types (``int``, ``short``, ``long``, ``float``, +``char`` and their ``unsigned`` or ``signed`` variants) and warns against their +use due to non-standard platform-dependent behavior. For example, ``long`` is +64 bits on Linux but 32 bits on Windows. There is no standard rationale or +intent for the sizes of these types. + +Instead of fundamental types, use fixed-width types such as ``int32_t`` or +implementation-defined types with standard semantics, e.g. ``int_fast32_t`` for +the fastest integer type greater than or equal to 32 bits. + +Examples + + +.. code-block:: c++ + + // Bad: platform-dependent fundamental types + int global_int = 42; + short global_short = 10; + long global_long = 100L; + unsigned long global_unsigned_long = 100UL; + + void function_with_int_param(int param) { +// ... + } + + int function_returning_int() { +return 42; + } + + struct MyStruct { +int member_int; +long member_long; + }; + +.. code-block:: c++ + + // Good: use fixed-width types or typedefs + #include + + int32_t global_int32 = 42; + int16_t global_int16 = 10; + int64_t global_int64 = 100L; + uint64_t global_uint64 = 100UL; + + void function_with_int32_param(int32_t param) { +// ... + } + + int32_t function_returning_int32() { +return 42; + } + + struct MyStruct { +int32_t member_int32; +int64_t member_int64; + }; + +The check will also warn about typedef declarations that use fundamental types +as their underlying type: + +.. code-block:: c++ + + // Bad: typedef using fundamental type + typedef long long MyLongType; + using MyIntType = int; + +.. code-block:: c++ + + // Good: use descriptive names or fixed-width types + typedef int64_t TimestampType; + using CounterType = uint32_t; + +Rationale +- + +Fundamental types have platform-dependent sizes and behavior: + +- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be + 16 bits by the spec +- ``long int`` is 32 bits on Windows but 64 bits on most Unix systems +- ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU (e.g. certain Arduinos) it can be 32 bits +- ``char`` is signed on ARM and unsigned on x86 + +The C++ specification does not define these types beyond their minimum sizes. +That means they can communicate intent in non-standard ways and are often +needlessly incompatible. For example, ``int``was traditionally the word size of +a given processor in 16-bit and 32-bit computing and was a reasonable default +for performance. This is no longer true on modern 64-bit computers, but the +size of ``int`` remains fixed at 32 bits for backwards compatibility with code +that relied on a 32-bit implementation of ``int``. + +If code is explicitly relying on the size of an ``int`` being 32 bits, it is +better to say so in the typename with ``int32_t``. Otherwise, use an +appropriate implementation-defined type such as ``fast_int32_t`` or +``least_int32_t`` that communicates the appropriate time/space tradeoff. + +Likewise, ``float`` and ``double`` should be replaced by ``float32_t`` and +``float64_t`` which are guaranteed to be standard IEEE754 floats for a given +size. + +``char`` should be replaced by ``char8_t`` when used in the representation of +Unicode text. When used to represent a byte on a given platform, ``std::byte`` +is an appropriate replacement. + +Types Not Flagged +- + +The following types are intentionally not flagged: + +- ``bool`` (boolean type) +- Standard library typedefs like ``size_t``, ``ptrdiff_t``, or ``uint32_t``. +- Already typedef'd types, though the check will flag the typedef itself + +``bool`` is excluded because it can only be true or false, and is not vulnerable to overflow or +narrowing issues that occur as a result of using implementation-defined types. + +Options +--- + +.. option:: WarnOnFloats + + When `true`, the check will warn about floating point types (``float`` and ``double``). jj-marr wrote: should be true by default. Maybe only on C++23 and above? https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,63 @@ +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: true}]}" -header-filter=.* -- -std=c++11 jj-marr wrote: should also ensure that ints aren't linted when WarnOnChars on its own is enabled and the other two are disabled https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,100 @@ +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: true}]}" -header-filter=.* -- -std=c++23 + +// Mock fixed-width float types +// In reality, these types are aliases to "extended floating point types", and +// are not typedefs. However, there isn't a good way to mock extended floats as +// they are not fundamental types. +// NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) +typedef float float32_t; +typedef double float64_t; +// NOLINTEND(portability-avoid-platform-specific-fundamental-types) + +// Test floating point types that should trigger warnings when WarnOnFloats is enabled +float global_float = 3.14f; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] +// CHECK-FIXES: float32_t global_float = 3.14f; jj-marr wrote: this should change the suffixes too if they exist https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,190 @@ +.. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types + +portability-avoid-platform-specific-fundamental-types += + +Finds fundamental types (e.g. `int`, `float`) and recommends using typedefs +or fixed-width types instead to improve portability across different platforms. + +This check detects fundamental types (``int``, ``short``, ``long``, ``float``, +``char`` and their ``unsigned`` or ``signed`` variants) and warns against their +use due to non-standard platform-dependent behavior. For example, ``long`` is +64 bits on Linux but 32 bits on Windows. There is no standard rationale or +intent for the sizes of these types. + +Instead of fundamental types, use fixed-width types such as ``int32_t`` or +implementation-defined types with standard semantics, e.g. ``int_fast32_t`` for +the fastest integer type greater than or equal to 32 bits. + +Examples + + +.. code-block:: c++ + + // Bad: platform-dependent fundamental types + int global_int = 42; + short global_short = 10; + long global_long = 100L; + unsigned long global_unsigned_long = 100UL; + + void function_with_int_param(int param) { +// ... + } + + int function_returning_int() { +return 42; + } + + struct MyStruct { +int member_int; +long member_long; + }; + +.. code-block:: c++ + + // Good: use fixed-width types or typedefs + #include + + int32_t global_int32 = 42; + int16_t global_int16 = 10; + int64_t global_int64 = 100L; + uint64_t global_uint64 = 100UL; + + void function_with_int32_param(int32_t param) { +// ... + } + + int32_t function_returning_int32() { +return 42; + } + + struct MyStruct { +int32_t member_int32; +int64_t member_int64; + }; + +The check will also warn about typedef declarations that use fundamental types +as their underlying type: + +.. code-block:: c++ + + // Bad: typedef using fundamental type + typedef long long MyLongType; + using MyIntType = int; + +.. code-block:: c++ + + // Good: use descriptive names or fixed-width types + typedef int64_t TimestampType; + using CounterType = uint32_t; + +Rationale +- + +Fundamental types have platform-dependent sizes and behavior: + +- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be + 16 bits by the spec +- ``long int`` is 32 bits on Windows but 64 bits on most Unix systems +- ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU (e.g. certain Arduinos) it can be 32 bits +- ``char`` is signed on ARM and unsigned on x86 + +The C++ specification does not define these types beyond their minimum sizes. +That means they can communicate intent in non-standard ways and are often +needlessly incompatible. For example, ``int``was traditionally the word size of jj-marr wrote: Done. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,260 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { + +AvoidPlatformSpecificFundamentalTypesCheck:: +AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", false)), + WarnOnInts(Options.get("WarnOnInts", true)), + WarnOnChars(Options.get("WarnOnChars", false)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( +const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "WarnOnInts", WarnOnInts); + Options.store(Opts, "WarnOnChars", WarnOnChars); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( +const BuiltinType *BT, ASTContext &Context) const { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { +switch (Width) { +// This is ambiguous by default since it could be bfloat16 or float16 +case 16U: + return ""; +case 32U: + return "float32_t"; +case 64U: + return "float64_t"; +case 128U: + return "float128_t"; +default: + return ""; +} + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: +return "bfloat16_t"; + case BuiltinType::Half: +return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: +return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: +return GetReplacementType(Target.getDoubleWidth()); + default: +return ""; + } +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( +MatchFinder *Finder) { + // Build the list of type strings to match + std::vector TypeStrings; + + // Add integer types if the option is enabled + if (WarnOnInts) { +TypeStrings.insert(TypeStrings.end(), {"short", + "short int", + "signed short", + "signed short int", + "unsigned short", + "unsigned short int", + "int", + "signed", + "signed int", + "unsigned", + "unsigned int", + "long", + "long int", + "signed long", + "signed long int", + "unsigned long", + "unsigned long int", + "long long", + "long long int", + "signed long long", + "signed long long int", + "unsigned long long", + "unsigned long long int"}); + } + + // Add float types if the option is enabled + if (WarnOnFloats) { +TypeStrings.insert(TypeStrings.end(), + {"half", "__bf16", "float", "double", "long double"}); + } + + // Add char types if the option is enabled + if (WarnOnChars) { +TypeStrings.insert(TypeStrings.end(), + {"char", "signed char", "unsigned char"}); + } + + // If no types are enabled, return early + if (TypeStrings.empty()) { +return; + } + + // Create the matcher dynamically + auto TypeMatcher = asString(TypeStrings.front()); + for
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,54 @@ +// clang-format off +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===-===// +// clang-format on jj-marr wrote: Done. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,54 @@ +// clang-format off +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -*- C++ -*-===// jj-marr wrote: Done. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
jj-marr wrote: > Check makes sense to me! As a first iteration it's fine without autofix but I > can imagine it will be hard for a codebase to enable this check given the > large amount of things to fix. Maybe users can specify a mapping of wanted > types via an option? I'm planning for an autofix of `float` and `double` since it's unambiguous what those types should be. For `int` types, maybe I'll give 3 options for an autofix: * Fixed (`int32_t`) * Fast (`int_fast32_t`) * Least (`int_least32_t`) Based on sizeof the type when running `clang-tidy`. This represents compatibility/time/space tradeoffs. Not sure about `char`. If you're actually representing UTF-8 text, it's a good idea to replace with `char8_t`. If you're using `char` because it's 1 byte and you want to do wacky things with memory, `std::byte` is the way to go. I'm not sure how relatively common each is since I work with low-level hardware at my day job and I'm biased towards assuming weird byte level stuff is more common than it really is. It's also not a "safe" replacement to get rid of `char` in all cases, since `char8_t` and `std::byte` are always unsigned. If the memory representation of `char` is identical to `unsigned char` it's probably safe enough? https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add portability-avoid-platform-specific-fundamental-types (PR #146970)
@@ -0,0 +1,260 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { + +AvoidPlatformSpecificFundamentalTypesCheck:: +AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", true)), + WarnOnInts(Options.get("WarnOnInts", true)), + WarnOnChars(Options.get("WarnOnChars", true)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( +const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( +ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "WarnOnInts", WarnOnInts); + Options.store(Opts, "WarnOnChars", WarnOnChars); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( +const BuiltinType *BT, ASTContext &Context) const { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { +switch (Width) { +// This is ambiguous by default since it could be bfloat16 or float16 +case 16U: + return ""; +case 32U: + return "float32_t"; +case 64U: + return "float64_t"; +case 128U: + return "float128_t"; +default: + return ""; +} + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: +return "bfloat16_t"; + case BuiltinType::Half: +return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: +return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: +return GetReplacementType(Target.getDoubleWidth()); + default: +return ""; + } +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( +MatchFinder *Finder) { + // Build the list of type strings to match + std::vector TypeStrings; + + // Add integer types if the option is enabled + if (WarnOnInts) { +TypeStrings.insert(TypeStrings.end(), {"short", jj-marr wrote: > You don't need to worry about `unit32_t` because clang-tidy usually suppress > warning from system headers unless you explicitly use `--header-filter=*`. > Usually people don't care what warnings system headers have. If the warning triggers on `MyLong global_long = 100L; // Warning`, then it would also trigger when I use `uint32_t global_long = 100U`, no? Assuming it's triggered on use. I also don't see the purpose of having this case because there will already be a warning on `using MyLong = long;` If I want to silence the warning, I'd rather `NOLINT` it when I define the typedef rather than everywhere I use it. https://github.com/llvm/llvm-project/pull/146970 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits