https://gcc.gnu.org/g:3b66a2a7890f2ae27ad4c1e1ac62b6551a2ffbae

commit r16-3061-g3b66a2a7890f2ae27ad4c1e1ac62b6551a2ffbae
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Thu Aug 7 08:52:38 2025 +0200

    c++: Add testcase for CWG2575 [PR120778]
    
    From the paper it isn't clear what caused the decision changes, not to drop
    the "the token defined is generated as a result of this replacement process 
or"
    part and make [cpp.cond]/10 violations IFNDR rather than ill-formed (the
    latter maybe so that the extension to handle e.g. !A(A) below etc. can be
    accepted).
    
    Anyway, because that case hasn't been dropped and we pedwarn on it already,
    and diagnose everything else the way it should, the following patch just
    adds testcase for it.
    
    2025-08-07  Jakub Jelinek  <ja...@redhat.com>
    
            PR preprocessor/120778
            * g++.dg/DRs/dr2575.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/DRs/dr2575.C | 51 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/gcc/testsuite/g++.dg/DRs/dr2575.C 
b/gcc/testsuite/g++.dg/DRs/dr2575.C
new file mode 100644
index 000000000000..f350282fec02
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2575.C
@@ -0,0 +1,51 @@
+// DR 2575 - Undefined behavior when macro-replacing "defined" operator
+// { dg-do preprocess }
+// { dg-options "-pedantic-errors" }
+
+#define A defined
+#if !A(A)              // { dg-error "this use of 'defined' may not be 
portable" }
+#error
+#endif
+#if A(B)               // { dg-error "this use of 'defined' may not be 
portable" }
+#error
+#endif
+#if !A A               // { dg-error "this use of 'defined' may not be 
portable" }
+#error
+#endif
+#if A B                        // { dg-error "this use of 'defined' may not be 
portable" }
+#error
+#endif
+#if defined A + B
+#else
+#error
+#endif
+#if defined +B         // { dg-error "operator 'defined' requires an 
identifier" }
+#endif                 // { dg-error "missing binary operator before token 
'B'" "" { target *-*-* } .-1 }
+#if defined 1          // { dg-error "operator 'defined' requires an 
identifier" }
+#endif
+#if defined            // { dg-error "operator 'defined' requires an 
identifier" }
+#endif
+#if defined (A + B)    // { dg-error "missing '\\\)' after 'defined'" }
+#endif                 // { dg-error "missing binary operator before token 
'B'" "" { target *-*-* } .-1 }
+#if defined (+B)       // { dg-error "operator 'defined' requires an 
identifier" }
+#endif                 // { dg-error "missing binary operator before token 
'B'" "" { target *-*-* } .-1 }
+#if defined (1)                // { dg-error "operator 'defined' requires an 
identifier" }
+#endif                 // { dg-error "missing '\\\(' in expression" "" { 
target *-*-* } .-1 }
+#if defined ()         // { dg-error "operator 'defined' requires an 
identifier" }
+#endif
+#if defined A, B       // { dg-error "comma operator in operand of #if" }
+#endif
+#if defined (A), B     // { dg-error "comma operator in operand of #if" }
+#endif
+#if (defined A), B     // { dg-error "comma operator in operand of #if" }
+#endif
+#if defined (A, B)     // { dg-error "missing '\\\)' after 'defined'" }
+#endif                 // { dg-error "missing binary operator before token 
'B'" "" { target *-*-* } .-1 }
+#if defined (A) + B
+#else
+#error
+#endif
+#if (defined A) + B
+#else
+#error
+#endif

Reply via email to