Author: Amelia Jochna
Date: 2026-05-21T14:42:25+02:00
New Revision: 4d7b7dff60c3c3c3858e91858d2f74a512d71538

URL: 
https://github.com/llvm/llvm-project/commit/4d7b7dff60c3c3c3858e91858d2f74a512d71538
DIFF: 
https://github.com/llvm/llvm-project/commit/4d7b7dff60c3c3c3858e91858d2f74a512d71538.diff

LOG: [Clang] Add warning for non-portable include paths with trailing 
whitespace or dots (#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.

Fixes #96064

Added: 
    clang/test/Preprocessor/nonportable-trailing-whitespace-win.c
    clang/test/Preprocessor/nonportable-trailing-whitespace.c

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticLexKinds.td
    clang/lib/Lex/PPDirectives.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6838cf3defcc13..e88e134c3a9b56 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -541,9 +541,11 @@ Improvements to Clang's diagnostics
 - Clang now errors when a function declaration aliases a variable or vice 
versa. (#GH195550)
 
 - Added ``-Wattribute-alias`` to diagnose type mismatches between an alias and 
its aliased function. (#GH195550)
-  
+
 - The diagnostics around ``__block`` now explain why a variable cannot be 
marked ``__block``. (#GH197213)
 
+- Extended ``-Wnonportable-include-path`` to warn about trailing whitespace 
and dots in ``#include`` paths. (#GH190610)
+
 Improvements to Clang's time-trace
 ----------------------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 264013ed7306a5..8031f99419bdc9 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -977,6 +977,7 @@ def MemsetTransposedArgs : 
DiagGroup<"memset-transposed-args">;
 def DynamicClassMemaccess : DiagGroup<"dynamic-class-memaccess">;
 def NonTrivialMemcall : DiagGroup<"nontrivial-memcall">;
 def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess", 
[NonTrivialMemcall]>;
+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 0ac7ac27a0271f..383bf1a7fdb3f5 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 
diff ers in case from file"
   " name on disk">;
 def pp_nonportable_path : NonportablePath,
   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|dot}1">;
+def pp_nonportable_path_trailing : NonportablePathTrailing,
+  InGroup<NonportableIncludePath>;
+def pp_nonportable_system_path_trailing : NonportablePathTrailing, 
DefaultIgnore,
+  InGroup<NonportableSystemIncludePath>;
 def pp_nonportable_path_separator : Warning<
   "non-portable path to file '%0'; specified path contains backslashes">,
   DefaultIgnore, InGroup<NonportableIncludePathSeparator>;

diff  --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 6e90f20572f1f5..12d3c765b15bc5 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -2382,6 +2382,11 @@ Preprocessor::ImportAction 
Preprocessor::HandleHeaderIncludeOrImport(
   // 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;

diff  --git a/clang/test/Preprocessor/nonportable-trailing-whitespace-win.c 
b/clang/test/Preprocessor/nonportable-trailing-whitespace-win.c
new file mode 100644
index 00000000000000..f957877a68d146
--- /dev/null
+++ b/clang/test/Preprocessor/nonportable-trailing-whitespace-win.c
@@ -0,0 +1,18 @@
+// 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
+// REQUIRES: system-windows
+
+// On Windows, the filesystem silently strips trailing whitespace and dots
+// from filenames, so the include succeeds. We should still emit a
+// portability warning but no file-not-found error.
+
+// Trailing whitespace: warn about non-portable path, but file is found.
+#include "simple.h " // expected-warning {{non-portable path to file 'simple.h 
'; specified path contains trailing whitespace}}
+
+// Trailing dots: warn about non-portable path, but file is found.
+#include "simple.h." // expected-warning {{non-portable path to file 
'simple.h.'; specified path contains trailing dot}}
+
+// Correct path: no diagnostics expected.
+#include "simple.h" // no-warning

diff  --git a/clang/test/Preprocessor/nonportable-trailing-whitespace.c 
b/clang/test/Preprocessor/nonportable-trailing-whitespace.c
new file mode 100644
index 00000000000000..569fe3ec34b38f
--- /dev/null
+++ b/clang/test/Preprocessor/nonportable-trailing-whitespace.c
@@ -0,0 +1,20 @@
+// 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
+// UNSUPPORTED: system-windows
+
+// On non-Windows systems, trailing whitespace and dots in include paths
+// produce both a portability warning and a file-not-found error,
+// because the filesystem treats them as part of the filename.
+
+// Trailing whitespace: warn about non-portable path, error because file not 
found.
+#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: warn about non-portable path, error because file not found.
+#include "simple.h." // expected-warning {{non-portable path to file 
'simple.h.'; specified path contains trailing dot}} \
+                     // expected-error {{'simple.h.' file not found}}
+
+// Correct path: no diagnostics expected.
+#include "simple.h" // no-warning


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to