This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGa1545f51a9ef: Warn if using `elifdef` & `elifndef` in 
not C2x & C++2b mode (authored by ken-matsui, committed by aaron.ballman).

Changed prior to commit:
  https://reviews.llvm.org/D125178?vs=428910&id=428924#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125178/new/

https://reviews.llvm.org/D125178

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticLexKinds.td
  clang/lib/Lex/PPDirectives.cpp
  clang/test/Lexer/Inputs/unsafe-macro-2.h
  clang/test/Lexer/deprecate-macro.c
  clang/test/Preprocessor/elifdef.c
  clang/test/Preprocessor/ext-pp-directive.c
  clang/test/Preprocessor/if_warning.c
  clang/test/Preprocessor/ifdef-recover.c
  clang/test/Preprocessor/macro_misc.c
  clang/test/Preprocessor/macro_vaopt_check.cpp

Index: clang/test/Preprocessor/macro_vaopt_check.cpp
===================================================================
--- clang/test/Preprocessor/macro_vaopt_check.cpp
+++ clang/test/Preprocessor/macro_vaopt_check.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -pedantic -std=c++20
-// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -pedantic -std=c++11
-// RUN: %clang_cc1 -x c %s -Eonly -verify -Wno-all -pedantic -std=c99
+// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -Wno-c++2b-extensions -pedantic -std=c++20
+// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -Wno-c++2b-extensions -pedantic -std=c++11
+// RUN: %clang_cc1 -x c %s -Eonly -verify -Wno-all -Wno-c2x-extensions -pedantic -std=c99
 
 //expected-error@+1{{missing '('}}
 #define V1(...) __VA_OPT__  
Index: clang/test/Preprocessor/macro_misc.c
===================================================================
--- clang/test/Preprocessor/macro_misc.c
+++ clang/test/Preprocessor/macro_misc.c
@@ -4,6 +4,7 @@
 #ifdef defined
 #elifdef defined
 #endif
+// expected-warning@-2 {{use of a '#elifdef' directive is a C2x extension}}
 
 
 
Index: clang/test/Preprocessor/ifdef-recover.c
===================================================================
--- clang/test/Preprocessor/ifdef-recover.c
+++ clang/test/Preprocessor/ifdef-recover.c
@@ -19,12 +19,14 @@
 #if f(2
 #endif
 
-/* expected-error@+2 {{macro name missing}} */
+/* expected-error@+3 {{macro name missing}} */
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef
 #endif
 
-/* expected-error@+2 {{macro name must be an identifier}} */
+/* expected-error@+3 {{macro name must be an identifier}} */
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef !
 #endif
Index: clang/test/Preprocessor/if_warning.c
===================================================================
--- clang/test/Preprocessor/if_warning.c
+++ clang/test/Preprocessor/if_warning.c
@@ -5,6 +5,7 @@
 #if foo   // expected-error {{'foo' is not defined, evaluates to 0}}
 #endif
 
+// expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}}
 #ifdef foo
 #elifdef foo
 #endif
@@ -14,6 +15,7 @@
 
 
 // PR3938
+// expected-warning@+3 {{use of a '#elifdef' directive is a C2x extension}}
 #if 0
 #ifdef D
 #elifdef D
