From ac615e10471f45031e69bd3eda6795dd8b75e4ad Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Tue, 15 Oct 2024 07:53:56 +0200
Subject: [PATCH] libcpp: Add -Wtrailing-blanks warning

Trailing blanks is something even git diff diagnoses; while it is a coding
style issue, if it is so common that git diff diagnoses it, I think it could
be useful to various projects to check that at compile time.

Dunno if it should be included in -Wextra, currently it isn't, and due to
tons of trailing whitespace in our sources, haven't enabled it for when
building gcc itself either.

Note, git diff also diagnoses indentation with tab following space, wonder
if we couldn't have trivial warning options where one would simply ask for
checking of indentation with no tabs, just spaces vs. indentation with
tabs followed by spaces (but never tab width or more spaces in the
indentation).  I think that would be easy to do also on the libcpp side.
Checking how much something should be exactly indented requires syntax
analysis (at least some limited one) and can consider columns of first token
on line, but what the exact indentation blanks were is something only libcpp
knows.

On Thu, Sep 19, 2024 at 08:17:24AM +0200, Richard Biener wrote:
> Generally I like diagnosing this early.  For the above I'd say -Wtrailing-whitespace=
> with a set of things to diagnose (and a sane default - just spaces and tabs - for
> -Wtrailiing-whitespace) would be nice.  As for naming possibly follow the
> is{space,blank,cntrl} character classifications?  If those are a good
> fit, that is.

The patch currently allows blank (' ' '\t') and space (' ' '\t' '\f' '\v'),
cntrl not yet added, not anything non-ASCII, but in theory could
be added later (though, non-ASCII would be just for inside of comments,
say non-breaking space etc. in the source is otherwise an error).

2024-10-15  Jakub Jelinek  <jakub@redhat.com>

libcpp/
	* include/cpplib.h (struct cpp_options): Add
	cpp_warn_trailing_whitespace member.
	(enum cpp_warning_reason): Add CPP_W_TRAILING_WHITESPACE.
	* internal.h (struct _cpp_line_note): Document 'W' line note.
	* lex.cc (_cpp_clean_line): Add 'W' line note for trailing whitespace
	except for trailing whitespace after backslash.  Formatting fix.
	(_cpp_process_line_notes): Emit -Wtrailing-whitespace diagnostics.
	Formatting fixes.
	(lex_raw_string): Clear type on 'W' notes.
gcc/
	* doc/invoke.texi (Wtrailing-whitespace): Document.
gcc/c-family/
	* c.opt (Wtrailing-whitespace=): New option.
	(Wtrailing-whitespace): New alias.
	* c.opt.urls: Regenerate.
gcc/testsuite/
	* c-c++-common/cpp/Wtrailing-whitespace-1.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-2.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-3.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-4.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-5.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-6.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-7.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-8.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-9.c: New test.
	* c-c++-common/cpp/Wtrailing-whitespace-10.c: New test.
---
 gcc/c-family/c.opt                            | 20 +++++++
 gcc/c-family/c.opt.urls                       |  6 ++
 gcc/doc/invoke.texi                           | 18 +++++-
 .../c-c++-common/cpp/Wtrailing-whitespace-1.c | 37 ++++++++++++
 .../cpp/Wtrailing-whitespace-10.c             | 29 ++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-2.c | 37 ++++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-3.c | 43 ++++++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-4.c | 28 ++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-5.c | 28 ++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-6.c | 38 +++++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-7.c | 38 +++++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-8.c | 44 +++++++++++++++
 .../c-c++-common/cpp/Wtrailing-whitespace-9.c | 29 ++++++++++
 libcpp/include/cpplib.h                       |  6 +-
 libcpp/internal.h                             |  4 +-
 libcpp/lex.cc                                 | 56 ++++++++++++++-----
 16 files changed, 444 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-1.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-10.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-2.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-3.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-4.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-5.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-6.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-7.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-8.c
 create mode 100644 gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-9.c

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 1f2e72a0bb73..f758d7b941c0 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1466,6 +1466,26 @@ Wtraditional-conversion
 C ObjC Var(warn_traditional_conversion) Warning
 Warn of prototypes causing type conversions different from what would happen in the absence of prototype.
 
