[clang] 9a92f2f - Make diagnostic pragma override -Werror=foo and DefaultError warnings

via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 14 09:57:25 PDT 2024


Author: Fangrui Song
Date: 2024-06-14T09:57:21-07:00
New Revision: 9a92f2f742347d9b31470349f3b777ecab580ac1

URL: https://github.com/llvm/llvm-project/commit/9a92f2f742347d9b31470349f3b777ecab580ac1
DIFF: https://github.com/llvm/llvm-project/commit/9a92f2f742347d9b31470349f3b777ecab580ac1.diff

LOG: Make diagnostic pragma override -Werror=foo and DefaultError warnings

In GCC, `#pragma GCC diagnostic warning "-Wfoo"` overrides command-line
`-Werror=foo` and errors that can become warnings (pedwarn with
-pedantic-errors and permerror).

```
#pragma GCC diagnostic warning "-Wnarrowing"
int x = {4.2};
#pragma GCC diagnostic warning "-Wundef"
#if FOO
#endif

// gcc -c -Werror=undef -Werror=narrowing => two warnings
```

These diagnostics are similar to our Warning/ExtWarn/Extension
diagnostics with DefaultError. This patch ports the behavior to Clang.

Fix #93474

Pull Request: https://github.com/llvm/llvm-project/pull/93647

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/docs/UsersManual.rst
    clang/lib/Basic/Diagnostic.cpp
    clang/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h
    clang/test/Modules/implicit-built-Werror-using-W.cpp
    clang/test/Preprocessor/pragma_diagnostic.c
    clang/test/Sema/implicit-decl.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bae9f5e1bd02a..36efeb8c70cca 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -351,6 +351,9 @@ Non-comprehensive list of changes in this release
 - Added ``__is_bitwise_cloneable`` which is used to check whether a type
   can be safely copied by memcpy/memmove.
 
+- ``#pragma GCC diagnostic warning "-Wfoo"`` can now downgrade ``-Werror=foo``
+  errors and certain default-to-error ``-W`` diagnostics to warnings.
+
 New Compiler Flags
 ------------------
 - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and

diff  --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 15bf5e30cf8e2..8e01ea15064ba 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1138,7 +1138,7 @@ and ``#pragma clang diagnostic`` are synonyms for Clang. GCC will ignore
 
 The pragma may control any warning that can be used from the command
 line. Warnings may be set to ignored, warning, error, or fatal. The
-following example code will tell Clang or GCC to ignore the -Wall
+following example code will tell Clang or GCC to ignore the ``-Wall``
 warnings:
 
 .. code-block:: c
@@ -1186,6 +1186,15 @@ severity levels. They can be used to change severity of a particular diagnostic
 for a region of source file. A notable 
diff erence from GCC is that diagnostic
 not enabled via command line arguments can't be enabled this way yet.
 
+Some diagnostics associated with a ``-W`` flag have the error severity by
+default. They can be ignored or downgraded to warnings:
+
+.. code-block:: cpp
+
+  // C only
+  #pragma GCC diagnostic warning "-Wimplicit-function-declaration"
+  int main(void) { puts(""); }
+
 In addition to controlling warnings and errors generated by the compiler, it is
 possible to generate custom warning and error messages through the following
 pragmas:

diff  --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index 10136b4cd9435..66776daa5e149 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -360,9 +360,10 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
          "Cannot map errors into warnings!");
   assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
 
-  // Don't allow a mapping to a warning override an error/fatal mapping.
+  // A command line -Wfoo has an invalid L and cannot override error/fatal
+  // mapping, while a warning pragma can.
   bool WasUpgradedFromWarning = false;