Index: clang/test/Preprocessor/ext-pp-directive.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/ext-pp-directive.c
@@ -0,0 +1,59 @@
+// For C
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify=pre-c2x-pedantic -pedantic %s
+// RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=pre-c2x-compat -Wpre-c2x-compat %s
+// RUN: not %clang_cc1 -std=c99 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -std=c2x -fsyntax-only -verify -pedantic %s
+// RUN: not %clang_cc1 -std=c2x -fsyntax-only -verify %s
+
+// For C++
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=pre-cpp2b-pedantic -pedantic %s
+// RUN: %clang_cc1 -x c++ -std=c++2b -fsyntax-only -verify=pre-cpp2b-compat -Wpre-c++2b-compat %s
+// RUN: not %clang_cc1 -x c++ -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -x c++ -std=c++2b -fsyntax-only -verify -pedantic %s
+// RUN: not %clang_cc1 -x c++ -std=c++2b -fsyntax-only -verify %s
+
+int x;
+
+#if 1
+#elifdef A // #1
+#endif
+// For C
+// pre-c2x-pedantic-warning@#1 {{use of a '#elifdef' directive is a C2x extension}}
+// pre-c2x-compat-warning@#1 {{use of a '#elifdef' directive is incompatible with C standards before C2x}}
+
+// For C++
+// pre-cpp2b-pedantic-warning@#1 {{use of a '#elifdef' directive is a C++2b extension}}
+// pre-cpp2b-compat-warning@#1 {{use of a '#elifdef' directive is incompatible with C++ standards before C++2b}}
+
+#if 1
+#elifndef B // #2
+#endif
+// For C
+// pre-c2x-pedantic-warning@#2 {{use of a '#elifndef' directive is a C2x extension}}
+// pre-c2x-compat-warning@#2 {{use of a '#elifndef' directive is incompatible with C standards before C2x}}
+
+// For C++
+// pre-cpp2b-pedantic-warning@#2 {{use of a '#elifndef' directive is a C++2b extension}}
+// pre-cpp2b-compat-warning@#2 {{use of a '#elifndef' directive is incompatible with C++ standards before C++2b}}
+
+#if 0
+#elifdef C
+#endif
+// For C
+// pre-c2x-pedantic-warning@-3 {{use of a '#elifdef' directive is a C2x extension}}
+// pre-c2x-compat-warning@-4 {{use of a '#elifdef' directive is incompatible with C standards before C2x}}
+
+// For C++
+// pre-cpp2b-pedantic-warning@-7 {{use of a '#elifdef' directive is a C++2b extension}}
+// pre-cpp2b-compat-warning@-8 {{use of a '#elifdef' directive is incompatible with C++ standards before C++2b}}
+
+#if 0
+#elifndef D
+#endif
+// For C
+// pre-c2x-pedantic-warning@-3 {{use of a '#elifndef' directive is a C2x extension}}
+// pre-c2x-compat-warning@-4 {{use of a '#elifndef' directive is incompatible with C standards before C2x}}
+
+// For C++
+// pre-cpp2b-pedantic-warning@-7 {{use of a '#elifndef' directive is a C++2b extension}}
+// pre-cpp2b-compat-warning@-8 {{use of a '#elifndef' directive is incompatible with C++ standards before C++2b}}
Index: clang/test/Preprocessor/elifdef.c
===================================================================
--- clang/test/Preprocessor/elifdef.c
+++ clang/test/Preprocessor/elifdef.c
@@ -1,24 +1,28 @@
 // RUN: %clang_cc1 %s -Eonly -verify
 
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef BAR
 #error "did not expect to get here"
 #endif
 
-/* expected-error@+4 {{"got it"}} */
+/* expected-error@+5 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef BAR
 #else
 #error "got it"
 #endif
 
-/* expected-error@+3 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifdef FOO
 #elifndef BAR
 #error "got it"
 #endif
 
-/* expected-error@+3 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifdef FOO
 #elifndef BAR
 #error "got it"
@@ -27,32 +31,37 @@
 #endif
 
 #define BAR
-/* expected-error@+3 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef BAR
 #error "got it"
 #endif
 #undef BAR
 
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef BAR // test that comments aren't an issue
 #error "did not expect to get here"
 #endif
 
-/* expected-error@+4 {{"got it"}} */
+/* expected-error@+5 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef BAR // test that comments aren't an issue
 #else
 #error "got it"
 #endif
 
-/* expected-error@+3 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifdef FOO
 #elifndef BAR // test that comments aren't an issue
 #error "got it"
 #endif
 
-/* expected-error@+3 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifdef FOO
 #elifndef BAR // test that comments aren't an issue
 #error "got it"
@@ -61,7 +70,8 @@
 #endif
 
 #define BAR
-/* expected-error@+3 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+2 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #elifdef BAR // test that comments aren't an issue
 #error "got it"
@@ -69,7 +79,8 @@
 #undef BAR
 
 #define BAR
-/* expected-error@+6 {{"got it"}} */
+/* expected-error@+7 {{"got it"}} */
+/* expected-warning@+3 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifdef FOO
 #error "did not expect to get here"
 #elifndef BAR
@@ -79,27 +90,33 @@
 #endif
 #undef BAR
 
-/* expected-error@+3 {{#elifdef after #else}} */
+/* expected-error@+4 {{#elifdef after #else}} */
+/* expected-warning@+3 {{use of a '#elifdef' directive is a C2x extension}} */
 #ifdef FOO
 #else
 #elifdef BAR
 #endif
 
