https://github.com/ameliajochna created https://github.com/llvm/llvm-project/pull/190610
This patch extends -Wnonportable-include-path to detect and warn about trailing whitespace and dots in #include directives. Such paths are non-portable and can lead to build failures on different operating systems. The warning is triggered when an include filename ends with a space or a dot, which is common when copy-pasting paths or due to typos. >From befa35cfdee0c694f717146627441f4082e592f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAmelia?= <“[email protected]”> Date: Mon, 6 Apr 2026 16:10:20 +0200 Subject: [PATCH] [Clang] Add warning for non-portable include paths with trailing whitespace or dots This patch extends -Wnonportable-include-path to detect and warn about trailing whitespace and dots in #include directives. Such paths are non-portable and can lead to build failures on different operating systems. The warning is triggered when an include filename ends with a space or a dot, which is common when copy-pasting paths or due to typos. Differential Revision: https://reviews.llvm.org/DXXXXX --- clang/include/clang/Basic/DiagnosticGroups.td | 2 + .../include/clang/Basic/DiagnosticLexKinds.td | 14 +- clang/lib/Lex/PPDirectives.cpp | 280 ++++++++++-------- .../nonportable-trailing-whitespace.c | 15 + 4 files changed, 180 insertions(+), 131 deletions(-) create mode 100644 clang/test/Preprocessor/nonportable-trailing-whitespace.c diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index dc7280c66ea79..e4491603df76c 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -944,6 +944,8 @@ def MemsetTransposedArgs : DiagGroup<"memset-transposed-args">; def DynamicClassMemaccess : DiagGroup<"dynamic-class-memaccess">; def NonTrivialMemcall : DiagGroup<"nontrivial-memcall">; def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess", [NonTrivialMemcall]>; +def NonportableIncludePath : DiagGroup<"nonportable-include-path">; +def NonportableSystemIncludePath : DiagGroup<"nonportable-system-include-path">; def SuspiciousBzero : DiagGroup<"suspicious-bzero">; def SuspiciousMemaccess : DiagGroup<"suspicious-memaccess", [SizeofPointerMemaccess, DynamicClassMemaccess, diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index bea0aafac98cf..deb1111b46134 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -373,13 +373,21 @@ def ext_missing_whitespace_after_macro_name : ExtWarn< def warn_missing_whitespace_after_macro_name : Warning< "whitespace recommended after macro name">; -class NonportablePath : Warning< +class NonportablePath : Warning< "non-portable path to file '%0'; specified path differs in case from file" " name on disk">; def pp_nonportable_path : NonportablePath, - InGroup<DiagGroup<"nonportable-include-path">>; + InGroup<NonportableIncludePath>; def pp_nonportable_system_path : NonportablePath, DefaultIgnore, - InGroup<DiagGroup<"nonportable-system-include-path">>; + InGroup<NonportableSystemIncludePath>; + +class NonportablePathTrailing : Warning< + "non-portable path to file '%0'; specified path contains trailing" + " %select{whitespace|dots}1">; +def pp_nonportable_path_trailing : NonportablePathTrailing, + InGroup<NonportableIncludePath>; +def pp_nonportable_system_path_trailing : NonportablePathTrailing, DefaultIgnore, + InGroup<NonportableSystemIncludePath>; def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">, InGroup<DiagGroup<"pragma-once-outside-header">>; diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index b90c04776ff9e..036e6f2556529 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -111,11 +111,7 @@ enum MacroDiag { /// Enumerates possible %select values for the pp_err_elif_after_else and /// pp_err_elif_without_if diagnostics. -enum PPElifDiag { - PED_Elif, - PED_Elifdef, - PED_Elifndef -}; +enum PPElifDiag { PED_Elif, PED_Elifdef, PED_Elifndef }; static bool isFeatureTestMacro(StringRef MacroName) { // list from: @@ -227,13 +223,14 @@ static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) { // and Boost headers. Improper case for these #includes is a // potential portability issue. static bool warnByDefaultOnWrongCase(StringRef Include) { - // If the first component of the path is "boost", treat this like a standard header - // for the purposes of diagnostics. + // If the first component of the path is "boost", treat this like a standard + // header for the purposes of diagnostics. if (::llvm::sys::path::begin(Include)->equals_insensitive("boost")) return true; // "condition_variable" is the longest standard header name at 18 characters. - // If the include file name is longer than that, it can't be a standard header. + // If the include file name is longer than that, it can't be a standard + // header. static const size_t MaxStdHeaderNameLen = 18u; if (Include.size() > MaxStdHeaderNameLen) return false; @@ -403,8 +400,7 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef, MacroDiag D = MD_NoWarn; if (isDefineUndef == MU_Define) { D = shouldWarnOnMacroDef(*this, II); - } - else if (isDefineUndef == MU_Undef) + } else if (isDefineUndef == MU_Undef) D = shouldWarnOnMacroUndef(*this, II); if (D == MD_KeywordDef) { // We do not want to warn on some patterns widely used in configuration @@ -484,7 +480,7 @@ Preprocessor::CheckEndOfDirective(StringRef DirType, bool EnableMacros, // There should be no tokens after the directive, but we allow them as an // extension. - while (Tmp.is(tok::comment)) // Skip comments in -C mode. + while (Tmp.is(tok::comment)) // Skip comments in -C mode. ReadNextTok(&Preprocessor::LexUnexpandedToken); if (Tmp.is(tok::eod)) @@ -497,7 +493,7 @@ Preprocessor::CheckEndOfDirective(StringRef DirType, bool EnableMacros, FixItHint Hint; if ((LangOpts.GNUMode || LangOpts.C99 || LangOpts.CPlusPlus) && !CurTokenLexer) - Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//"); + Hint = FixItHint::CreateInsertion(Tmp.getLocation(), "//"); unsigned DiagID = diag::ext_pp_extra_tokens_at_eol; // C++20 import or module directive has no '#' prefix. @@ -513,11 +509,11 @@ void Preprocessor::SuggestTypoedDirective(const Token &Tok, StringRef Directive) const { // If this is a `.S` file, treat unknown # directives as non-preprocessor // directives. - if (getLangOpts().AsmPreprocessor) return; + if (getLangOpts().AsmPreprocessor) + return; - std::vector<StringRef> Candidates = { - "if", "ifdef", "ifndef", "elif", "else", "endif" - }; + std::vector<StringRef> Candidates = {"if", "ifdef", "ifndef", + "elif", "else", "endif"}; if (LangOpts.C23 || LangOpts.CPlusPlus23) Candidates.insert(Candidates.end(), {"elifdef", "elifndef"}); @@ -708,7 +704,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, // directive mode. Tell the lexer this so any newlines we see will be // converted into an EOD token (this terminates the macro). CurPPLexer->ParsingPreprocessorDirective = true; - if (CurLexer) CurLexer->SetKeepWhitespaceMode(false); + if (CurLexer) + CurLexer->SetKeepWhitespaceMode(false); assert(Tok.is(tok::hash)); const char *Hashptr = CurLexer->getBufferLocation() - Tok.getLength(); @@ -722,7 +719,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, if (Tok.isNot(tok::raw_identifier)) { CurPPLexer->ParsingPreprocessorDirective = false; // Restore comment saving mode. - if (CurLexer) CurLexer->resetExtendedTokenMode(); + if (CurLexer) + CurLexer->resetExtendedTokenMode(); continue; } @@ -734,11 +732,12 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, StringRef RI = Tok.getRawIdentifier(); char FirstChar = RI[0]; - if (FirstChar >= 'a' && FirstChar <= 'z' && - FirstChar != 'i' && FirstChar != 'e') { + if (FirstChar >= 'a' && FirstChar <= 'z' && FirstChar != 'i' && + FirstChar != 'e') { CurPPLexer->ParsingPreprocessorDirective = false; // Restore comment saving mode. - if (CurLexer) CurLexer->resetExtendedTokenMode(); + if (CurLexer) + CurLexer->resetExtendedTokenMode(); continue; } @@ -755,7 +754,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, if (IdLen >= 20) { CurPPLexer->ParsingPreprocessorDirective = false; // Restore comment saving mode. - if (CurLexer) CurLexer->resetExtendedTokenMode(); + if (CurLexer) + CurLexer->resetExtendedTokenMode(); continue; } memcpy(DirectiveBuf, &DirectiveStr[0], IdLen); @@ -765,24 +765,25 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, if (Directive.starts_with("if")) { StringRef Sub = Directive.substr(2); if (Sub.empty() || // "if" - Sub == "def" || // "ifdef" - Sub == "ndef") { // "ifndef" + Sub == "def" || // "ifdef" + Sub == "ndef") { // "ifndef" // We know the entire #if/#ifdef/#ifndef block will be skipped, don't // bother parsing the condition. DiscardUntilEndOfDirective(); - CurPPLexer->pushConditionalLevel(Tok.getLocation(), /*wasskipping*/true, - /*foundnonskip*/false, - /*foundelse*/false); + CurPPLexer->pushConditionalLevel(Tok.getLocation(), + /*wasskipping*/ true, + /*foundnonskip*/ false, + /*foundelse*/ false); } else { SuggestTypoedDirective(Tok, Directive); } } else if (Directive[0] == 'e') { StringRef Sub = Directive.substr(1); - if (Sub == "ndif") { // "endif" + if (Sub == "ndif") { // "endif" PPConditionalInfo CondInfo; CondInfo.WasSkipping = true; // Silence bogus warning. bool InCond = CurPPLexer->popConditionalLevel(CondInfo); - (void)InCond; // Silence warning in no-asserts mode. + (void)InCond; // Silence warning in no-asserts mode. assert(!InCond && "Can't be skipping if not in a conditional!"); // If we popped the outermost skipping block, we're done skipping! @@ -828,9 +829,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, Callbacks->Else(Tok.getLocation(), CondInfo.IfLoc); break; } else { - DiscardUntilEndOfDirective(); // C99 6.10p4. + DiscardUntilEndOfDirective(); // C99 6.10p4. } - } else if (Sub == "lif") { // "elif". + } else if (Sub == "lif") { // "elif". PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel(); if (!CondInfo.WasSkipping) @@ -954,7 +955,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, CurPPLexer->ParsingPreprocessorDirective = false; // Restore comment saving mode. - if (CurLexer) CurLexer->resetExtendedTokenMode(); + if (CurLexer) + CurLexer->resetExtendedTokenMode(); } // Finally, if we are out of the conditional (saw an #endif or ran off the end @@ -1268,14 +1270,12 @@ OptionalFileEntryRef Preprocessor::LookupEmbedFile(StringRef Filename, class Preprocessor::ResetMacroExpansionHelper { public: ResetMacroExpansionHelper(Preprocessor *pp) - : PP(pp), save(pp->DisableMacroExpansion) { + : PP(pp), save(pp->DisableMacroExpansion) { if (pp->MacroExpansionInDirectivesOverride) pp->DisableMacroExpansion = false; } - ~ResetMacroExpansionHelper() { - PP->DisableMacroExpansion = save; - } + ~ResetMacroExpansionHelper() { PP->DisableMacroExpansion = save; } private: Preprocessor *PP; @@ -1320,7 +1320,8 @@ void Preprocessor::HandleDirective(Token &Result) { // mode. Tell the lexer this so any newlines we see will be converted into an // EOD token (which terminates the directive). CurPPLexer->ParsingPreprocessorDirective = true; - if (CurLexer) CurLexer->SetKeepWhitespaceMode(false); + if (CurLexer) + CurLexer->SetKeepWhitespaceMode(false); bool ImmediatelyAfterTopLevelIfndef = CurPPLexer->MIOpt.getImmediatelyAfterTopLevelIfndef(); @@ -1331,7 +1332,8 @@ void Preprocessor::HandleDirective(Token &Result) { // We are about to read a token. For the multiple-include optimization FA to // work, we have to remember if we had read any tokens *before* this // pp-directive. - bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal(); + bool ReadAnyTokensBeforeDirective = + CurPPLexer->MIOpt.getHasReadAnyTokensVal(); // Save the directive-introducing token('#' and import/module in C++20) in // case we need to return it later. @@ -1392,14 +1394,14 @@ void Preprocessor::HandleDirective(Token &Result) { // optimization, i.e. allow the null directive to appear outside of the // include guard and still enable the multiple-include optimization. CurPPLexer->MIOpt.SetReadToken(ReadAnyTokensBeforeDirective); - return; // null directive. + return; // null directive. case tok::code_completion: setCodeCompletionReached(); if (CodeComplete) CodeComplete->CodeCompleteDirective( - CurPPLexer->getConditionalStackDepth() > 0); + CurPPLexer->getConditionalStackDepth() > 0); return; - case tok::numeric_constant: // # 7 GNU line marker directive. + case tok::numeric_constant: // # 7 GNU line marker directive. // In a .S file "# 4" may be a comment so don't treat it as a preprocessor // directive. However do permit it in the predefines file, as we use line // markers to mark the builtin macros as being in a system header. @@ -1409,11 +1411,13 @@ void Preprocessor::HandleDirective(Token &Result) { return HandleDigitDirective(Result); default: IdentifierInfo *II = Result.getIdentifierInfo(); - if (!II) break; // Not an identifier. + if (!II) + break; // Not an identifier. // Ask what the preprocessor keyword ID is. switch (II->getPPKeywordID()) { - default: break; + default: + break; // C99 6.10.1 - Conditional Inclusion. case tok::pp_if: return HandleIfDirective(Result, Introducer, @@ -1494,10 +1498,10 @@ void Preprocessor::HandleDirective(Token &Result) { case tok::pp_embed: return HandleEmbedDirective(Introducer.getLocation(), Result); case tok::pp_assert: - //isExtension = true; // FIXME: implement #assert + // isExtension = true; // FIXME: implement #assert break; case tok::pp_unassert: - //isExtension = true; // FIXME: implement #unassert + // isExtension = true; // FIXME: implement #unassert break; case tok::pp___public_macro: @@ -1531,7 +1535,7 @@ void Preprocessor::HandleDirective(Token &Result) { // Enter this token stream so that we re-lex the tokens. Make sure to // enable macro expansion, in case the token after the # is an identifier // that is expanded. - EnterTokenStream(std::move(Toks), 2, false, /*IsReinject*/false); + EnterTokenStream(std::move(Toks), 2, false, /*IsReinject*/ false); return; } @@ -1547,9 +1551,8 @@ void Preprocessor::HandleDirective(Token &Result) { /// GetLineValue - Convert a numeric token into an unsigned value, emitting /// Diagnostic DiagID if it is invalid, and returning the value in Val. -static bool GetLineValue(Token &DigitTok, unsigned &Val, - unsigned DiagID, Preprocessor &PP, - bool IsGNULineDirective=false) { +static bool GetLineValue(Token &DigitTok, unsigned &Val, unsigned DiagID, + Preprocessor &PP, bool IsGNULineDirective = false) { if (DigitTok.isNot(tok::numeric_constant)) { PP.Diag(DigitTok, DiagID); @@ -1578,12 +1581,13 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, if (!isDigit(DigitTokBegin[i])) { PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i), - diag::err_pp_line_digit_sequence) << IsGNULineDirective; + diag::err_pp_line_digit_sequence) + << IsGNULineDirective; PP.DiscardUntilEndOfDirective(); return true; } - unsigned NextVal = Val*10+(DigitTokBegin[i]-'0'); + unsigned NextVal = Val * 10 + (DigitTokBegin[i] - '0'); if (NextVal < Val) { // overflow. PP.Diag(DigitTok, DiagID); PP.DiscardUntilEndOfDirective(); @@ -1594,7 +1598,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, if (DigitTokBegin[0] == '0' && Val) PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal) - << IsGNULineDirective; + << IsGNULineDirective; return false; } @@ -1614,7 +1618,7 @@ void Preprocessor::HandleLineDirective() { // Validate the number and convert it to an unsigned. unsigned LineNo; - if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer,*this)) + if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer, *this)) return; if (LineNo == 0) @@ -1690,7 +1694,8 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, unsigned FlagVal; Token FlagTok; PP.Lex(FlagTok); - if (FlagTok.is(tok::eod)) return false; + if (FlagTok.is(tok::eod)) + return false; if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP)) return true; @@ -1698,8 +1703,10 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, IsFileEntry = true; PP.Lex(FlagTok); - if (FlagTok.is(tok::eod)) return false; - if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP)) + if (FlagTok.is(tok::eod)) + return false; + if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, + PP)) return true; } else if (FlagVal == 2) { IsFileExit = true; @@ -1708,7 +1715,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, // If we are leaving the current presumed file, check to make sure the // presumed include stack isn't empty! FileID CurFileID = - SM.getDecomposedExpansionLoc(FlagTok.getLocation()).first; + SM.getDecomposedExpansionLoc(FlagTok.getLocation()).first; PresumedLoc PLoc = SM.getPresumedLoc(FlagTok.getLocation()); if (PLoc.isInvalid()) return true; @@ -1724,8 +1731,10 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, } PP.Lex(FlagTok); - if (FlagTok.is(tok::eod)) return false; - if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP)) + if (FlagTok.is(tok::eod)) + return false; + if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, + PP)) return true; } @@ -1739,7 +1748,8 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, FileKind = SrcMgr::C_System; PP.Lex(FlagTok); - if (FlagTok.is(tok::eod)) return false; + if (FlagTok.is(tok::eod)) + return false; if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP)) return true; @@ -1753,7 +1763,8 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, FileKind = SrcMgr::C_ExternCSystem; PP.Lex(FlagTok); - if (FlagTok.is(tok::eod)) return false; + if (FlagTok.is(tok::eod)) + return false; // There are no more valid flags here. PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag); @@ -1843,8 +1854,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { /// HandleUserDiagnosticDirective - Handle a #warning or #error directive. /// -void Preprocessor::HandleUserDiagnosticDirective(Token &Tok, - bool isWarning) { +void Preprocessor::HandleUserDiagnosticDirective(Token &Tok, bool isWarning) { // Read the rest of the line raw. We do this because we don't want macros // to be expanded and we don't require that the tokens be valid preprocessing // tokens. For example, this is allowed: "#warning ` 'foo". GCC does @@ -1923,7 +1933,7 @@ void Preprocessor::HandleMacroPublicDirective(Token &Tok) { // Note that this macro has now been exported. appendMacroDirective(II, AllocateVisibilityMacroDirective( - MacroNameTok.getLocation(), /*isPublic=*/true)); + MacroNameTok.getLocation(), /*isPublic=*/true)); } /// Handle a #private directive. @@ -2006,13 +2016,12 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, } // Skip the brackets. - Buffer = Buffer.substr(1, Buffer.size()-2); + Buffer = Buffer.substr(1, Buffer.size() - 2); return isAngled; } /// Push a token onto the token stream containing an annotation. -void Preprocessor::EnterAnnotationToken(SourceRange Range, - tok::TokenKind Kind, +void Preprocessor::EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, void *AnnotationVal) { // FIXME: Produce this as the current token directly, rather than // allocating a new token for it. @@ -2214,8 +2223,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, case ImportAction::SkippedModuleImport: break; case ImportAction::ModuleBegin: - EnterAnnotationToken(SourceRange(HashLoc, EndLoc), - tok::annot_module_begin, Action.ModuleForHeader); + EnterAnnotationToken(SourceRange(HashLoc, EndLoc), tok::annot_module_begin, + Action.ModuleForHeader); break; case ImportAction::HeaderUnitImport: EnterAnnotationToken(SourceRange(HashLoc, EndLoc), tok::annot_header_unit, @@ -2370,16 +2379,21 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( StringRef Filename = getSpelling(FilenameTok, FilenameBuffer); SourceLocation CharEnd = FilenameTok.getEndLoc(); - CharSourceRange FilenameRange - = CharSourceRange::getCharRange(FilenameTok.getLocation(), CharEnd); + CharSourceRange FilenameRange = + CharSourceRange::getCharRange(FilenameTok.getLocation(), CharEnd); StringRef OriginalFilename = Filename; bool isAngled = - GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); + GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. if (Filename.empty()) return {ImportAction::None}; + if (Filename.ends_with(" ") || Filename.ends_with(".")) { + unsigned Selection = Filename.ends_with(".") ? 1 : 0; + Diag(FilenameTok, diag::pp_nonportable_path_trailing) + << Filename << Selection; + } bool IsImportDecl = HashLoc.isInvalid(); SourceLocation StartLoc = IsImportDecl ? IncludeTok.getLocation() : HashLoc; @@ -2633,7 +2647,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( // module corresponding to the named header. if (IsImportDecl && !ModuleToImport) { Diag(FilenameTok, diag::err_header_import_not_header_unit) - << OriginalFilename << File->getName(); + << OriginalFilename << File->getName(); return {ImportAction::None}; } @@ -2680,7 +2694,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( if (trySimplifyPath(Components, RealPathName, BackslashStyle)) { SmallString<128> Path; - Path.reserve(Name.size()+2); + Path.reserve(Name.size() + 2); Path.push_back(isAngled ? '<' : '"'); const auto IsSep = [BackslashStyle](char c) { @@ -2709,11 +2723,11 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( Path.push_back(isAngled ? '>' : '"'); continue; } - assert(IsSep(NameWithoriginalSlashes[Path.size()-1])); + assert(IsSep(NameWithoriginalSlashes[Path.size() - 1])); do - Path.push_back(NameWithoriginalSlashes[Path.size()-1]); + Path.push_back(NameWithoriginalSlashes[Path.size() - 1]); while (Path.size() <= NameWithoriginalSlashes.size() && - IsSep(NameWithoriginalSlashes[Path.size()-1])); + IsSep(NameWithoriginalSlashes[Path.size() - 1])); } #if defined(_WIN32) @@ -2728,8 +2742,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( (FileCharacter == SrcMgr::C_User || warnByDefaultOnWrongCase(Name)) ? diag::pp_nonportable_path : diag::pp_nonportable_system_path; - Diag(FilenameTok, DiagId) << Path << - FixItHint::CreateReplacement(FilenameRange, Path); + Diag(FilenameTok, DiagId) + << Path << FixItHint::CreateReplacement(FilenameRange, Path); } } @@ -2763,7 +2777,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( } // Check that we don't have infinite #include recursion. - if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) { + if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth - 1) { Diag(FilenameTok, diag::err_pp_include_too_deep); HasReachedMaxIncludeDepth = true; return {ImportAction::None}; @@ -2854,7 +2868,7 @@ void Preprocessor::HandleMicrosoftImportDirective(Token &Tok) { // does, so we ignore it and error out. However, #import can optionally have // trailing attributes that span multiple lines. We're going to eat those // so we can continue processing from there. - Diag(Tok, diag::err_pp_import_directive_ms ); + Diag(Tok, diag::err_pp_import_directive_ms); // Read tokens until we get to the end of the directive. Note that the // directive can be split over multiple lines using the backslash character. @@ -2865,7 +2879,7 @@ void Preprocessor::HandleMicrosoftImportDirective(Token &Tok) { /// void Preprocessor::HandleImportDirective(SourceLocation HashLoc, Token &ImportTok) { - if (!LangOpts.ObjC) { // #import is standard for ObjC. + if (!LangOpts.ObjC) { // #import is standard for ObjC. if (LangOpts.MSVCCompat) return HandleMicrosoftImportDirective(ImportTok); Diag(ImportTok, diag::ext_pp_import_directive); @@ -2909,23 +2923,22 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc, /// closing ), updating MI with what we learn. Return true if an error occurs /// parsing the param list. bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { - SmallVector<IdentifierInfo*, 32> Parameters; + SmallVector<IdentifierInfo *, 32> Parameters; while (true) { LexUnexpandedNonComment(Tok); switch (Tok.getKind()) { case tok::r_paren: // Found the end of the parameter list. - if (Parameters.empty()) // #define FOO() + if (Parameters.empty()) // #define FOO() return false; // Otherwise we have #define FOO(A,) Diag(Tok, diag::err_pp_expected_ident_in_arg_list); return true; - case tok::ellipsis: // #define X(... -> C99 varargs + case tok::ellipsis: // #define X(... -> C99 varargs if (!LangOpts.C99) - Diag(Tok, LangOpts.CPlusPlus11 ? - diag::warn_cxx98_compat_variadic_macro : - diag::ext_variadic_macro); + Diag(Tok, LangOpts.CPlusPlus11 ? diag::warn_cxx98_compat_variadic_macro + : diag::ext_variadic_macro); // OpenCL v1.2 s6.9.e: variadic macros are not supported. if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus) { @@ -2943,7 +2956,7 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { MI->setIsC99Varargs(); MI->setParameterList(Parameters, BP); return false; - case tok::eod: // #define X( + case tok::eod: // #define X( Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); return true; default: @@ -2970,15 +2983,15 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { LexUnexpandedNonComment(Tok); switch (Tok.getKind()) { - default: // #define X(A B + default: // #define X(A B Diag(Tok, diag::err_pp_expected_comma_in_arg_list); return true; case tok::r_paren: // #define X(A) MI->setParameterList(Parameters, BP); return false; - case tok::comma: // #define X(A, + case tok::comma: // #define X(A, break; - case tok::ellipsis: // #define X(A... -> GCC extension + case tok::ellipsis: // #define X(A... -> GCC extension // Diagnose extension. Diag(Tok, diag::ext_named_variadic_macro); @@ -3245,7 +3258,7 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( continue; } else { Diag(Tok, diag::err_pp_stringize_not_parameter) - << LastTok.is(tok::hashat); + << LastTok.is(tok::hashat); return nullptr; } } @@ -3267,8 +3280,9 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( if (VAOCtx.isInVAOpt()) { assert(Tok.is(tok::eod) && "Must be at End Of preprocessing Directive"); Diag(Tok, diag::err_pp_expected_after) - << LastTok.getKind() << tok::r_paren; - Diag(VAOCtx.getUnmatchedOpeningParenLoc(), diag::note_matching) << tok::l_paren; + << LastTok.getKind() << tok::r_paren; + Diag(VAOCtx.getUnmatchedOpeningParenLoc(), diag::note_matching) + << tok::l_paren; return nullptr; } } @@ -3305,12 +3319,14 @@ void Preprocessor::HandleDefineDirective( // If we are supposed to keep comments in #defines, reenable comment saving // mode. - if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments); + if (CurLexer) + CurLexer->SetCommentRetentionState(KeepMacroComments); MacroInfo *const MI = ReadOptionalMacroParameterListAndBody( MacroNameTok, ImmediatelyAfterHeaderGuard); - if (!MI) return; + if (!MI) + return; if (MacroShadowsKeyword && !isConfigurationPattern(MacroNameTok, MI, getLangOpts())) { @@ -3324,8 +3340,8 @@ void Preprocessor::HandleDefineDirective( Diag(MI->getReplacementToken(0), diag::err_paste_at_start); return; } - if (MI->getReplacementToken(NumTokens-1).is(tok::hashhash)) { - Diag(MI->getReplacementToken(NumTokens-1), diag::err_paste_at_end); + if (MI->getReplacementToken(NumTokens - 1).is(tok::hashhash)) { + Diag(MI->getReplacementToken(NumTokens - 1), diag::err_paste_at_end); return; } } @@ -3334,7 +3350,7 @@ void Preprocessor::HandleDefineDirective( if (SkippingUntilPCHThroughHeader) { const MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo()); if (!OtherMI || !MI->isIdenticalTo(*OtherMI, *this, - /*Syntactic=*/LangOpts.MicrosoftExt)) + /*Syntactic=*/LangOpts.MicrosoftExt)) Diag(MI->getDefinitionLoc(), diag::warn_pp_macro_def_mismatch_with_pch) << MacroNameTok.getIdentifierInfo(); // Issue the diagnostic but allow the change if msvc extensions are enabled @@ -3344,7 +3360,8 @@ void Preprocessor::HandleDefineDirective( // Finally, if this identifier already had a macro defined for it, verify that // the macro bodies are identical, and issue diagnostics if they are not. - if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) { + if (const MacroInfo *OtherMI = + getMacroInfo(MacroNameTok.getIdentifierInfo())) { // Final macros are hard-mode: they always warn. Even if the bodies are // identical. Even if they are in system headers. Even if they are things we // would silently allow in the past. @@ -3385,9 +3402,10 @@ void Preprocessor::HandleDefineDirective( // Macros must be identical. This means all tokens and whitespace // separation must be the same. C99 6.10.3p2. else if (!OtherMI->isAllowRedefinitionsWithoutWarning() && - !MI->isIdenticalTo(*OtherMI, *this, /*Syntactic=*/LangOpts.MicrosoftExt)) { + !MI->isIdenticalTo(*OtherMI, *this, + /*Syntactic=*/LangOpts.MicrosoftExt)) { Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef) - << MacroNameTok.getIdentifierInfo(); + << MacroNameTok.getIdentifierInfo(); Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition); } } @@ -3472,8 +3490,7 @@ void Preprocessor::HandleUndefDirective() { /// true if any tokens have been returned or pp-directives activated before this /// \#ifndef has been lexed. /// -void Preprocessor::HandleIfdefDirective(Token &Result, - const Token &HashToken, +void Preprocessor::HandleIfdefDirective(Token &Result, const Token &HashToken, bool isIfndef, bool ReadAnyTokensBeforeDirective) { ++NumIf; @@ -3514,7 +3531,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, } // If there is a macro, process it. - if (MI) // Mark it used. + if (MI) // Mark it used. markMacroAsUsed(MI); if (Callbacks) { @@ -3524,16 +3541,17 @@ void Preprocessor::HandleIfdefDirective(Token &Result, Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok, MD); } - bool RetainExcludedCB = PPOpts.RetainExcludedConditionalBlocks && - getSourceManager().isInMainFile(DirectiveTok.getLocation()); + bool RetainExcludedCB = + PPOpts.RetainExcludedConditionalBlocks && + getSourceManager().isInMainFile(DirectiveTok.getLocation()); // Should we include the stuff contained by this directive? if (PPOpts.SingleFileParseMode && !MI) { // In 'single-file-parse mode' undefined identifiers trigger parsing of all // the directive blocks. CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), - /*wasskip*/false, /*foundnonskip*/false, - /*foundelse*/false); + /*wasskip*/ false, /*foundnonskip*/ false, + /*foundelse*/ false); } else if (PPOpts.SingleModuleParseMode && !MI) { // In 'single-module-parse mode' undefined identifiers trigger skipping of // all the directive blocks. We lie here and set FoundNonSkipPortion so that @@ -3544,8 +3562,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result, } else if (!MI == isIfndef || RetainExcludedCB) { // Yes, remember that we are inside a conditional, then lex the next token. CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), - /*wasskip*/false, /*foundnonskip*/true, - /*foundelse*/false); + /*wasskip*/ false, /*foundnonskip*/ true, + /*foundelse*/ false); } else { // No, skip the contents of this block. SkipExcludedConditionalBlock(HashToken.getLocation(), @@ -3557,8 +3575,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, /// HandleIfDirective - Implements the \#if directive. /// -void Preprocessor::HandleIfDirective(Token &IfToken, - const Token &HashToken, +void Preprocessor::HandleIfDirective(Token &IfToken, const Token &HashToken, bool ReadAnyTokensBeforeDirective) { ++NumIf; @@ -3586,15 +3603,17 @@ void Preprocessor::HandleIfDirective(Token &IfToken, IfToken.getLocation(), DER.ExprRange, (ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False)); - bool RetainExcludedCB = PPOpts.RetainExcludedConditionalBlocks && - getSourceManager().isInMainFile(IfToken.getLocation()); + bool RetainExcludedCB = + PPOpts.RetainExcludedConditionalBlocks && + getSourceManager().isInMainFile(IfToken.getLocation()); // Should we include the stuff contained by this directive? if (PPOpts.SingleFileParseMode && DER.IncludedUndefinedIds) { // In 'single-file-parse mode' undefined identifiers trigger parsing of all // the directive blocks. - CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false, - /*foundnonskip*/false, /*foundelse*/false); + CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/ false, + /*foundnonskip*/ false, + /*foundelse*/ false); } else if (PPOpts.SingleModuleParseMode && DER.IncludedUndefinedIds) { // In 'single-module-parse mode' undefined identifiers trigger skipping of // all the directive blocks. We lie here and set FoundNonSkipPortion so that @@ -3604,8 +3623,9 @@ void Preprocessor::HandleIfDirective(Token &IfToken, /*FoundElse=*/false); } else if (ConditionalTrue || RetainExcludedCB) { // Yes, remember that we are inside a conditional, then lex the next token. - CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false, - /*foundnonskip*/true, /*foundelse*/false); + CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/ false, + /*foundnonskip*/ true, + /*foundelse*/ false); } else { // No, skip the contents of this block. SkipExcludedConditionalBlock(HashToken.getLocation(), IfToken.getLocation(), @@ -3659,19 +3679,21 @@ void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) { CurPPLexer->MIOpt.EnterTopLevelConditional(); // If this is a #else with a #else before it, report the error. - if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else); + if (CI.FoundElse) + Diag(Result, diag::pp_err_else_after_else); if (Callbacks) Callbacks->Else(Result.getLocation(), CI.IfLoc); bool RetainExcludedCB = PPOpts.RetainExcludedConditionalBlocks && - getSourceManager().isInMainFile(Result.getLocation()); + getSourceManager().isInMainFile(Result.getLocation()); if ((PPOpts.SingleFileParseMode && !CI.FoundNonSkip) || RetainExcludedCB) { // In 'single-file-parse mode' undefined identifiers trigger parsing of all // the directive blocks. - CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false, - /*foundnonskip*/false, /*foundelse*/true); + CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/ false, + /*foundnonskip*/ false, + /*foundelse*/ true); return; } @@ -3744,14 +3766,16 @@ void Preprocessor::HandleElifFamilyDirective(Token &ElifToken, } } - bool RetainExcludedCB = PPOpts.RetainExcludedConditionalBlocks && - getSourceManager().isInMainFile(ElifToken.getLocation()); + bool RetainExcludedCB = + PPOpts.RetainExcludedConditionalBlocks && + getSourceManager().isInMainFile(ElifToken.getLocation()); if ((PPOpts.SingleFileParseMode && !CI.FoundNonSkip) || RetainExcludedCB) { // In 'single-file-parse mode' undefined identifiers trigger parsing of all // the directive blocks. - CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/false, - /*foundnonskip*/false, /*foundelse*/false); + CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/ false, + /*foundnonskip*/ false, + /*foundelse*/ false); return; } diff --git a/clang/test/Preprocessor/nonportable-trailing-whitespace.c b/clang/test/Preprocessor/nonportable-trailing-whitespace.c new file mode 100644 index 0000000000000..4b1b62a6a2094 --- /dev/null +++ b/clang/test/Preprocessor/nonportable-trailing-whitespace.c @@ -0,0 +1,15 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: touch %t/simple.h +// RUN: %clang_cc1 -fsyntax-only -I%t -Wnonportable-include-path -verify %s + +// Trailing whitespace in include path should warn. +#include "simple.h " // expected-warning {{non-portable path to file 'simple.h '; specified path contains trailing whitespace}} \ + // expected-error {{'simple.h ' file not found}} + +// Trailing dots in include path should warn. +#include "simple.h." // expected-warning {{non-portable path to file 'simple.h.'; specified path contains trailing dots}} \ + // expected-error {{'simple.h.' file not found}} + +// Correct path should not produce any warnings. +#include "simple.h" // no-warning \ No newline at end of file _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
