diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Lex | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'clang/lib/Lex')
-rw-r--r-- | clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Lex/HeaderSearch.cpp | 68 | ||||
-rw-r--r-- | clang/lib/Lex/Lexer.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Lex/LiteralSupport.cpp | 111 | ||||
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 71 | ||||
-rw-r--r-- | clang/lib/Lex/PPCallbacks.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Lex/PPDirectives.cpp | 236 | ||||
-rw-r--r-- | clang/lib/Lex/PPExpressions.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Lex/PPLexerChange.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Lex/Pragma.cpp | 70 | ||||
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Lex/TokenConcatenation.cpp | 4 |
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 == '>'; } } |