-/* expected-error@+3 {{#elifndef after #else}} */
+/* expected-error@+4 {{#elifndef after #else}} */
+/* expected-warning@+3 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifdef FOO
 #else
 #elifndef BAR
 #endif
 
+/* expected-warning@+1 {{use of a '#elifdef' directive is a C2x extension}} */
 #elifdef FOO /* expected-error {{#elifdef without #if}} */
 #endif       /* expected-error {{#endif without #if}} */
 
+/* expected-warning@+1 {{use of a '#elifndef' directive is a C2x extension}} */
 #elifndef FOO /* expected-error {{#elifndef without #if}} */
 #endif        /* expected-error {{#endif without #if}} */
 
 /* Note, we do not expect errors about the missing macro name in the skipped
    blocks. This is consistent with #elif behavior. */
-/* expected-error@+2 {{"got it"}} */
+/* expected-error@+4 {{"got it"}} */
+/* expected-warning@+4 {{use of a '#elifdef' directive is a C2x extension}} */
+/* expected-warning@+4 {{use of a '#elifndef' directive is a C2x extension}} */
 #ifndef FOO
 #error "got it"
 #elifdef
Index: clang/test/Lexer/deprecate-macro.c
===================================================================
--- clang/test/Lexer/deprecate-macro.c
+++ clang/test/Lexer/deprecate-macro.c
@@ -79,6 +79,7 @@
 #ifdef baz
 #elifdef foo
 // expected-warning@-1{{macro 'foo' has been marked as deprecated}}
+// expected-warning@-2{{use of a '#elifdef' directive is a C2x extension}}
 #endif
 
 // Test that we diagnose on #elifndef.
@@ -86,18 +87,21 @@
 #elifndef foo
 #endif
 // expected-warning@-2{{macro 'foo' has been marked as deprecated}}
+// expected-warning@-3{{use of a '#elifndef' directive is a C2x extension}}
 
 // FIXME: These cases are currently not handled because clang doesn't expand
 // conditions on skipped #elif* blocks. See the FIXME notes in
 // Preprocessor::SkipExcludedConditionalBlock.
 
 #ifdef frobble
-// not-expected-warning@+1{{macro 'foo' has been marked as deprecated}}
+// not-expected-warning@+2{{macro 'foo' has been marked as deprecated}}
+// expected-warning@+1{{use of a '#elifndef' directive is a C2x extension}}
 #elifndef foo
 #endif
 
 #ifdef frobble
-// not-expected-warning@+1{{macro 'foo' has been marked as deprecated}}
+// not-expected-warning@+2{{macro 'foo' has been marked as deprecated}}
+// expected-warning@+1{{use of a '#elifdef' directive is a C2x extension}}
 #elifdef foo
 #endif
 
Index: clang/test/Lexer/Inputs/unsafe-macro-2.h
===================================================================
--- clang/test/Lexer/Inputs/unsafe-macro-2.h
+++ clang/test/Lexer/Inputs/unsafe-macro-2.h
@@ -40,6 +40,7 @@
 #ifdef baz
 #elifdef UNSAFE_MACRO
 // expected-warning@-1{{macro 'UNSAFE_MACRO' has been marked as unsafe for use in headers: Don't use this!}}
+// expected-warning@-2{{use of a '#elifdef' directive is a C2x extension}}
 #endif
 
 // Test that we diagnose on #elifndef.
@@ -47,6 +48,7 @@
 #elifndef UNSAFE_MACRO
 #endif
 // expected-warning@-2{{macro 'UNSAFE_MACRO' has been marked as unsafe for use in headers: Don't use this!}}
+// expected-warning@-3{{use of a '#elifndef' directive is a C2x extension}}
 
 // FIXME: These cases are currently not handled because clang doesn't expand
 // conditions on skipped #elif* blocks. See the FIXME notes in
@@ -55,12 +57,14 @@
 #define frobble
 
 #ifdef frobble
-// not-expected-warning@+1{{macro 'UNSAFE_MACRO' has been marked as unsafe for use in headers: Don't use this!}}
+// not-expected-warning@+2{{macro 'UNSAFE_MACRO' has been marked as unsafe for use in headers: Don't use this!}}
+// expected-warning@+1{{use of a '#elifndef' directive is a C2x extension}}
 #elifndef UNSAFE_MACRO
 #endif
 
 #ifdef frobble