+Enum
+Name(warn_trailing_whitespace_kind) Type(int) UnknownError(argument %qs to %<-Wtrailing-whitespace=%> not recognized)
+
+EnumValue
+Enum(warn_trailing_whitespace_kind) String(none) Value(0)
+
+EnumValue
+Enum(warn_trailing_whitespace_kind) String(blank) Value(1)
+
+EnumValue
+Enum(warn_trailing_whitespace_kind) String(space) Value(2)
+
+Wtrailing-whitespace=
+C ObjC C++ ObjC++ CPP(cpp_warn_trailing_whitespace) CppReason(CPP_W_TRAILING_WHITESPACE) Enum(warn_trailing_whitespace_kind) Joined RejectNegative Var(warn_trailing_whitespace) Init(0) Warning
+Warn about trailing whitespace on lines except when in raw string literals.
+
+Wtrailing-whitespace
+C ObjC C++ ObjC++ Alias(Wtrailing-whitespace=,blank,none) Warning
+Warn about trailing whitespace on lines except when in raw string literals.   Equivalent to Wtrailing-whitespace=blank when enabled or Wtrailing-whitespace=none when disabled.
+
 Wtrigraphs
 C ObjC C++ ObjC++ CPP(warn_trigraphs) CppReason(CPP_W_TRIGRAPHS) Var(cpp_warn_trigraphs) Init(2) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn if trigraphs are encountered that might affect the meaning of the program.
diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls
index b1593ef41401..c1738095e6dd 100644
--- a/gcc/c-family/c.opt.urls
+++ b/gcc/c-family/c.opt.urls
@@ -864,6 +864,12 @@ UrlSuffix(gcc/Warning-Options.html#index-Wno-traditional)
 Wtraditional-conversion
 UrlSuffix(gcc/Warning-Options.html#index-Wno-traditional-conversion)
 
+Wtrailing-whitespace=
+UrlSuffix(gcc/Warning-Options.html#index-Wno-trailing-whitespace)
+
+Wtrailing-whitespace
+UrlSuffix(gcc/Warning-Options.html#index-Wno-trailing-whitespace)
+
 Wtrigraphs
 UrlSuffix(gcc/Warning-Options.html#index-Wtrigraphs)
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 575dffd2a2f5..4f4ca6375495 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -414,7 +414,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]}
 -Wswitch  -Wno-switch-bool  -Wswitch-default  -Wswitch-enum
 -Wno-switch-outside-range  -Wno-switch-unreachable  -Wsync-nand
--Wsystem-headers  -Wtautological-compare  -Wtrampolines  -Wtrigraphs
+-Wsystem-headers  -Wtautological-compare  -Wtrailing-whitespace
+-Wtrailing-whitespace=@var{kind}  -Wtrampolines  -Wtrigraphs
 -Wtrivial-auto-var-init  -Wno-tsan  -Wtype-limits  -Wundef
 -Wuninitialized  -Wunknown-pragmas
 -Wunsuffixed-float-constants
@@ -8773,6 +8774,21 @@ will always be false.
 
 This warning is enabled by @option{-Wall}.
 
+@opindex Wtrailing-whitespace
+@opindex Wno-trailing-whitespace
+@opindex Wtrailing-whitespace=
+@item -Wtrailing-whitespace
+@itemx -Wtrailing-whitespace=@var{kind}
+Warn about trailing whitespace at the end of lines, including inside of
+comments, but excluding trailing whitespace in raw string literals.
+@code{-Wtrailing-whitespace} is equivalent to
+@code{-Wtrailing-whitespace=blank} and warns just about trailing space and
+horizontal tab characters.  @code{-Wtrailing-whitespace=space} warns about
+those or trailing form feed or vertical tab characters.
+@code{-Wno-trailing-whitespace} or @code{-Wtrailing-whitespace=none}
+disables the warning, which is the default.
+This is a coding style warning.
+
 @opindex Wtrampolines
 @opindex Wno-trampolines
 @item -Wtrampolines
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-1.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-1.c
new file mode 100644
index 000000000000..ccfed0013c94
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace" } */
+
+int i;   
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int j;		
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-3 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace	
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .+1 } */
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-10.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-10.c
new file mode 100644
index 000000000000..6a4e9cd457bd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-10.c
@@ -0,0 +1,29 @@
+/* This test uses intentionally DOS line endings (CR+LF).  */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wno-trailing-whitespace" } */
+
+int i;   
+int j;		
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+
+ 
+ 
+
+ 
+ 
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace	
+*/
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-2.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-2.c
new file mode 100644
index 000000000000..b31c92502601
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-2.c
@@ -0,0 +1,37 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace=blank" } */
+
+int i;   
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int j;		
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-3 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace	
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .+1 } */
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-3.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-3.c
new file mode 100644
index 000000000000..3c3a9ac4db74
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-3.c
@@ -0,0 +1,43 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace=space" } */
+
+int i;   
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int j;		
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-3 } */
+
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace	
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace 
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .+1 } */
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-4.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-4.c
new file mode 100644
index 000000000000..ea01bb089494
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-4.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace=none" } */
+
+int i;   
+int j;		
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+
+ 
+ 
+
+ 
+ 
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace	
+*/
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-5.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-5.c
new file mode 100644
index 000000000000..075de3058f4b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-5.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wno-trailing-whitespace" } */
+
+int i;   
+int j;		
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+
+ 
+ 
+
+ 
+ 
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace	
+*/
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-6.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-6.c
new file mode 100644
index 000000000000..751f90e98460
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-6.c
@@ -0,0 +1,38 @@
+/* This test uses intentionally DOS line endings (CR+LF).  */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace" } */
+
+int i;   
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int j;		
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-3 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace	
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .+1 } */
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-7.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-7.c
new file mode 100644
index 000000000000..6f9bac345668
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-7.c
@@ -0,0 +1,38 @@
+/* This test uses intentionally DOS line endings (CR+LF).  */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace=blank" } */
+
+int i;   
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int j;		
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-3 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+
+ 
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace	
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .+1 } */
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-8.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-8.c
new file mode 100644
index 000000000000..29dae90e1e29
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-8.c
@@ -0,0 +1,44 @@
+/* This test uses intentionally DOS line endings (CR+LF).  */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace=space" } */
+
+int i;   
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int j;		
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-3 } */
+
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+ 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace	
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+// This is a comment with trailing whitespace 
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-1 } */
+/* This is a comment with trailing whitespace 
+*/
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .-2 } */
+/* { dg-warning "trailing whitespace" "" { target *-*-* } .+1 } */
+    
\ No newline at end of file
diff --git a/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-9.c b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-9.c
new file mode 100644
index 000000000000..9567a2fd34d2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/Wtrailing-whitespace-9.c
@@ -0,0 +1,29 @@
+/* This test uses intentionally DOS line endings (CR+LF).  */
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-options "-Wtrailing-whitespace=none" } */
+
+int i;   
+int j;		
+int \	
+  k \	
+  ;	
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+/* { dg-warning "backslash and newline separated by space" "" { target *-*-* } .-3 } */
+
+ 
+ 
+
+ 
+ 
+const char *p = R"*|*(		
+  
+        
+.
+)*|*";	 
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace	
+*/
+// This is a comment with trailing whitespace 
+/* This is a comment with trailing whitespace 
+*/
+    
\ No newline at end of file
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index be367b1f54af..3f05d085fcf9 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -598,6 +598,9 @@ struct cpp_options
   /* True if -finput-charset= option has been used explicitly.  */
   bool cpp_input_charset_explicit;
 
+  /* -Wtrailing-whitespace= value.  */
+  unsigned char cpp_warn_trailing_whitespace;
+
   /* Dependency generation.  */
   struct
   {
@@ -722,7 +725,8 @@ enum cpp_warning_reason {
   CPP_W_INVALID_UTF8,
   CPP_W_UNICODE,
   CPP_W_HEADER_GUARD,
-  CPP_W_PRAGMA_ONCE_OUTSIDE_HEADER
+  CPP_W_PRAGMA_ONCE_OUTSIDE_HEADER,
+  CPP_W_TRAILING_WHITESPACE
 };
 
 /* Callback for header lookup for HEADER, which is the name of a
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 6c2a36ecd0ab..a658a8c5739c 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -318,8 +318,8 @@ struct _cpp_line_note
 
   /* Type of note.  The 9 'from' trigraph characters represent those
      trigraphs, '\\' an escaped newline, ' ' an escaped newline with
-     intervening space, 0 represents a note that has already been handled,
-     and anything else is invalid.  */
+     intervening space, 'W' trailing whitespace, 0 represents a note that
+     has already been handled, and anything else is invalid.  */
   unsigned int type;
 };
 
