summaryrefslogtreecommitdiff
path: root/clang/lib/Lex
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Lex
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'clang/lib/Lex')
-rw-r--r--clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp1
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp68
-rw-r--r--clang/lib/Lex/Lexer.cpp22
-rw-r--r--clang/lib/Lex/LiteralSupport.cpp111
-rw-r--r--clang/lib/Lex/ModuleMap.cpp71
-rw-r--r--clang/lib/Lex/PPCallbacks.cpp19
-rw-r--r--clang/lib/Lex/PPDirectives.cpp236
-rw-r--r--clang/lib/Lex/PPExpressions.cpp26
-rw-r--r--clang/lib/Lex/PPLexerChange.cpp9
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp6
-rw-r--r--clang/lib/Lex/Pragma.cpp70
-rw-r--r--clang/lib/Lex/Preprocessor.cpp36
-rw-r--r--clang/lib/Lex/TokenConcatenation.cpp4
13 files changed, 448 insertions, 231 deletions
diff --git a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
index 029bfe1cd6008..cdb4a79fa11a7 100644
--- a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
+++ b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/MemoryBuffer.h"
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index f0c5900c8ce45..1df28cc07209d 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -133,7 +133,7 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
void HeaderSearch::getHeaderMapFileNames(
SmallVectorImpl<std::string> &Names) const {
for (auto &HM : HeaderMaps)
- Names.push_back(HM.first->getName());
+ Names.push_back(std::string(HM.first->getName()));
}
std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
@@ -145,7 +145,7 @@ std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
bool FileMapOnly) {
// First check the module name to pcm file map.
- auto i (HSOpts->PrebuiltModuleFiles.find(ModuleName));
+ auto i(HSOpts->PrebuiltModuleFiles.find(ModuleName));
if (i != HSOpts->PrebuiltModuleFiles.end())
return i->second;
@@ -159,7 +159,7 @@ std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
llvm::sys::fs::make_absolute(Result);
llvm::sys::path::append(Result, ModuleName + ".pcm");
if (getFileMgr().getFile(Result.str()))
- return Result.str().str();
+ return std::string(Result);
}
return {};
}
@@ -184,7 +184,8 @@ std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName,
//
// To avoid false-negatives, we form as canonical a path as we can, and map
// to lower-case in case we're on a case-insensitive file system.
- std::string Parent = llvm::sys::path::parent_path(ModuleMapPath);
+ std::string Parent =
+ std::string(llvm::sys::path::parent_path(ModuleMapPath));
if (Parent.empty())
Parent = ".";
auto Dir = FileMgr.getDirectory(Parent);
@@ -468,7 +469,7 @@ getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
// If this is a framework directory, then we're a subframework of this
// framework.
if (llvm::sys::path::extension(DirName) == ".framework") {
- SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+ SubmodulePath.push_back(std::string(llvm::sys::path::stem(DirName)));
TopFrameworkDir = *Dir;
}
} while (true);
@@ -1218,9 +1219,11 @@ HeaderSearch::getExistingFileInfo(const FileEntry *FE,
}
bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
- // Check if we've ever seen this file as a header.
+ // Check if we've entered this file and found an include guard or #pragma
+ // once. Note that we dor't check for #import, because that's not a property
+ // of the file itself.
if (auto *HFI = getExistingFileInfo(File))
- return HFI->isPragmaOnce || HFI->isImport || HFI->ControllingMacro ||
+ return HFI->isPragmaOnce || HFI->ControllingMacro ||
HFI->ControllingMacroID;
return false;
}
@@ -1273,14 +1276,12 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
//
// It's common that libc++ and system modules will both define such
// submodules. Make sure cached results for a builtin header won't
- // prevent other builtin modules to potentially enter the builtin header.
- // Note that builtins are header guarded and the decision to actually
- // enter them is postponed to the controlling macros logic below.
+ // prevent other builtin modules from potentially entering the builtin
+ // header. Note that builtins are header guarded and the decision to
+ // actually enter them is postponed to the controlling macros logic below.
bool TryEnterHdr = false;
if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
- TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() &&
- ModuleMap::isBuiltinHeader(
- llvm::sys::path::filename(File->getName()));
+ TryEnterHdr = ModMap.isBuiltinHeader(File);
// Textual headers can be #imported from different modules. Since ObjC
// headers find in the wild might rely only on #import and do not contain
@@ -1398,25 +1399,46 @@ HeaderSearch::findModuleForHeader(const FileEntry *File,
return ModMap.findModuleForHeader(File, AllowTextual);
}
+ArrayRef<ModuleMap::KnownHeader>
+HeaderSearch::findAllModulesForHeader(const FileEntry *File) const {
+ if (ExternalSource) {
+ // Make sure the external source has handled header info about this file,
+ // which includes whether the file is part of a module.
+ (void)getExistingFileInfo(File);
+ }
+ return ModMap.findAllModulesForHeader(File);
+}
+
static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule) {
ModuleMap::KnownHeader Module =
HS.findModuleForHeader(File, /*AllowTextual*/true);
- if (SuggestedModule)
- *SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader)
- ? ModuleMap::KnownHeader()
- : Module;
// If this module specifies [no_undeclared_includes], we cannot find any
// file that's in a non-dependency module.
if (RequestingModule && Module && RequestingModule->NoUndeclaredIncludes) {
- HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/false);
+ HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/ false);
if (!RequestingModule->directlyUses(Module.getModule())) {
+ // Builtin headers are a special case. Multiple modules can use the same
+ // builtin as a modular header (see also comment in
+ // ShouldEnterIncludeFile()), so the builtin header may have been
+ // "claimed" by an unrelated module. This shouldn't prevent us from
+ // including the builtin header textually in this module.
+ if (HS.getModuleMap().isBuiltinHeader(File)) {
+ if (SuggestedModule)
+ *SuggestedModule = ModuleMap::KnownHeader();
+ return true;
+ }
return false;
}
}
+ if (SuggestedModule)
+ *SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader)
+ ? ModuleMap::KnownHeader()
+ : Module;
+
return true;
}
@@ -1567,6 +1589,16 @@ HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
llvm::sys::path::append(ModuleMapFileName, "module.map");
if (auto F = FileMgr.getFile(ModuleMapFileName))
return *F;
+
+ // For frameworks, allow to have a private module map with a preferred
+ // spelling when a public module map is absent.
+ if (IsFramework) {
+ ModuleMapFileName = Dir->getName();
+ llvm::sys::path::append(ModuleMapFileName, "Modules",
+ "module.private.modulemap");
+ if (auto F = FileMgr.getFile(ModuleMapFileName))
+ return *F;
+ }
return nullptr;
}
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 648bda2705780..a559ca3eac2ba 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -29,6 +29,7 @@
#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
@@ -253,7 +254,7 @@ template <typename T> static void StringifyImpl(T &Str, char Quote) {
}
std::string Lexer::Stringify(StringRef Str, bool Charify) {
- std::string Result = Str;
+ std::string Result = std::string(Str);
char Quote = Charify ? '\'' : '"';
StringifyImpl(Result, Quote);
return Result;
@@ -1861,7 +1862,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize,
getLangOpts());
if (!isIdentifierBody(Next)) {
- // End of suffix. Check whether this is on the whitelist.
+ // End of suffix. Check whether this is on the allowed list.
const StringRef CompleteSuffix(Buffer, Chars);
IsUDSuffix = StringLiteralParser::isValidUDSuffix(getLangOpts(),
CompleteSuffix);
@@ -2092,7 +2093,8 @@ void Lexer::codeCompleteIncludedFile(const char *PathStart,
bool IsAngled) {
// Completion only applies to the filename, after the last slash.
StringRef PartialPath(PathStart, CompletionPoint - PathStart);
- auto Slash = PartialPath.find_last_of(LangOpts.MSVCCompat ? "/\\" : "/");
+ llvm::StringRef SlashChars = LangOpts.MSVCCompat ? "/\\" : "/";
+ auto Slash = PartialPath.find_last_of(SlashChars);
StringRef Dir =
(Slash == StringRef::npos) ? "" : PartialPath.take_front(Slash);
const char *StartOfFilename =
@@ -2100,7 +2102,8 @@ void Lexer::codeCompleteIncludedFile(const char *PathStart,
// Code completion filter range is the filename only, up to completion point.
PP->setCodeCompletionIdentifierInfo(&PP->getIdentifierTable().get(
StringRef(StartOfFilename, CompletionPoint - StartOfFilename)));
- // We should replace the characters up to the closing quote, if any.
+ // We should replace the characters up to the closing quote or closest slash,
+ // if any.
while (CompletionPoint < BufferEnd) {
char Next = *(CompletionPoint + 1);
if (Next == 0 || Next == '\r' || Next == '\n')
@@ -2108,7 +2111,10 @@ void Lexer::codeCompleteIncludedFile(const char *PathStart,
++CompletionPoint;
if (Next == (IsAngled ? '>' : '"'))
break;
+ if (llvm::is_contained(SlashChars, Next))
+ break;
}
+
PP->setCodeCompletionTokenRange(
FileLoc.getLocWithOffset(StartOfFilename - BufferStart),
FileLoc.getLocWithOffset(CompletionPoint - BufferStart));
@@ -2552,8 +2558,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
'/', '/', '/', '/', '/', '/', '/', '/',
'/', '/', '/', '/', '/', '/', '/', '/'
};
- while (CurPtr+16 <= BufferEnd &&
- !vec_any_eq(*(const vector unsigned char*)CurPtr, Slashes))
+ while (CurPtr + 16 <= BufferEnd &&
+ !vec_any_eq(*(const __vector unsigned char *)CurPtr, Slashes))
CurPtr += 16;
#else
// Scan for '/' quickly. Many block comments are very large.
@@ -3694,7 +3700,7 @@ LexNextToken:
} else if (Char == '=') {
char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
if (After == '>') {
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus20) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::warn_cxx17_compat_spaceship);
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
@@ -3705,7 +3711,7 @@ LexNextToken:
// Suggest adding a space between the '<=' and the '>' to avoid a
// change in semantics if this turns up in C++ <=17 mode.
if (getLangOpts().CPlusPlus && !isLexingRawMode()) {
- Diag(BufferPtr, diag::warn_cxx2a_compat_spaceship)
+ Diag(BufferPtr, diag::warn_cxx20_compat_spaceship)
<< FixItHint::CreateInsertion(
getSourceLocation(CurPtr + SizeTmp, SizeTmp2), " ");
}
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 9a852141c6eea..eb16bc8c7da2d 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -25,6 +25,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
@@ -524,8 +525,12 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
///
NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
SourceLocation TokLoc,
- Preprocessor &PP)
- : PP(PP), ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) {
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const TargetInfo &Target,
+ DiagnosticsEngine &Diags)
+ : SM(SM), LangOpts(LangOpts), Diags(Diags),
+ ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) {
// This routine assumes that the range begin/end matches the regex for integer
// and FP constants (specifically, the 'pp-number' regex), and assumes that
@@ -571,7 +576,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
checkSeparator(TokLoc, s, CSK_AfterDigits);
// Initial scan to lookahead for fixed point suffix.
- if (PP.getLangOpts().FixedPoint) {
+ if (LangOpts.FixedPoint) {
for (const char *c = s; c != ThisTokEnd; ++c) {
if (*c == 'r' || *c == 'k' || *c == 'R' || *c == 'K') {
saw_fixed_point_suffix = true;
@@ -582,6 +587,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// Parse the suffix. At this point we can classify whether we have an FP or
// integer constant.
+ bool isFixedPointConstant = isFixedPointLiteral();
bool isFPConstant = isFloatingLiteral();
// Loop over all of the characters of the suffix. If we see something bad,
@@ -590,14 +596,16 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
switch (*s) {
case 'R':
case 'r':
- if (!PP.getLangOpts().FixedPoint) break;
+ if (!LangOpts.FixedPoint)
+ break;
if (isFract || isAccum) break;
if (!(saw_period || saw_exponent)) break;
isFract = true;
continue;
case 'K':
case 'k':
- if (!PP.getLangOpts().FixedPoint) break;
+ if (!LangOpts.FixedPoint)
+ break;
if (isFract || isAccum) break;
if (!(saw_period || saw_exponent)) break;
isAccum = true;
@@ -605,7 +613,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
case 'h': // FP Suffix for "half".
case 'H':
// OpenCL Extension v1.2 s9.5 - h or H suffix for half type.
- if (!(PP.getLangOpts().Half || PP.getLangOpts().FixedPoint)) break;
+ if (!(LangOpts.Half || LangOpts.FixedPoint))
+ break;
if (isIntegerLiteral()) break; // Error for integer constant.
if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid.
isHalf = true;
@@ -619,8 +628,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// CUDA host and device may have different _Float16 support, therefore
// allows f16 literals to avoid false alarm.
// ToDo: more precise check for CUDA.
- if ((PP.getTargetInfo().hasFloat16Type() || PP.getLangOpts().CUDA) &&
- s + 2 < ThisTokEnd && s[1] == '1' && s[2] == '6') {
+ if ((Target.hasFloat16Type() || LangOpts.CUDA) && s + 2 < ThisTokEnd &&
+ s[1] == '1' && s[2] == '6') {
s += 2; // success, eat up 2 characters.
isFloat16 = true;
continue;
@@ -655,10 +664,10 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
} else {
isLong = true;
}
- continue; // Success.
+ continue; // Success.
case 'i':
case 'I':
- if (PP.getLangOpts().MicrosoftExt) {
+ if (LangOpts.MicrosoftExt) {
if (isLong || isLongLong || MicrosoftInteger)
break;
@@ -711,7 +720,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
if (s != ThisTokEnd || isImaginary) {
// FIXME: Don't bother expanding UCNs if !tok.hasUCN().
expandUCNs(UDSuffixBuf, StringRef(SuffixBegin, ThisTokEnd - SuffixBegin));
- if (isValidUDSuffix(PP.getLangOpts(), UDSuffixBuf)) {
+ if (isValidUDSuffix(LangOpts, UDSuffixBuf)) {
if (!isImaginary) {
// Any suffix pieces we might have parsed are actually part of the
// ud-suffix.
@@ -734,9 +743,11 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
if (s != ThisTokEnd) {
// Report an error if there are any.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
- diag::err_invalid_suffix_constant)
- << StringRef(SuffixBegin, ThisTokEnd - SuffixBegin) << isFPConstant;
+ Diags.Report(Lexer::AdvanceToTokenCharacter(
+ TokLoc, SuffixBegin - ThisTokBegin, SM, LangOpts),
+ diag::err_invalid_suffix_constant)
+ << StringRef(SuffixBegin, ThisTokEnd - SuffixBegin)
+ << (isFixedPointConstant ? 2 : isFPConstant);
hadError = true;
}
}
@@ -755,9 +766,11 @@ void NumericLiteralParser::ParseDecimalOrOctalCommon(SourceLocation TokLoc){
// If we have a hex digit other than 'e' (which denotes a FP exponent) then
// the code is using an incorrect base.
if (isHexDigit(*s) && *s != 'e' && *s != 'E' &&
- !isValidUDSuffix(PP.getLangOpts(), StringRef(s, ThisTokEnd - s))) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_invalid_digit) << StringRef(s, 1) << (radix == 8 ? 1 : 0);
+ !isValidUDSuffix(LangOpts, StringRef(s, ThisTokEnd - s))) {
+ Diags.Report(
+ Lexer::AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin, SM, LangOpts),
+ diag::err_invalid_digit)
+ << StringRef(s, 1) << (radix == 8 ? 1 : 0);
hadError = true;
return;
}
@@ -783,8 +796,9 @@ void NumericLiteralParser::ParseDecimalOrOctalCommon(SourceLocation TokLoc){
s = first_non_digit;
} else {
if (!hadError) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
- diag::err_exponent_has_no_digits);
+ Diags.Report(Lexer::AdvanceToTokenCharacter(
+ TokLoc, Exponent - ThisTokBegin, SM, LangOpts),
+ diag::err_exponent_has_no_digits);
hadError = true;
}
return;
@@ -815,7 +829,7 @@ bool NumericLiteralParser::isValidUDSuffix(const LangOptions &LangOpts,
.Cases("h", "min", "s", true)
.Cases("ms", "us", "ns", true)
.Cases("il", "i", "if", true)
- .Cases("d", "y", LangOpts.CPlusPlus2a)
+ .Cases("d", "y", LangOpts.CPlusPlus20)
.Default(false);
}
@@ -830,9 +844,10 @@ void NumericLiteralParser::checkSeparator(SourceLocation TokLoc,
return;
if (isDigitSeparator(*Pos)) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Pos - ThisTokBegin),
- diag::err_digit_separator_not_between_digits)
- << IsAfterDigits;
+ Diags.Report(Lexer::AdvanceToTokenCharacter(TokLoc, Pos - ThisTokBegin, SM,
+ LangOpts),
+ diag::err_digit_separator_not_between_digits)
+ << IsAfterDigits;
hadError = true;
}
}
@@ -870,9 +885,10 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
if (!HasSignificandDigits) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
- diag::err_hex_constant_requires)
- << PP.getLangOpts().CPlusPlus << 1;
+ Diags.Report(Lexer::AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin, SM,
+ LangOpts),
+ diag::err_hex_constant_requires)
+ << LangOpts.CPlusPlus << 1;
hadError = true;
return;
}
@@ -888,8 +904,9 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
const char *first_non_digit = SkipDigits(s);
if (!containsDigits(s, first_non_digit)) {
if (!hadError) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
- diag::err_exponent_has_no_digits);
+ Diags.Report(Lexer::AdvanceToTokenCharacter(
+ TokLoc, Exponent - ThisTokBegin, SM, LangOpts),
+ diag::err_exponent_has_no_digits);
hadError = true;
}
return;
@@ -897,16 +914,17 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = first_non_digit;
- if (!PP.getLangOpts().HexFloats)
- PP.Diag(TokLoc, PP.getLangOpts().CPlusPlus
- ? diag::ext_hex_literal_invalid
- : diag::ext_hex_constant_invalid);
- else if (PP.getLangOpts().CPlusPlus17)
- PP.Diag(TokLoc, diag::warn_cxx17_hex_literal);
+ if (!LangOpts.HexFloats)
+ Diags.Report(TokLoc, LangOpts.CPlusPlus
+ ? diag::ext_hex_literal_invalid
+ : diag::ext_hex_constant_invalid);
+ else if (LangOpts.CPlusPlus17)
+ Diags.Report(TokLoc, diag::warn_cxx17_hex_literal);
} else if (saw_period) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
- diag::err_hex_constant_requires)
- << PP.getLangOpts().CPlusPlus << 0;
+ Diags.Report(Lexer::AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin, SM,
+ LangOpts),
+ diag::err_hex_constant_requires)
+ << LangOpts.CPlusPlus << 0;
hadError = true;
}
return;
@@ -915,12 +933,10 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// Handle simple binary numbers 0b01010
if ((c1 == 'b' || c1 == 'B') && (s[1] == '0' || s[1] == '1')) {
// 0b101010 is a C++1y / GCC extension.
- PP.Diag(TokLoc,
- PP.getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_binary_literal
- : PP.getLangOpts().CPlusPlus
- ? diag::ext_binary_literal_cxx14
- : diag::ext_binary_literal);
+ Diags.Report(TokLoc, LangOpts.CPlusPlus14
+ ? diag::warn_cxx11_compat_binary_literal
+ : LangOpts.CPlusPlus ? diag::ext_binary_literal_cxx14
+ : diag::ext_binary_literal);
++s;
assert(s < ThisTokEnd && "didn't maximally munch?");
radix = 2;
@@ -929,10 +945,11 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
if (s == ThisTokEnd) {
// Done.
} else if (isHexDigit(*s) &&
- !isValidUDSuffix(PP.getLangOpts(),
- StringRef(s, ThisTokEnd - s))) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
- diag::err_invalid_digit) << StringRef(s, 1) << 2;
+ !isValidUDSuffix(LangOpts, StringRef(s, ThisTokEnd - s))) {
+ Diags.Report(Lexer::AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin, SM,
+ LangOpts),
+ diag::err_invalid_digit)
+ << StringRef(s, 1) << 2;
hadError = true;
}
// Other suffixes will be diagnosed by the caller.
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index fe20a35070362..bcdc5b8062a02 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -262,7 +262,7 @@ void ModuleMap::resolveHeader(Module *Mod,
// Record this umbrella header.
setUmbrellaHeader(Mod, File, RelativePathName.str());
} else {
- Module::Header H = {RelativePathName.str(), File};
+ Module::Header H = {std::string(RelativePathName.str()), File};
if (Header.Kind == Module::HK_Excluded)
excludeHeader(Mod, H);
else
@@ -282,7 +282,7 @@ void ModuleMap::resolveHeader(Module *Mod,
// resolved. (Such a module still can't be built though, except from
// preprocessed source.)
if (!Header.Size && !Header.ModTime)
- Mod->markUnavailable();
+ Mod->markUnavailable(/*Unimportable=*/false);
}
}
@@ -305,7 +305,7 @@ bool ModuleMap::resolveAsBuiltinHeader(
return false;
auto Role = headerKindToRole(Header.Kind);
- Module::Header H = {Path.str(), *File};
+ Module::Header H = {std::string(Path.str()), *File};
addHeader(Mod, H, Role);
return true;
}
@@ -387,13 +387,17 @@ bool ModuleMap::isBuiltinHeader(StringRef FileName) {
.Default(false);
}
+bool ModuleMap::isBuiltinHeader(const FileEntry *File) {
+ return File->getDir() == BuiltinIncludeDir &&
+ ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()));
+}
+
ModuleMap::HeadersMap::iterator
ModuleMap::findKnownHeader(const FileEntry *File) {
resolveHeaderDirectives(File);
HeadersMap::iterator Known = Headers.find(File);
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
- Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
- ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
+ Known == Headers.end() && ModuleMap::isBuiltinHeader(File)) {
HeaderInfo.loadTopLevelSystemModules();
return Headers.find(File);
}
@@ -544,6 +548,9 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
static bool isBetterKnownHeader(const ModuleMap::KnownHeader &New,
const ModuleMap::KnownHeader &Old) {
// Prefer available modules.
+ // FIXME: Considering whether the module is available rather than merely
+ // importable is non-hermetic and can result in surprising behavior for
+ // prebuilt modules. Consider only checking for importability here.
if (New.getModule()->isAvailable() && !Old.getModule()->isAvailable())
return true;
@@ -659,7 +666,20 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
}
ArrayRef<ModuleMap::KnownHeader>
-ModuleMap::findAllModulesForHeader(const FileEntry *File) const {
+ModuleMap::findAllModulesForHeader(const FileEntry *File) {
+ HeadersMap::iterator Known = findKnownHeader(File);
+ if (Known != Headers.end())
+ return Known->second;
+
+ if (findOrCreateModuleForHeaderInUmbrellaDir(File))
+ return Headers.find(File)->second;
+
+ return None;
+}
+
+ArrayRef<ModuleMap::KnownHeader>
+ModuleMap::findResolvedModulesForHeader(const FileEntry *File) const {
+ // FIXME: Is this necessary?
resolveHeaderDirectives(File);
auto It = Headers.find(File);
if (It == Headers.end())
@@ -1094,7 +1114,7 @@ Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework,
/*IsExplicit=*/false, NumCreatedModules++);
Result->ShadowingModule = ShadowingModule;
- Result->IsAvailable = false;
+ Result->markUnavailable(/*Unimportable*/true);
ModuleScopeIDs[Result] = CurrentModuleScopeID;
ShadowModules.push_back(Result);
@@ -1105,6 +1125,7 @@ void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader,
Twine NameAsWritten) {
Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
Mod->Umbrella = UmbrellaHeader;
+ Mod->HasUmbrellaDir = false;
Mod->UmbrellaAsWritten = NameAsWritten.str();
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
@@ -1116,6 +1137,7 @@ void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader,
void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir,
Twine NameAsWritten) {
Mod->Umbrella = UmbrellaDir;
+ Mod->HasUmbrellaDir = true;
Mod->UmbrellaAsWritten = NameAsWritten.str();
UmbrellaDirs[UmbrellaDir] = Mod;
}
@@ -1242,6 +1264,11 @@ void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) {
InferredModuleAllowedBy[M] = ModMap;
}
+void ModuleMap::addAdditionalModuleMapFile(const Module *M,
+ const FileEntry *ModuleMap) {
+ AdditionalModMaps[M].insert(ModuleMap);
+}
+
LLVM_DUMP_METHOD void ModuleMap::dump() {
llvm::errs() << "Modules:";
for (llvm::StringMap<Module *>::iterator M = Modules.begin(),
@@ -1681,7 +1708,8 @@ bool ModuleMapParser::parseModuleId(ModuleId &Id) {
Id.clear();
do {
if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
- Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation()));
+ Id.push_back(
+ std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
consumeToken();
} else {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
@@ -2088,9 +2116,9 @@ void ModuleMapParser::parseModuleDecl() {
// If the module meets all requirements but is still unavailable, mark the
// whole tree as unavailable to prevent it from building.
- if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement &&
+ if (!ActiveModule->IsAvailable && !ActiveModule->IsUnimportable &&
ActiveModule->Parent) {
- ActiveModule->getTopLevelModule()->markUnavailable();
+ ActiveModule->getTopLevelModule()->markUnavailable(/*Unimportable=*/false);
ActiveModule->getTopLevelModule()->MissingHeaders.append(
ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());
}
@@ -2129,7 +2157,7 @@ void ModuleMapParser::parseExternModuleDecl() {
HadError = true;
return;
}
- std::string FileName = Tok.getString();
+ std::string FileName = std::string(Tok.getString());
consumeToken(); // filename
StringRef FileNameRef = FileName;
@@ -2209,7 +2237,7 @@ void ModuleMapParser::parseRequiresDecl() {
}
// Consume the feature name.
- std::string Feature = Tok.getString();
+ std::string Feature = std::string(Tok.getString());
consumeToken();
bool IsRequiresExcludedHack = false;
@@ -2283,7 +2311,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
return;
}
Module::UnresolvedHeaderDirective Header;
- Header.FileName = Tok.getString();
+ Header.FileName = std::string(Tok.getString());
Header.FileNameLoc = consumeToken();
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
Header.Kind =
@@ -2380,7 +2408,7 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
return;
}
- std::string DirName = Tok.getString();
+ std::string DirName = std::string(Tok.getString());
SourceLocation DirNameLoc = consumeToken();
// Check whether we already have an umbrella.
@@ -2422,8 +2450,7 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E;
I != E && !EC; I.increment(EC)) {
if (auto FE = SourceMgr.getFileManager().getFile(I->path())) {
-
- Module::Header Header = {I->path(), *FE};
+ Module::Header Header = {std::string(I->path()), *FE};
Headers.push_back(std::move(Header));
}
}
@@ -2466,8 +2493,8 @@ void ModuleMapParser::parseExportDecl() {
do {
// FIXME: Support string-literal module names here.
if (Tok.is(MMToken::Identifier)) {
- ParsedModuleId.push_back(std::make_pair(Tok.getString(),
- Tok.getLocation()));
+ ParsedModuleId.push_back(
+ std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
consumeToken();
if (Tok.is(MMToken::Period)) {
@@ -2526,7 +2553,7 @@ void ModuleMapParser::parseExportAsDecl() {
}
}
- ActiveModule->ExportAsModule = Tok.getString();
+ ActiveModule->ExportAsModule = std::string(Tok.getString());
Map.addLinkAsDependency(ActiveModule);
consumeToken();
@@ -2572,7 +2599,7 @@ void ModuleMapParser::parseLinkDecl() {
return;
}
- std::string LibraryName = Tok.getString();
+ std::string LibraryName = std::string(Tok.getString());
consumeToken();
ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName,
IsFramework));
@@ -2794,8 +2821,8 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
break;
}
- Map.InferredDirectories[Directory].ExcludedModules
- .push_back(Tok.getString());
+ Map.InferredDirectories[Directory].ExcludedModules.push_back(
+ std::string(Tok.getString()));
consumeToken();
break;
diff --git a/clang/lib/Lex/PPCallbacks.cpp b/clang/lib/Lex/PPCallbacks.cpp
index cd8b04b20d245..b618071590baf 100644
--- a/clang/lib/Lex/PPCallbacks.cpp
+++ b/clang/lib/Lex/PPCallbacks.cpp
@@ -7,7 +7,24 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/PPCallbacks.h"
+#include "clang/Basic/FileManager.h"
using namespace clang;
-void PPChainedCallbacks::anchor() { }
+// Out of line key method.
+PPCallbacks::~PPCallbacks() = default;
+
+void PPCallbacks::HasInclude(SourceLocation Loc, StringRef FileName,
+ bool IsAngled, Optional<FileEntryRef> File,
+ SrcMgr::CharacteristicKind FileType) {}
+
+// Out of line key method.
+PPChainedCallbacks::~PPChainedCallbacks() = default;
+
+void PPChainedCallbacks::HasInclude(SourceLocation Loc, StringRef FileName,
+ bool IsAngled, Optional<FileEntryRef> File,
+ SrcMgr::CharacteristicKind FileType) {
+ First->HasInclude(Loc, FileName, IsAngled, File, FileType);
+ Second->HasInclude(Loc, FileName, IsAngled, File, FileType);
+}
+
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index e433b2cf1b957..053ef1d2dd180 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -432,6 +432,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// Skip to the next '#endif' / '#else' / '#elif'.
CurLexer->skipOver(*SkipLength);
}
+ SourceLocation endLoc;
while (true) {
CurLexer->Lex(Tok);
@@ -538,7 +539,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// Restore the value of LexingRawMode so that trailing comments
// are handled correctly, if we've reached the outermost block.
CurPPLexer->LexingRawMode = false;
- CheckEndOfDirective("endif");
+ endLoc = CheckEndOfDirective("endif");
CurPPLexer->LexingRawMode = true;
if (Callbacks)
Callbacks->Endif(Tok.getLocation(), CondInfo.IfLoc);
@@ -565,7 +566,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// Restore the value of LexingRawMode so that trailing comments
// are handled correctly.
CurPPLexer->LexingRawMode = false;
- CheckEndOfDirective("else");
+ endLoc = CheckEndOfDirective("else");
CurPPLexer->LexingRawMode = true;
if (Callbacks)
Callbacks->Else(Tok.getLocation(), CondInfo.IfLoc);
@@ -621,7 +622,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// by the end of the preamble; we'll resume parsing after the preamble.
if (Callbacks && (Tok.isNot(tok::eof) || !isRecordingPreamble()))
Callbacks->SourceRangeSkipped(
- SourceRange(HashTokenLoc, CurPPLexer->getSourceLocation()),
+ SourceRange(HashTokenLoc, endLoc.isValid()
+ ? endLoc
+ : CurPPLexer->getSourceLocation()),
Tok.getLocation());
}
@@ -646,24 +649,8 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
}
const FileEntry *
-Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
- Module *M,
- SourceLocation Loc) {
- assert(M && "no module to include");
-
- // If the context is the global module fragment of some module, we never
- // want to return that file; instead, we want the innermost include-guarded
- // header that it included.
- bool InGlobalModuleFragment = M->Kind == Module::GlobalModuleFragment;
-
- // If we have a module import syntax, we shouldn't include a header to
- // make a particular module visible.
- if ((getLangOpts().ObjC || getLangOpts().CPlusPlusModules ||
- getLangOpts().ModulesTS) &&
- !InGlobalModuleFragment)
- return nullptr;
-
- Module *TopM = M->getTopLevelModule();
+Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+ SourceLocation Loc) {
Module *IncM = getModuleForLocation(IncLoc);
// Walk up through the include stack, looking through textual headers of M
@@ -677,37 +664,50 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
if (!FE)
break;
- if (InGlobalModuleFragment) {
- if (getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE))
- return FE;
- Loc = SM.getIncludeLoc(ID);
- continue;
- }
-
- bool InTextualHeader = false;
- for (auto Header : HeaderInfo.getModuleMap().findAllModulesForHeader(FE)) {
- if (!Header.getModule()->isSubModuleOf(TopM))
- continue;
-
- if (!(Header.getRole() & ModuleMap::TextualHeader)) {
- // If this is an accessible, non-textual header of M's top-level module
- // that transitively includes the given location and makes the
- // corresponding module visible, this is the thing to #include.
- if (Header.isAccessibleFrom(IncM))
- return FE;
+ // We want to find all possible modules that might contain this header, so
+ // search all enclosing directories for module maps and load them.
+ HeaderInfo.hasModuleMap(FE->getName(), /*Root*/ nullptr,
+ SourceMgr.isInSystemHeader(Loc));
+ bool InPrivateHeader = false;
+ for (auto Header : HeaderInfo.findAllModulesForHeader(FE)) {
+ if (!Header.isAccessibleFrom(IncM)) {
// It's in a private header; we can't #include it.
// FIXME: If there's a public header in some module that re-exports it,
// then we could suggest including that, but it's not clear that's the
// expected way to make this entity visible.
+ InPrivateHeader = true;
continue;
}
- InTextualHeader = true;
+ // We'll suggest including textual headers below if they're
+ // include-guarded.
+ if (Header.getRole() & ModuleMap::TextualHeader)
+ continue;
+
+ // If we have a module import syntax, we shouldn't include a header to
+ // make a particular module visible. Let the caller know they should
+ // suggest an import instead.
+ if (getLangOpts().ObjC || getLangOpts().CPlusPlusModules ||
+ getLangOpts().ModulesTS)
+ return nullptr;
+
+ // If this is an accessible, non-textual header of M's top-level module
+ // that transitively includes the given location and makes the
+ // corresponding module visible, this is the thing to #include.
+ return FE;
}
- if (!InTextualHeader)
- break;
+ // FIXME: If we're bailing out due to a private header, we shouldn't suggest
+ // an import either.
+ if (InPrivateHeader)
+ return nullptr;
+
+ // If the header is includable and has an include guard, assume the
+ // intended way to expose its contents is by #include, not by importing a
+ // module that transitively includes it.
+ if (getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE))
+ return FE;
Loc = SM.getIncludeLoc(ID);
}
@@ -1708,15 +1708,22 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
tok::annot_module_include, Action.ModuleForHeader);
break;
+ case ImportAction::Failure:
+ assert(TheModuleLoader.HadFatalFailure &&
+ "This should be an early exit only to a fatal error");
+ TheModuleLoader.HadFatalFailure = true;
+ IncludeTok.setKind(tok::eof);
+ CurLexer->cutOffLexing();
+ return;
}
}
Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
- const DirectoryLookup *&CurDir, StringRef Filename,
+ const DirectoryLookup *&CurDir, StringRef& Filename,
SourceLocation FilenameLoc, CharSourceRange FilenameRange,
const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
bool &IsMapped, const DirectoryLookup *LookupFrom,
- const FileEntry *LookupFromFile, StringRef LookupFilename,
+ const FileEntry *LookupFromFile, StringRef& LookupFilename,
SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
ModuleMap::KnownHeader &SuggestedModule, bool isAngled) {
Optional<FileEntryRef> File = LookupFile(
@@ -1785,21 +1792,10 @@ Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
return Filename;
};
StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
-
-#ifndef _WIN32
- // Normalize slashes when compiling with -fms-extensions on non-Windows.
- // This is unnecessary on Windows since the filesystem there handles
- // backslashes.
- SmallString<128> NormalizedTypoCorrectionPath;
- if (LangOpts.MicrosoftExt) {
- NormalizedTypoCorrectionPath = TypoCorrectionName;
- llvm::sys::path::native(NormalizedTypoCorrectionPath);
- TypoCorrectionName = NormalizedTypoCorrectionPath;
- }
-#endif
+ StringRef TypoCorrectionLookupName = CorrectTypoFilename(LookupFilename);
Optional<FileEntryRef> File = LookupFile(
- FilenameLoc, TypoCorrectionName, isAngled, LookupFrom, LookupFromFile,
+ FilenameLoc, TypoCorrectionLookupName, isAngled, LookupFrom, LookupFromFile,
CurDir, Callbacks ? &SearchPath : nullptr,
Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
/*IsFrameworkFound=*/nullptr);
@@ -1814,6 +1810,7 @@ Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
// We found the file, so set the Filename to the name after typo
// correction.
Filename = TypoCorrectionName;
+ LookupFilename = TypoCorrectionLookupName;
return File;
}
}
@@ -1911,14 +1908,18 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
SourceLocation FilenameLoc = FilenameTok.getLocation();
StringRef LookupFilename = Filename;
-#ifndef _WIN32
+#ifdef _WIN32
+ llvm::sys::path::Style BackslashStyle = llvm::sys::path::Style::windows;
+#else
// Normalize slashes when compiling with -fms-extensions on non-Windows. This
// is unnecessary on Windows since the filesystem there handles backslashes.
SmallString<128> NormalizedPath;
+ llvm::sys::path::Style BackslashStyle = llvm::sys::path::Style::posix;
if (LangOpts.MicrosoftExt) {
NormalizedPath = Filename.str();
llvm::sys::path::native(NormalizedPath);
LookupFilename = NormalizedPath;
+ BackslashStyle = llvm::sys::path::Style::windows;
}
#endif
@@ -1933,19 +1934,6 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
return {ImportAction::None};
}
- // Check for circular inclusion of the main file.
- // We can't generate a consistent preamble with regard to the conditional
- // stack if the main file is included again as due to the preamble bounds
- // some directives (e.g. #endif of a header guard) will never be seen.
- // Since this will lead to confusing errors, avoid the inclusion.
- if (File && PreambleConditionalStack.isRecording() &&
- SourceMgr.translateFile(&File->getFileEntry()) ==
- SourceMgr.getMainFileID()) {
- Diag(FilenameTok.getLocation(),
- diag::err_pp_including_mainfile_in_preamble);
- return {ImportAction::None};
- }
-
// Should we enter the source file? Set to Skip if either the source file is
// known to have no effect beyond its effect on module visibility -- that is,
// if it's got an include guard that is already defined, set to Import if it
@@ -2063,6 +2051,18 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
Action = (SuggestedModule && !getLangOpts().CompilingPCH) ? Import : Skip;
}
+ // Check for circular inclusion of the main file.
+ // We can't generate a consistent preamble with regard to the conditional
+ // stack if the main file is included again as due to the preamble bounds
+ // some directives (e.g. #endif of a header guard) will never be seen.
+ // Since this will lead to confusing errors, avoid the inclusion.
+ if (Action == Enter && File && PreambleConditionalStack.isRecording() &&
+ SourceMgr.isMainFile(*File)) {
+ Diag(FilenameTok.getLocation(),
+ diag::err_pp_including_mainfile_in_preamble);
+ return {ImportAction::None};
+ }
+
if (Callbacks && !IsImportDecl) {
// Notify the callback object that we've seen an inclusion directive.
// FIXME: Use a different callback for a pp-import?
@@ -2093,29 +2093,90 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
if (CheckIncludePathPortability) {
StringRef Name = LookupFilename;
+ StringRef NameWithoriginalSlashes = Filename;
+#if defined(_WIN32)
+ // Skip UNC prefix if present. (tryGetRealPathName() always
+ // returns a path with the prefix skipped.)
+ bool NameWasUNC = Name.consume_front("\\\\?\\");
+ NameWithoriginalSlashes.consume_front("\\\\?\\");
+#endif
StringRef RealPathName = File->getFileEntry().tryGetRealPathName();
SmallVector<StringRef, 16> Components(llvm::sys::path::begin(Name),
llvm::sys::path::end(Name));
+#if defined(_WIN32)
+ // -Wnonportable-include-path is designed to diagnose includes using
+ // case even on systems with a case-insensitive file system.
+ // On Windows, RealPathName always starts with an upper-case drive
+ // letter for absolute paths, but Name might start with either
+ // case depending on if `cd c:\foo` or `cd C:\foo` was used in the shell.
+ // ("foo" will always have on-disk case, no matter which case was
+ // used in the cd command). To not emit this warning solely for
+ // the drive letter, whose case is dependent on if `cd` is used
+ // with upper- or lower-case drive letters, always consider the
+ // given drive letter case as correct for the purpose of this warning.
+ SmallString<128> FixedDriveRealPath;
+ if (llvm::sys::path::is_absolute(Name) &&
+ llvm::sys::path::is_absolute(RealPathName) &&
+ toLowercase(Name[0]) == toLowercase(RealPathName[0]) &&
+ isLowercase(Name[0]) != isLowercase(RealPathName[0])) {
+ assert(Components.size() >= 3 && "should have drive, backslash, name");
+ assert(Components[0].size() == 2 && "should start with drive");
+ assert(Components[0][1] == ':' && "should have colon");
+ FixedDriveRealPath = (Name.substr(0, 1) + RealPathName.substr(1)).str();
+ RealPathName = FixedDriveRealPath;
+ }
+#endif
if (trySimplifyPath(Components, RealPathName)) {
SmallString<128> Path;
Path.reserve(Name.size()+2);
Path.push_back(isAngled ? '<' : '"');
- bool isLeadingSeparator = llvm::sys::path::is_absolute(Name);
+
+ const auto IsSep = [BackslashStyle](char c) {
+ return llvm::sys::path::is_separator(c, BackslashStyle);
+ };
+
for (auto Component : Components) {
- if (isLeadingSeparator)
- isLeadingSeparator = false;
- else
+ // On POSIX, Components will contain a single '/' as first element
+ // exactly if Name is an absolute path.
+ // On Windows, it will contain "C:" followed by '\' for absolute paths.
+ // The drive letter is optional for absolute paths on Windows, but
+ // clang currently cannot process absolute paths in #include lines that
+ // don't have a drive.
+ // If the first entry in Components is a directory separator,
+ // then the code at the bottom of this loop that keeps the original
+ // directory separator style copies it. If the second entry is
+ // a directory separator (the C:\ case), then that separator already
+ // got copied when the C: was processed and we want to skip that entry.
+ if (!(Component.size() == 1 && IsSep(Component[0])))
Path.append(Component);
- // Append the separator the user used, or the close quote
- Path.push_back(
- Path.size() <= Filename.size() ? Filename[Path.size()-1] :
- (isAngled ? '>' : '"'));
+ else if (!Path.empty())
+ continue;
+
+ // Append the separator(s) the user used, or the close quote
+ if (Path.size() > NameWithoriginalSlashes.size()) {
+ Path.push_back(isAngled ? '>' : '"');
+ continue;
+ }
+ assert(IsSep(NameWithoriginalSlashes[Path.size()-1]));
+ do
+ Path.push_back(NameWithoriginalSlashes[Path.size()-1]);
+ while (Path.size() <= NameWithoriginalSlashes.size() &&
+ IsSep(NameWithoriginalSlashes[Path.size()-1]));
}
- // For user files and known standard headers, by default we issue a diagnostic.
- // For other system headers, we don't. They can be controlled separately.
- auto DiagId = (FileCharacter == SrcMgr::C_User || warnByDefaultOnWrongCase(Name)) ?
- diag::pp_nonportable_path : diag::pp_nonportable_system_path;
+
+#if defined(_WIN32)
+ // Restore UNC prefix if it was there.
+ if (NameWasUNC)
+ Path = (Path.substr(0, 1) + "\\\\?\\" + Path.substr(1)).str();
+#endif
+
+ // For user files and known standard headers, issue a diagnostic.
+ // For other system headers, don't. They can be controlled separately.
+ auto DiagId =
+ (FileCharacter == SrcMgr::C_User || warnByDefaultOnWrongCase(Name))
+ ? diag::pp_nonportable_path
+ : diag::pp_nonportable_system_path;
Diag(FilenameTok, DiagId) << Path <<
FixItHint::CreateReplacement(FilenameRange, Path);
}
@@ -2165,7 +2226,10 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
if (IncludePos.isMacroID())
IncludePos = SourceMgr.getExpansionRange(IncludePos).getEnd();
FileID FID = SourceMgr.createFileID(*File, IncludePos, FileCharacter);
- assert(FID.isValid() && "Expected valid file ID");
+ if (!FID.isValid()) {
+ TheModuleLoader.HadFatalFailure = true;
+ return ImportAction::Failure;
+ }
// If all is good, enter the new file!
if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation()))
@@ -2792,7 +2856,9 @@ void Preprocessor::HandleDefineDirective(
// warn-because-unused-macro set. If it gets used it will be removed from set.
if (getSourceManager().isInMainFile(MI->getDefinitionLoc()) &&
!Diags->isIgnored(diag::pp_macro_not_used, MI->getDefinitionLoc()) &&
- !MacroExpansionInDirectivesOverride) {
+ !MacroExpansionInDirectivesOverride &&
+ getSourceManager().getFileID(MI->getDefinitionLoc()) !=
+ getPredefinesFileID()) {
MI->setIsWarnIfUnused(true);
WarnUnusedMacroLocs.insert(MI->getDefinitionLoc());
}
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index e5ec2b99f5074..8c120c13d7d26 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -15,7 +15,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -26,9 +25,12 @@
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -251,8 +253,24 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// If this identifier isn't 'defined' or one of the special
// preprocessor keywords and it wasn't macro expanded, it turns
// into a simple 0
- if (ValueLive)
+ if (ValueLive) {
PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
+
+ const DiagnosticsEngine &DiagEngine = PP.getDiagnostics();
+ // If 'Wundef' is enabled, do not emit 'undef-prefix' diagnostics.
+ if (DiagEngine.isIgnored(diag::warn_pp_undef_identifier,
+ PeekTok.getLocation())) {
+ const std::vector<std::string> UndefPrefixes =
+ DiagEngine.getDiagnosticOptions().UndefPrefixes;
+ const StringRef IdentifierName = II->getName();
+ if (llvm::any_of(UndefPrefixes,
+ [&IdentifierName](const std::string &Prefix) {
+ return IdentifierName.startswith(Prefix);
+ }))
+ PP.Diag(PeekTok, diag::warn_pp_undef_prefix)
+ << AddFlagValue{llvm::join(UndefPrefixes, ",")} << II;
+ }
+ }
Result.Val = 0;
Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
Result.setIdentifier(II);
@@ -277,7 +295,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (NumberInvalid)
return true; // a diagnostic was already reported
- NumericLiteralParser Literal(Spelling, PeekTok.getLocation(), PP);
+ NumericLiteralParser Literal(Spelling, PeekTok.getLocation(),
+ PP.getSourceManager(), PP.getLangOpts(),
+ PP.getTargetInfo(), PP.getDiagnostics());
if (Literal.hadError)
return true; // a diagnostic was already reported.
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index 8021726939606..b7c7e2693ef18 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -24,8 +24,6 @@
#include "llvm/Support/Path.h"
using namespace clang;
-PPCallbacks::~PPCallbacks() {}
-
//===----------------------------------------------------------------------===//
// Miscellaneous Methods.
//===----------------------------------------------------------------------===//
@@ -81,7 +79,7 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
if (Invalid) {
SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID);
Diag(Loc, diag::err_pp_error_opening_file)
- << std::string(SourceMgr.getBufferName(FileStart)) << "";
+ << std::string(SourceMgr.getBufferName(FileStart)) << "";
return true;
}
@@ -417,7 +415,10 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
if (!isEndOfMacro && CurPPLexer &&
- SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid()) {
+ (SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid() ||
+ // Predefines file doesn't have a valid include location.
+ (PredefinesFileID.isValid() &&
+ CurPPLexer->getFileID() == PredefinesFileID))) {
// Notify SourceManager to record the number of FileIDs that were created
// during lexing of the #include'd file.
unsigned NumFIDs =
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index cf8bb2fbab991..4908594d6081f 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1456,10 +1456,8 @@ static void remapMacroPath(
const std::map<std::string, std::string, std::greater<std::string>>
&MacroPrefixMap) {
for (const auto &Entry : MacroPrefixMap)
- if (Path.startswith(Entry.first)) {
- Path = (Twine(Entry.second) + Path.substr(Entry.first.size())).str();
+ if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
break;
- }
}
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
@@ -1543,8 +1541,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
} else {
FN += PLoc.getFilename();
}
- Lexer::Stringify(FN);
remapMacroPath(FN, PPOpts->MacroPrefixMap);
+ Lexer::Stringify(FN);
OS << '"' << FN << '"';
}
Tok.setKind(tok::string_literal);
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index e4636265a72bb..b512a547de7df 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -30,6 +30,7 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorLexer.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/Token.h"
#include "clang/Lex/TokenLexer.h"
#include "llvm/ADT/ArrayRef.h"
@@ -39,9 +40,9 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Timer.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -70,31 +71,36 @@ void EmptyPragmaHandler::HandlePragma(Preprocessor &PP,
// PragmaNamespace Implementation.
//===----------------------------------------------------------------------===//
-PragmaNamespace::~PragmaNamespace() {
- llvm::DeleteContainerSeconds(Handlers);
-}
-
/// FindHandler - Check to see if there is already a handler for the
/// specified name. If not, return the handler for the null identifier if it
/// exists, otherwise return null. If IgnoreNull is true (the default) then
/// the null handler isn't returned on failure to match.
PragmaHandler *PragmaNamespace::FindHandler(StringRef Name,
bool IgnoreNull) const {
- if (PragmaHandler *Handler = Handlers.lookup(Name))
- return Handler;
- return IgnoreNull ? nullptr : Handlers.lookup(StringRef());
+ auto I = Handlers.find(Name);
+ if (I != Handlers.end())
+ return I->getValue().get();
+ if (IgnoreNull)
+ return nullptr;
+ I = Handlers.find(StringRef());
+ if (I != Handlers.end())
+ return I->getValue().get();
+ return nullptr;
}
void PragmaNamespace::AddPragma(PragmaHandler *Handler) {
- assert(!Handlers.lookup(Handler->getName()) &&
+ assert(!Handlers.count(Handler->getName()) &&
"A handler with this name is already registered in this namespace");
- Handlers[Handler->getName()] = Handler;
+ Handlers[Handler->getName()].reset(Handler);
}
void PragmaNamespace::RemovePragmaHandler(PragmaHandler *Handler) {
- assert(Handlers.lookup(Handler->getName()) &&
+ auto I = Handlers.find(Handler->getName());
+ assert(I != Handlers.end() &&
"Handler not registered in this namespace");
- Handlers.erase(Handler->getName());
+ // Release ownership back to the caller.
+ I->getValue().release();
+ Handlers.erase(I);
}
void PragmaNamespace::HandlePragma(Preprocessor &PP,
@@ -1035,15 +1041,21 @@ struct PragmaDebugHandler : public PragmaHandler {
IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("assert")) {
- llvm_unreachable("This is an assertion!");
+ if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
+ llvm_unreachable("This is an assertion!");
} else if (II->isStr("crash")) {
- LLVM_BUILTIN_TRAP;
+ llvm::Timer T("crash", "pragma crash");
+ llvm::TimeRegion R(&T);
+ if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
+ LLVM_BUILTIN_TRAP;
} else if (II->isStr("parser_crash")) {
- Token Crasher;
- Crasher.startToken();
- Crasher.setKind(tok::annot_pragma_parser_crash);
- Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
- PP.EnterToken(Crasher, /*IsReinject*/false);
+ if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) {
+ Token Crasher;
+ Crasher.startToken();
+ Crasher.setKind(tok::annot_pragma_parser_crash);
+ Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
+ PP.EnterToken(Crasher, /*IsReinject*/ false);
+ }
} else if (II->isStr("dump")) {
Token Identifier;
PP.LexUnexpandedToken(Identifier);
@@ -1075,9 +1087,11 @@ struct PragmaDebugHandler : public PragmaHandler {
<< II->getName();
}
} else if (II->isStr("llvm_fatal_error")) {
- llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
+ if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
+ llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
} else if (II->isStr("llvm_unreachable")) {
- llvm_unreachable("#pragma clang __debug llvm_unreachable");
+ if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
+ llvm_unreachable("#pragma clang __debug llvm_unreachable");
} else if (II->isStr("macro")) {
Token MacroName;
PP.LexUnexpandedToken(MacroName);
@@ -1104,11 +1118,8 @@ struct PragmaDebugHandler : public PragmaHandler {
}
M->dump();
} else if (II->isStr("overflow_stack")) {
- DebugOverflowStack();
- } else if (II->isStr("handle_crash")) {
- llvm::CrashRecoveryContext *CRC =llvm::CrashRecoveryContext::GetCurrent();
- if (CRC)
- CRC->HandleCrash();
+ if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
+ DebugOverflowStack();
} else if (II->isStr("captured")) {
HandleCaptured(PP);
} else {
@@ -1896,10 +1907,9 @@ void Preprocessor::RegisterBuiltinPragmas() {
}
// Pragmas added by plugins
- for (PragmaHandlerRegistry::iterator it = PragmaHandlerRegistry::begin(),
- ie = PragmaHandlerRegistry::end();
- it != ie; ++it) {
- AddPragmaHandler(it->instantiate().release());
+ for (const PragmaHandlerRegistry::entry &handler :
+ PragmaHandlerRegistry::entries()) {
+ AddPragmaHandler(handler.instantiate().release());
}
}
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 0e9be3923630a..160e2b6ed8846 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -119,7 +119,7 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
// a macro. They get unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus20) {
(Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use);
} else {
@@ -166,6 +166,8 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
this->PPOpts->ExcludedConditionalDirectiveSkipMappings;
if (ExcludedConditionalDirectiveSkipMappings)
ExcludedConditionalDirectiveSkipMappings->clear();
+
+ MaxTokens = LangOpts.MaxTokens;
}
Preprocessor::~Preprocessor() {
@@ -769,9 +771,13 @@ static diag::kind getFutureCompatDiagKind(const IdentifierInfo &II,
return llvm::StringSwitch<diag::kind>(II.getName())
#define CXX11_KEYWORD(NAME, FLAGS) \
.Case(#NAME, diag::warn_cxx11_keyword)
-#define CXX2A_KEYWORD(NAME, FLAGS) \
- .Case(#NAME, diag::warn_cxx2a_keyword)
+#define CXX20_KEYWORD(NAME, FLAGS) \
+ .Case(#NAME, diag::warn_cxx20_keyword)
#include "clang/Basic/TokenKinds.def"
+ // char8_t is not modeled as a CXX20_KEYWORD because it's not
+ // unconditionally enabled in C++20 mode. (It can be disabled
+ // by -fno-char8_t.)
+ .Case("char8_t", diag::warn_cxx20_keyword)
;
llvm_unreachable(
@@ -906,6 +912,9 @@ void Preprocessor::Lex(Token &Result) {
}
} while (!ReturnedToken);
+ if (Result.is(tok::unknown) && TheModuleLoader.HadFatalFailure)
+ return;
+
if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) {
// Remember the identifier before code completion token.
setCodeCompletionIdentifierInfo(Result.getIdentifierInfo());
@@ -959,8 +968,12 @@ void Preprocessor::Lex(Token &Result) {
LastTokenWasAt = Result.is(tok::at);
--LexLevel;
- if (OnToken && LexLevel == 0 && !Result.getFlag(Token::IsReinjected))
- OnToken(Result);
+
+ if (LexLevel == 0 && !Result.getFlag(Token::IsReinjected)) {
+ ++TokenCount;
+ if (OnToken)
+ OnToken(Result);
+ }
}
/// Lex a header-name token (including one formed from header-name-tokens if
@@ -1200,6 +1213,13 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
Suffix[0].setAnnotationValue(Action.ModuleForHeader);
// FIXME: Call the moduleImport callback?
break;
+ case ImportAction::Failure:
+ assert(TheModuleLoader.HadFatalFailure &&
+ "This should be an early exit only to a fatal error");
+ Result.setKind(tok::eof);
+ CurLexer->cutOffLexing();
+ EnterTokens(Suffix);
+ return true;
}
EnterTokens(Suffix);
@@ -1339,7 +1359,7 @@ bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String,
return false;
}
- String = Literal.GetString();
+ String = std::string(Literal.GetString());
return true;
}
@@ -1350,7 +1370,9 @@ bool Preprocessor::parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value) {
StringRef Spelling = getSpelling(Tok, IntegerBuffer, &NumberInvalid);
if (NumberInvalid)
return false;
- NumericLiteralParser Literal(Spelling, Tok.getLocation(), *this);
+ NumericLiteralParser Literal(Spelling, Tok.getLocation(), getSourceManager(),
+ getLangOpts(), getTargetInfo(),
+ getDiagnostics());
if (Literal.hadError || !Literal.isIntegerLiteral() || Literal.hasUDSuffix())
return false;
llvm::APInt APVal(64, 0);
diff --git a/clang/lib/Lex/TokenConcatenation.cpp b/clang/lib/Lex/TokenConcatenation.cpp
index e626cfcc927f5..f6b005d9e19cf 100644
--- a/clang/lib/Lex/TokenConcatenation.cpp
+++ b/clang/lib/Lex/TokenConcatenation.cpp
@@ -103,7 +103,7 @@ TokenConcatenation::TokenConcatenation(const Preprocessor &pp) : PP(pp) {
TokenInfo[tok::utf8_char_constant] |= aci_custom;
// These tokens have custom code in C++2a mode.
- if (PP.getLangOpts().CPlusPlus2a)
+ if (PP.getLangOpts().CPlusPlus20)
TokenInfo[tok::lessequal ] |= aci_custom_firstchar;
// These tokens change behavior if followed by an '='.
@@ -292,6 +292,6 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
case tok::arrow: // ->*
return PP.getLangOpts().CPlusPlus && FirstChar == '*';
case tok::lessequal: // <=> (C++2a)
- return PP.getLangOpts().CPlusPlus2a && FirstChar == '>';
+ return PP.getLangOpts().CPlusPlus20 && FirstChar == '>';
}
}