-// not-expected-warning@+1{{macro 'UNSAFE_MACRO' has been marked as unsafe for use in headers: Don't use this!}}
+// not-expected-warning@+2{{macro 'UNSAFE_MACRO' has been marked as unsafe for use in headers: Don't use this!}}
+// expected-warning@+1{{use of a '#elifdef' directive is a C2x extension}}
 #elifdef UNSAFE_MACRO
 #endif
 
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -652,6 +652,17 @@
         PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
         Token DirectiveToken = Tok;
 
+        // Warn if using `#elifdef` & `#elifndef` in not C2x & C++2b mode even
+        // if this branch is in a skipping block.
+        unsigned DiagID;
+        if (LangOpts.CPlusPlus)
+          DiagID = LangOpts.CPlusPlus2b ? diag::warn_cxx2b_compat_pp_directive
+                                        : diag::ext_cxx2b_pp_directive;
+        else
+          DiagID = LangOpts.C2x ? diag::warn_c2x_compat_pp_directive
+                                : diag::ext_c2x_pp_directive;
+        Diag(Tok, DiagID) << (IsElifDef ? PED_Elifdef : PED_Elifndef);
+
         // If this is a #elif with a #else before it, report the error.
         if (CondInfo.FoundElse)
           Diag(Tok, diag::pp_err_elif_after_else)
@@ -3259,6 +3270,23 @@
                                                  : PED_Elifndef;
   ++NumElse;
 
+  // Warn if using `#elifdef` & `#elifndef` in not C2x & C++2b mode.
+  switch (DirKind) {
+  case PED_Elifdef:
+  case PED_Elifndef:
+    unsigned DiagID;
+    if (LangOpts.CPlusPlus)
+      DiagID = LangOpts.CPlusPlus2b ? diag::warn_cxx2b_compat_pp_directive
+                                    : diag::ext_cxx2b_pp_directive;
+    else
+      DiagID = LangOpts.C2x ? diag::warn_c2x_compat_pp_directive
+                            : diag::ext_c2x_pp_directive;
+    Diag(ElifToken, DiagID) << DirKind;
+    break;
+  default:
+    break;
+  }
+
   // #elif directive in a non-skipping conditional... start skipping.
   // We don't care what the condition is, because we will always skip it (since
   // the block immediately before it was included).
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -698,6 +698,23 @@
   "#line number greater than 32767 is incompatible with C++98">,
   InGroup<CXX98CompatPedantic>, DefaultIgnore;
 
+def warn_c2x_compat_pp_directive : Warning<
+  "use of a '#%select{<BUG IF SEEN>|elifdef|elifndef}0' directive "
+  "is incompatible with C standards before C2x">,
+  InGroup<CPre2xCompat>, DefaultIgnore;
+def ext_c2x_pp_directive : ExtWarn<
+  "use of a '#%select{<BUG IF SEEN>|elifdef|elifndef}0' directive "
+  "is a C2x extension">,
+  InGroup<C2x>;
+def warn_cxx2b_compat_pp_directive : Warning<
+  "use of a '#%select{<BUG IF SEEN>|elifdef|elifndef}0' directive "
+  "is incompatible with C++ standards before C++2b">,
+  InGroup<CXXPre2bCompat>, DefaultIgnore;
+def ext_cxx2b_pp_directive : ExtWarn<
+  "use of a '#%select{<BUG IF SEEN>|elifdef|elifndef}0' directive "
+  "is a C++2b extension">,
+  InGroup<CXX2b>;
+
 def err_pp_visibility_non_macro : Error<"no macro named %0">;
 
 def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -217,6 +217,12 @@
 - Added the ``-Wgnu-line-marker`` diagnostic flag (grouped under the ``-Wgnu``
   flag) which is a portability warning about use of GNU linemarker preprocessor
   directives. Fixes `Issue 55067 <https://github.com/llvm/llvm-project/issues/55067>`_.
+- Using ``#elifdef`` and ``#elifndef`` that are incompatible with C/C++
+  standards before C2x/C++2b are now warned via ``-pedantic``. Additionally,
+  on such language mode, ``-Wpre-c2x-compat`` and ``-Wpre-c++2b-compat``
+  diagnostic flags report a compatibility issue.
+  Fixes `Issue 55306 <https://github.com/llvm/llvm-project/issues/55306>`_.
+
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to