diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp --- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -25,6 +25,7 @@ #include "../misc/StaticAssertCheck.h" #include "../misc/ThrowByValueCatchByReferenceCheck.h" #include "../performance/MoveConstructorInitCheck.h" +#include "../portability/NonPortableIntegerConstantCheck.h" #include "../readability/UppercaseLiteralSuffixCheck.h" #include "CommandProcessorCheck.h" #include "DefaultOperatorNewAlignmentCheck.h" @@ -302,6 +303,9 @@ "cert-flp37-c"); // FIO CheckFactories.registerCheck("cert-fio38-c"); + // INT + CheckFactories.registerCheck( + "cert-int17-c"); // MSC CheckFactories.registerCheck( "cert-msc24-c"); diff --git a/clang-tools-extra/clang-tidy/cert/CMakeLists.txt b/clang-tools-extra/clang-tidy/cert/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/cert/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cert/CMakeLists.txt @@ -27,6 +27,7 @@ clangTidyGoogleModule clangTidyMiscModule clangTidyPerformanceModule + clangTidyPortabilityModule clangTidyReadabilityModule clangTidyUtils diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt @@ -5,6 +5,7 @@ ) add_clang_library(clangTidyPortabilityModule + NonPortableIntegerConstantCheck.cpp PortabilityTidyModule.cpp RestrictSystemIncludesCheck.cpp SIMDIntrinsicsCheck.cpp diff --git a/clang-tools-extra/clang-tidy/portability/NonPortableIntegerConstantCheck.h b/clang-tools-extra/clang-tidy/portability/NonPortableIntegerConstantCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/NonPortableIntegerConstantCheck.h @@ -0,0 +1,30 @@ +//===--- NonPortableIntegerConstantCheck.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_NON_PORTABLE_INTEGER_CONSTANT_CHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_NON_PORTABLE_INTEGER_CONSTANT_CHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::portability { + +/// Finds integer literals that are being used in a non-portable manner. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/portability/non-portable-integer-constant.html +class NonPortableIntegerConstantCheck : public ClangTidyCheck { +public: + NonPortableIntegerConstantCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::portability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_NON_PORTABLE_INTEGER_CONSTANT_CHECK_H diff --git a/clang-tools-extra/clang-tidy/portability/NonPortableIntegerConstantCheck.cpp b/clang-tools-extra/clang-tidy/portability/NonPortableIntegerConstantCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/NonPortableIntegerConstantCheck.cpp @@ -0,0 +1,166 @@ +//===--- NonPortableIntegerConstantCheck.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 "NonPortableIntegerConstantCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { +namespace { + +struct SanitizedLiteralType { + StringRef StrippedLiteral; + // The exact bit value of the MSB. + std::size_t MSBBit; + // The bit value of MSB rounded up to the nearest byte. + std::size_t MSBByte; + std::size_t Radix; +}; + +} // namespace + +// Does not calculate true MSB - only takes the value of the first digit into +// account alongside the total digit count. Returns MSB zero if radix is 10, and +// MSBBit zero if first digit is 0. +static SanitizedLiteralType sanitizeAndCountBits(std::string &IntegerLiteral) { + llvm::erase_value(IntegerLiteral, '\''); // Skip digit separators. + StringRef StrippedLiteral{IntegerLiteral}; + + const auto MSBBit = [&StrippedLiteral](std::size_t RemainingBitCount) + -> std::size_t { + char FirstDigit = StrippedLiteral.front(); + + if (FirstDigit == '0') { + return 0; + } else if (FirstDigit <= '1') { + return RemainingBitCount + 1; + } else if (FirstDigit <= '3') { + return RemainingBitCount + 2; + } else if (FirstDigit <= '7') { + return RemainingBitCount + 3; + } else { + return RemainingBitCount + 4; + } + }; + + if(StrippedLiteral.consume_front("0b")) + { + StrippedLiteral = StrippedLiteral.take_while( + [](char c){return c == '0' || c == '1'; }); + assert(!StrippedLiteral.empty()); + + return { StrippedLiteral, + MSBBit(StrippedLiteral.size() - 1), + StrippedLiteral.size(), + 2 }; + } + else if(StrippedLiteral.consume_front("0x")) + { + StrippedLiteral = StrippedLiteral.take_while(llvm::isHexDigit); + assert(!StrippedLiteral.empty()); + + return { StrippedLiteral, + MSBBit((StrippedLiteral.size() - 1) * 4), + StrippedLiteral.size() * 4, + 16 }; + } + else if(StrippedLiteral != "0" && StrippedLiteral.consume_front("0")) + { + StrippedLiteral = StrippedLiteral.take_while( + [](char c){ return c >= '0' || c <= '7'; }); + assert(!StrippedLiteral.empty()); + + return { StrippedLiteral, + MSBBit((StrippedLiteral.size() - 1) * 3), + StrippedLiteral.size() * 3, + 8 }; + } else { + return { StrippedLiteral, 0, 0, 10 }; + } +} + +void NonPortableIntegerConstantCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(integerLiteral().bind("integer"), this); +} + + +void NonPortableIntegerConstantCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *MatchedInt = Result.Nodes.getNodeAs("integer"); + + assert(MatchedInt); + + QualType IntegerLiteralType = MatchedInt->getType(); + auto LiteralBitWidth = Result.Context->getTypeSize( IntegerLiteralType ); + + llvm::APInt LiteralValue = MatchedInt->getValue(); + + std::string LiteralStr = + Lexer::getSourceText( + CharSourceRange::getTokenRange(MatchedInt->getSourceRange()), + *Result.SourceManager, Result.Context->getLangOpts(), nullptr) + .lower(); + + // FIXME: There are two problematic cases where we cannot read the character. + // With macros, in some cases (such as when not passing an argument) the + // integer literal's token range will be 0 long. + if (LiteralStr.empty()) + return; + // A template function with an integer literal template argument will warn in + // both the argument, and the function body. In the instantiated body, the + // source range will contain the argument name, not the literal. + // FIXME: This disables checking macro literals entirely. + if (!llvm::isDigit(LiteralStr[0])) + return; + + const SanitizedLiteralType SanitizedLiteral = sanitizeAndCountBits(LiteralStr); + + // Only potential edge case is "0", handled by sanitizeAndCountBits. + assert(!SanitizedLiteral.StrippedLiteral.empty() && + "integer literal should not be empty"); + + assert(SanitizedLiteral.MSBBit <= LiteralBitWidth && + "integer literal has more bits set than its bit width"); + + bool IsMax = LiteralValue.isMaxValue() || LiteralValue.isMaxSignedValue(); + bool IsUnsignedMaxMinusOne = (LiteralValue + 1).isMaxValue(); + bool IsMin = LiteralValue.isMinValue() || LiteralValue.isMinSignedValue(); + bool RepresentsZero = LiteralValue.isNullValue(); + + bool IsMSBBitUsed = SanitizedLiteral.MSBBit == LiteralBitWidth; + // Can be greater, eg. an 8-bit UCHAR_MAX byte value represented by 377 octal + bool IsMSBByteUsed = SanitizedLiteral.MSBByte >= LiteralBitWidth; + bool HasLeadingZeroes = SanitizedLiteral.StrippedLiteral[0] == '0'; + + if (IsMax || IsUnsignedMaxMinusOne) { + diag(MatchedInt->getBeginLoc(), + "non-portable integer literal: hardcoded platform-specific maximum value"); + } else if (IsMin && !RepresentsZero) { + diag(MatchedInt->getBeginLoc(), + "non-portable integer literal: hardcoded platform-specific minimum value"); + } else if (HasLeadingZeroes && !RepresentsZero) { + diag(MatchedInt->getBeginLoc(), + "non-portable integer literal: integer literal with leading zeroes"); + // Matches only the most significant bit, + // eg. unsigned value 0x80000000. + } else if (IsMSBBitUsed) { + diag(MatchedInt->getBeginLoc(), + "non-portable integer literal: should not rely on the most significant bit"); + // Matches the most significant byte, + // eg. literals like 0x30000000. + } else if (IsMSBByteUsed) { + diag(MatchedInt->getBeginLoc(), + "non-portable integer literal: should not rely on bits of most significant byte"); + } +} + +} // namespace clang::tidy::portability diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp --- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "NonPortableIntegerConstantCheck.h" #include "RestrictSystemIncludesCheck.h" #include "SIMDIntrinsicsCheck.h" #include "StdAllocatorConstCheck.h" @@ -19,6 +20,8 @@ class PortabilityModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "portability-non-portable-integer-constant"); CheckFactories.registerCheck( "portability-restrict-system-includes"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -133,6 +133,16 @@ Checks that all implicit and explicit inline functions in header files are tagged with the ``LIBC_INLINE`` macro. +- New :doc:`portability-non-portable-integer-constant + ` check. + + Finds masks that are being used in a non-portable manner. + +- New :doc:`portability-non-portable-integer-constant + ` check. + + Finds integer literals that are being used in a non-portable manner. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/int17-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/int17-c.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cert/int17-c.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - cert-int17-c +.. meta:: + :http-equiv=refresh: 5;URL=../portability/non-portable-integer-constant.html + +cert-int17-c +============ + +The cert-int17-c check is an alias, please see +`portability-non-portable-integer-constant <../portability/non-portable-integer-constant.html>`_ +for more information. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -152,6 +152,7 @@ `cert-err58-cpp `_, `cert-err60-cpp `_, `cert-flp30-c `_, + `cert-int17-c `_, `cert-mem57-cpp `_, `cert-msc50-cpp `_, `cert-msc51-cpp `_, @@ -327,6 +328,7 @@ `performance-type-promotion-in-math-fn `_, "Yes" `performance-unnecessary-copy-initialization `_, "Yes" `performance-unnecessary-value-param `_, "Yes" + `portability-non-portable-integer-constant `_, `portability-restrict-system-includes `_, "Yes" `portability-simd-intrinsics `_, `portability-std-allocator-const `_, diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/non-portable-integer-constant.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/non-portable-integer-constant.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/non-portable-integer-constant.rst @@ -0,0 +1,40 @@ +.. title:: clang-tidy - portability-non-portable-integer-constant + +portability-non-portable-integer-constant +====================================== + +`cert-int17-c` redirects here as an alias for this check. + +Finds integer literals that are being used in a non-portable manner. + +Currently the check detects cases where maximum or minimum values should be used +instead, as well as error-prone integer literals having leading zeroes, or +relying on the most significant bits. + +This check corresponds to CERT C Coding Standard rule `INT17-C. Define integer +constants in an implementation-independent manner +`_. + +.. code-block:: c + + unsigned long flip_bits(unsigned long x) { + return x ^ 0xFFFFFFFF; + // The right way to write this would be ULONG_MAX, or -1. + } + +.. code-block:: c++ + + const unsigned long mask = 0b1000'0000'0000'0000'0000'0000'0000'0000; // warn + // The right way to write this would be ~(ULONG_MAX >> 1). + unsigned long x; + + x &= mask; + +.. code-block:: c++ + + const unsigned long bit_to_set = 0x00010000; // warn + // Incorrectly assumes that long is 4 bytes. + + unsigned long set_bit(unsigned long x) { + return x | bit_to_set; + } diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/non-portable-integer-constant.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/non-portable-integer-constant.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/non-portable-integer-constant.cpp @@ -0,0 +1,258 @@ +// RUN: %check_clang_tidy %s -std=c++17-or-later portability-non-portable-integer-constant %t + +using int32_t = decltype(42); + +void regular() { + // no-warnings + 0; + 00; + 0x0; + 0x00; + 0b0; + 0b00; + 0b0'0'0; + + -1; + -0X1; + + 127; + 0x7'f; + + -128; + -0x80; + + 256; + 0X100; + + 42; + 0x2A; + + 180079837; + 0xabbccdd; + + // FIXME: (only 31 bits) False positive, reported as max signed int. + 0b1111111111111111111111111111111; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + // FIXME: Large numbers represented as hex are the most common false positive, + // eg. the following literal is a 64-bit prime. + 0xff51afd7ed558ccd; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: should not rely on the most significant bit [portability-non-portable-integer-constant] + + // FIXME: Fixed-size integer literals are a common false positive as well. + int32_t literal = 0x40000000; + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: non-portable integer literal: should not rely on bits of most significant byte [portability-non-portable-integer-constant] + + // FIXME: According to the standard, the type of the integer literal is the + // smallest type it can fit into. While technically a false positive, it could + // signal literal width confusion regardless. + long long int long_literal = 0x7fffffff; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] +} + +enum LiteralClamp { + +}; + +// INT_MIN, INT_MAX, UINT_MAX, UINT_MAX-1 +// All binary literals are 32 bits long +void limits_int() { + // FIXME: not recognize as Min + -214748'3'648; + // --CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + -0x80'00'00'00; + // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + -020000000000; + // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + -0b10000000000000000000000000000000; + // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + + + 21474'83647; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0x7FFFFFFF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 017777777777; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 429'4'96'7295u; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0xFFFFFFFF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 037777777777; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0B11111111111111111111111111111111; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 4294967294; // recognized as long ( Not UINT_MAX-1) + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0XFFFFFFFE; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 037777777776; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0B11111111111111111111111111111110; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] +} + +// LLONG_MIN, LLONG_MAX, ULLONG_MAX, ULLONG_MAX-1 +// Most binary literals are 64 bits long +void limits_llong() { + -9'22337203'6854775808LL; + // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + 0x8000000000000000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + 01000000000000000000000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + 0b1000000000000000000000000000000000000000000000000000000000000000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + + 9223372036854775807; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0x7FFFFFFFFFFFFFFF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0777777777777777777777; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + // 63 bits + 0b111111111111111111111111111111111111111111111111111111111111111; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 18446744073709551615llU; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0xFFFFFFFFFFFFFFFF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 01777777777777777777777; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0b1111111111111111111111111111111111111111111111111111111111111111; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 18446744073709551614llU; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0xFFFFFFFFFFFFFFFe; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 01777777777777777777776; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + 0b1111111111111111111111111111111111111111111111111111111111111110; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] +} + +void full_patterns() { + 0x7F'FF'FF'FF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + -0x80'00'00'00; + // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + 0xFFFFFFFFu; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + 0xFF'FF'FF'Fe; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + + + 0x7F'FF'FFFFFFFFFFFF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] + -0x80'0000000000000'0LL; + // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: non-portable integer literal: hardcoded platform-specific minimum value [portability-non-portable-integer-constant] + 0XFFffFFFffFFFFFFFllU; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: hardcoded platform-specific maximum value [portability-non-portable-integer-constant] +} + +void most_significant_bits() { + 0x80004000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: should not rely on the most significant bit [portability-non-portable-integer-constant] + + 0xAFFFFFFF; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: should not rely on the most significant bit [portability-non-portable-integer-constant] + + 0x10000000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: should not rely on bits of most significant byte [portability-non-portable-integer-constant] + + 0x3000200010004000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: should not rely on bits of most significant byte [portability-non-portable-integer-constant] + + 0x00001000; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: integer literal with leading zeroes [portability-non-portable-integer-constant] + + // In some cases, an integer literal represents a smaller type than its + // bitcount, which caused issues with MSBBit detection. + 0x0000000000000001; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal: integer literal with leading zeroes [portability-non-portable-integer-constant] +} + +template bool template_unused_reported() { return I < 0x7FFFFFFF; } +// CHECK-MESSAGES: :[[@LINE-1]]:63: warning: non-portable integer literal + +template bool template_arg_not_reported() { return I < 0x7FFFFFFF; } +// CHECK-MESSAGES: :[[@LINE-1]]:64: warning: non-portable integer literal +// CHECK-MESSAGES-NOT: :[[@LINE-2]]:60: warning: non-portable integer literal + +template bool template_default_reported() { return I < 0; } +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: non-portable integer literal +// CHECK-MESSAGES-NOT: :[[@LINE-2]]:74: warning: non-portable integer literal + +void templates() { + // Should be reported only at the callsite. + template_arg_not_reported<0x7FFFFFFF>(); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: non-portable integer literal + + template_default_reported(); + + // Do not report same literal twice. + template_default_reported<0>(); +} + +// FIXME: Macros are currently not distinguished from the template arguments. +void macros() { +#define FULL_LITERAL 0x0100000000000000 + FULL_LITERAL; + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal + // --CHECK-MESSAGES: :[[@LINE-3]]:22: note: expanded from macro + +#define PARTIAL_LITERAL(start) start##00000000 + PARTIAL_LITERAL(0x01000000); + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal + // --CHECK-MESSAGES: :[[@LINE-3]]:32: note: expanded from macro + + // FIXME: In this case, the integer literal token is 0 long due to a tokenizer issue. +#define EMPTY_ARGUMENT(start) start##0x0100000000000000 + EMPTY_ARGUMENT(); + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal + // --CHECK-MESSAGES: :[[@LINE-3]]:38: note: expanded from macro + + // The following literals could be detected without reading the text representation. +#define MAX_VALUE_LITERAL 0x7FFFFFFF + MAX_VALUE_LITERAL; + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal + // --CHECK-MESSAGES: :[[@LINE-3]]:22: note: expanded from macro + +#define MAX_VALUE_PARTIAL_LITERAL(start) start##FFFF + MAX_VALUE_PARTIAL_LITERAL(0x7FFF); + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal + // --CHECK-MESSAGES: :[[@LINE-3]]:32: note: expanded from macro + +#define MAX_VALUE_EMPTY_ARGUMENT(start) start##0x7FFFFFFF + MAX_VALUE_EMPTY_ARGUMENT(); + // --CHECK-MESSAGES: :[[@LINE-1]]:3: warning: non-portable integer literal + // --CHECK-MESSAGES: :[[@LINE-3]]:38: note: expanded from macro +}