-  if (Map == diag::Severity::Warning) {
+  if (Map == diag::Severity::Warning && L.isInvalid()) {
     DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
     if (Info.getSeverity() == diag::Severity::Error ||
         Info.getSeverity() == diag::Severity::Fatal) {

diff  --git a/clang/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h b/clang/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h
index 0ed02bc793bd1..532fd6e28ccc4 100644
--- a/clang/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h
+++ b/clang/test/Modules/Inputs/implicit-built-Werror-using-W/convert.h
@@ -1,6 +1,10 @@
 #ifdef USE_PRAGMA
 #pragma clang diagnostic push
+#if USE_PRAGMA == 1
 #pragma clang diagnostic warning "-Wshorten-64-to-32"
+#else
+#pragma clang diagnostic error "-Wshorten-64-to-32"
+#endif
 #endif
 template <class T> int convert(T V) { return V; }
 #ifdef USE_PRAGMA

diff  --git a/clang/test/Modules/implicit-built-Werror-using-W.cpp b/clang/test/Modules/implicit-built-Werror-using-W.cpp
index 9fb7a6bf0b035..973dbba130b7f 100644
--- a/clang/test/Modules/implicit-built-Werror-using-W.cpp
+++ b/clang/test/Modules/implicit-built-Werror-using-W.cpp
@@ -22,16 +22,23 @@
 // RUN: | FileCheck %s -allow-empty
 //
 // In the presence of a warning pragma, build with -Werror and then without.
-// RUN: not %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
-// RUN:   -DUSE_PRAGMA -Werror=shorten-64-to-32 \
+// RUN: %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN:   -DUSE_PRAGMA=1 -Werror=shorten-64-to-32 \
 // RUN:   -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
 // RUN:   -fmodules-cache-path=%t-pragma.cache -x c++ %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix=CHECK-ERROR
+// RUN: | FileCheck %s -check-prefix=CHECK-WARN
 // RUN: %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
-// RUN:   -DUSE_PRAGMA \
+// RUN:   -DUSE_PRAGMA=1 \
 // RUN:   -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
 // RUN:   -fmodules-cache-path=%t-pragma.cache -x c++ %s 2>&1 \
 // RUN: | FileCheck %s -check-prefix=CHECK-WARN
+
+// Test an error pragma.
+// RUN: not %clang_cc1 -triple x86_64-apple-darwin16 -fsyntax-only -fmodules \
+// RUN:   -DUSE_PRAGMA=2 -Wshorten-64-to-32 \
+// RUN:   -I%S/Inputs/implicit-built-Werror-using-W -fimplicit-module-maps \
+// RUN:   -fmodules-cache-path=%t-pragma.cache -x c++ %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ERROR
 #include <convert.h>
 
 long long foo() { return convert<long long>(0); }

diff  --git a/clang/test/Preprocessor/pragma_diagnostic.c b/clang/test/Preprocessor/pragma_diagnostic.c
index 8a5adcf6ab55b..ff379079b7baf 100644
--- a/clang/test/Preprocessor/pragma_diagnostic.c
+++ b/clang/test/Preprocessor/pragma_diagnostic.c
@@ -1,8 +1,14 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wno-undef %s
 // RUN: %clang_cc1 -fsyntax-only -verify -Wno-undef -Wno-unknown-warning-option -DAVOID_UNKNOWN_WARNING %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Werror=undef -DINITIAL_UNDEF %s
 
+#ifdef INITIAL_UNDEF
+#if FOO    // expected-error {{'FOO' is not defined}}
+#endif
+#else
 #if FOO    // ok.
 #endif
+#endif
 
 #pragma GCC diagnostic warning "-Wundef"
 
@@ -52,6 +58,6 @@ void ppq(void){}
 void ppr(void){} // expected-error {{no previous prototype for function 'ppr'}}
 // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}
 
-#pragma clang diagnostic warning "-Weverything" // This should not be effective
-void pps(void){} // expected-error {{no previous prototype for function 'pps'}}
+#pragma clang diagnostic warning "-Weverything" // Set to warning
+void pps(void){} // expected-warning {{no previous prototype for function 'pps'}}
 // expected-note at -1{{declare 'static' if the function is not intended to be used outside of this translation unit}}

diff  --git a/clang/test/Sema/implicit-decl.c b/clang/test/Sema/implicit-decl.c
index d7d3e108e8048..a3f35222d833c 100644
--- a/clang/test/Sema/implicit-decl.c
+++ b/clang/test/Sema/implicit-decl.c
@@ -74,3 +74,20 @@ void GH48579_2(void) {
 
 int GH48579_3 = ({a();});              // both-error {{statement expression not allowed at file scope}}
 void GH48579_4(int array[({ a(); })]); // both-error {{statement expression not allowed at file scope}}
+
+void pragma_warning(void) {
+#pragma clang diagnostic warning "-Wimplicit-function-declaration"
+  bark(); // expected-warning {{call to undeclared function 'bark'; ISO C99 and later do not support implicit function declarations}} \
+             c2x-error {{use of undeclared identifier 'bark'}}
+}
+
+void pragma_error(void) {
+#pragma clang diagnostic error "-Wimplicit-function-declaration"
+  bark(); // expected-error {{call to undeclared function 'bark'; ISO C99 and later do not support implicit function declarations}} \
+             c2x-error {{use of undeclared identifier 'bark'}}
+}
+
+void pragma_ignored(void) {
+#pragma clang diagnostic ignored "-Wimplicit-function-declaration"
+  bark(); // c2x-error {{use of undeclared identifier 'bark'}}
+}


        


More information about the cfe-commits mailing list