diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 84f5ab3443a59..50ec95225b7ba 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -438,6 +438,8 @@ LANGOPT(CXXAssumptions, 1, 1, NotCompatible, "Enable or disable codegen and comp LANGOPT(RawStringLiterals, 1, 1, NotCompatible, "Enable or disable raw string literals") +LANGOPT(AllowLiteralDigitSeparator, 1, 0, NotCompatible, "Allow literal digit seperator in source") + ENUM_LANGOPT(StrictFlexArraysLevel, StrictFlexArraysLevelKind, 2, StrictFlexArraysLevelKind::Default, NotCompatible, "Rely on strict definition of flexible arrays") diff --git a/clang/include/clang/Basic/LangStandard.h b/clang/include/clang/Basic/LangStandard.h index 49412232c9c5e..05294f2416da1 100644 --- a/clang/include/clang/Basic/LangStandard.h +++ b/clang/include/clang/Basic/LangStandard.h @@ -140,6 +140,9 @@ struct LangStandard { return isCPlusPlus11() || (!isCPlusPlus() && isC99() && isGNUMode()); } + /// allowLiteralDigitSeparator - Language supports literal digit seperator + bool allowLiteralDigitSeparator() const { return isCPlusPlus14() || isC23(); } + /// isGNUMode - Language includes GNU extensions. bool isGNUMode() const { return Flags & GNUMode; } diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index f034514466d3f..d55100202ee87 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -128,6 +128,7 @@ void LangOptions::setLangDefaults(LangOptions &Opts, Language Lang, Opts.WChar = Std.isCPlusPlus(); Opts.Digraphs = Std.hasDigraphs(); Opts.RawStringLiterals = Std.hasRawStringLiterals(); + Opts.AllowLiteralDigitSeparator = Std.allowLiteralDigitSeparator(); Opts.NamedLoops = Std.isC2y(); Opts.HLSL = Lang == Language::HLSL; diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index eee57c786442a..4d1502816f68a 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -74,6 +74,7 @@ struct Scanner { LangOpts.ObjC = true; LangOpts.LineComment = true; LangOpts.RawStringLiterals = true; + LangOpts.AllowLiteralDigitSeparator = true; // FIXME: we do not enable C11 or C++11, so we are missing u/u8/U"". return LangOpts; } diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index b282a600c0e56..1af4f6ca02ef4 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -2087,7 +2087,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { } // If we have a digit separator, continue. - if (C == '\'' && (LangOpts.CPlusPlus14 || LangOpts.C23)) { + if (C == '\'' && LangOpts.AllowLiteralDigitSeparator) { auto [Next, NextSize] = getCharAndSizeNoWarn(CurPtr + Size, LangOpts); if (isAsciiIdentifierContinue(Next)) { if (!isLexingRawMode()) diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index ddc87921ea084..dd8ef8daef816 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/DependencyDirectivesScanner.h" +#include "clang/Basic/TokenKinds.h" #include "llvm/ADT/SmallString.h" #include "gtest/gtest.h" @@ -1000,6 +1001,21 @@ int z = 128'78; EXPECT_STREQ("#include \n", Out.data()); } +TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralInPreprocessor) { + SmallVector Out; + SmallVector Tokens; + SmallVector Directives; + + StringRef Source = R"( + #if 1'2 == 12 + #endif + )"; + ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens, Directives)); + ASSERT_GE(Tokens.size(), 4u); + EXPECT_EQ(Tokens[2].Kind, tok::numeric_constant); + EXPECT_EQ(Tokens[3].Kind, tok::equalequal); +} + TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) { SmallVector Out; SmallVector Tokens;