diff --git a/libcpp/lex.cc b/libcpp/lex.cc
index f3feadf9352f..bb5cd394ab44 100644
--- a/libcpp/lex.cc
+++ b/libcpp/lex.cc
@@ -928,7 +928,7 @@ _cpp_clean_line (cpp_reader *pfile)
 	      if (p == buffer->next_line || p[-1] != '\\')
 		break;
 
-	      add_line_note (buffer, p - 1, p != d ? ' ': '\\');
+	      add_line_note (buffer, p - 1, p != d ? ' ' : '\\');
 	      d = p - 2;
 	      buffer->next_line = p - 1;
 	    }
@@ -943,6 +943,20 @@ _cpp_clean_line (cpp_reader *pfile)
 		}
 	    }
 	}
+     done:
+      if (d > buffer->next_line
+	  && CPP_OPTION (pfile, cpp_warn_trailing_whitespace))
+	switch (CPP_OPTION (pfile, cpp_warn_trailing_whitespace))
+	  {
+	  case 1:
+	    if (ISBLANK (d[-1]))
+	      add_line_note (buffer, d - 1, 'W');
+	    break;
+	  case 2:
+	    if (IS_NVSPACE (d[-1]) && d[-1])
+	      add_line_note (buffer, d - 1, 'W');
+	    break;
+	  }
     }
   else
     {
@@ -955,7 +969,6 @@ _cpp_clean_line (cpp_reader *pfile)
 	s++;
     }
 
- done:
   *d = '\n';
   /* A sentinel note that should never be processed.  */
   add_line_note (buffer, d + 1, '\n');
@@ -1013,13 +1026,23 @@ _cpp_process_line_notes (cpp_reader *pfile, int in_comment)
 
       if (note->type == '\\' || note->type == ' ')
 	{
-	  if (note->type == ' ' && !in_comment)
-	    cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line_table->highest_line, col,
-				 "backslash and newline separated by space");
+	  if (note->type == ' ')
+	    {
+	      if (!in_comment)
+		cpp_error_with_line (pfile, CPP_DL_WARNING,
+				     pfile->line_table->highest_line, col,
+				     "backslash and newline separated by "
+				     "space");
+	      else if (CPP_OPTION (pfile, cpp_warn_trailing_whitespace))
+		cpp_warning_with_line (pfile, CPP_W_TRAILING_WHITESPACE,
+				       pfile->line_table->highest_line, col,
+				       "trailing whitespace");
+	    }
 
 	  if (buffer->next_line > buffer->rlimit)
 	    {
-	      cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, col,
+	      cpp_error_with_line (pfile, CPP_DL_PEDWARN,
+				   pfile->line_table->highest_line, col,
 				   "backslash-newline at end of file");
 	      /* Prevent "no newline at end of file" warning.  */
 	      buffer->next_line = buffer->rlimit;
@@ -1040,15 +1063,16 @@ _cpp_process_line_notes (cpp_reader *pfile, int in_comment)
 				       note->type,
 				       (int) _cpp_trigraph_map[note->type]);
 	      else
-		{
-		  cpp_warning_with_line 
-		    (pfile, CPP_W_TRIGRAPHS,
-                     pfile->line_table->highest_line, col,
-		     "trigraph %<??%c%> ignored, use %<-trigraphs%> to enable",
-		     note->type);
-		}
+		cpp_warning_with_line (pfile, CPP_W_TRIGRAPHS,
+				       pfile->line_table->highest_line, col,
+				       "trigraph %<??%c%> ignored, use "
+				       "%<-trigraphs%> to enable", note->type);
 	    }
 	}
+      else if (note->type == 'W')
+	cpp_warning_with_line (pfile, CPP_W_TRAILING_WHITESPACE,
+			       pfile->line_table->highest_line, col,
+			       "trailing whitespace");
       else if (note->type == 0)
 	/* Already processed in lex_raw_string.  */;
       else
@@ -2507,6 +2531,12 @@ lex_raw_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
 	    note++;
 	    break;
 
+	  case 'W':
+	    /* Don't warn about trailing whitespace in raw string literals.  */
+	    note->type = 0;
+	    note++;
+	    break;
+
 	  default:
 	    gcc_checking_assert (_cpp_trigraph_map[note->type]);
 
-- 
GitLab