https://github.com/benlangmuir updated 
https://github.com/llvm/llvm-project/pull/200458

>From dea4550a9a0e371a22353d49c0293db1f785708b Mon Sep 17 00:00:00 2001
From: Ben Langmuir <[email protected]>
Date: Thu, 28 May 2026 15:11:13 -0700
Subject: [PATCH 1/3] [clang][deps] Fix printing of object-like macros from dep
 directives

Preserve the necessary whitespace between the macro name and the body when an
object-like macro starts with lparen. Otherwise it accidentally turns into an
invalid function-like macro.
---
 clang/lib/Lex/DependencyDirectivesScanner.cpp | 30 ++++++---
 ...minimize_source_to_dependency_directives.c |  1 +
 ...to_dependency_directives_function_macros.c | 66 +++++++++++++++++++
 ..._source_to_dependency_directives_pragmas.c |  8 ++-
 ..._source_to_dependency_directives_utf8bom.c |  4 +-
 .../Lex/DependencyDirectivesScannerTest.cpp   | 19 ++++++
 6 files changed, 116 insertions(+), 12 deletions(-)
 create mode 100644 
clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c

diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp 
b/clang/lib/Lex/DependencyDirectivesScanner.cpp
index 332485a4ab5d54..e39fc55e56df85 100644
--- a/clang/lib/Lex/DependencyDirectivesScanner.cpp
+++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp
@@ -1092,34 +1092,44 @@ void clang::printDependencyDirectivesAsSource(
     ArrayRef<dependency_directives_scan::Directive> Directives,
     llvm::raw_ostream &OS) {
   // Add a space separator where it is convenient for testing purposes.
-  auto needsSpaceSeparator =
-      [](tok::TokenKind Prev,
-         const dependency_directives_scan::Token &Tok) -> bool {
-    if (Prev == Tok.Kind)
+  auto needsSpaceSeparator = [](const dependency_directives_scan::Token &Prev,
+                                const dependency_directives_scan::Token &Tok,
+                                DirectiveKind Kind, unsigned TokIdx) -> bool {
+    if (Prev.Kind == Tok.Kind)
       return !Tok.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
                           tok::r_square);
-    if (Prev == tok::raw_identifier &&
+    if (Prev.Kind == tok::raw_identifier &&
         Tok.isOneOf(tok::hash, tok::numeric_constant, tok::string_literal,
                     tok::char_constant, tok::header_name))
       return true;
-    if (Prev == tok::r_paren &&
+    if (Prev.Kind == tok::r_paren &&
         Tok.isOneOf(tok::raw_identifier, tok::hash, tok::string_literal,
                     tok::char_constant, tok::unknown))
       return true;
-    if (Prev == tok::comma &&
+    if (Prev.Kind == tok::comma &&
         Tok.isOneOf(tok::l_paren, tok::string_literal, tok::less))
       return true;
+    // For object-like macros that begin with an lparen, preserve a space
+    // between the name and the body to avoid it being converted to a
+    // function-like macro.
+    constexpr unsigned FirstBodyIdx = 3; // `#`, `define`, <NAME>, <BODY...>
+    if (Kind == pp_define && TokIdx == FirstBodyIdx &&
+        Prev.is(tok::raw_identifier) && Tok.is(tok::l_paren) &&
+        Tok.Offset > Prev.getEnd())
+      return true;
     return false;
   };
 
   for (const dependency_directives_scan::Directive &Directive : Directives) {
     if (Directive.Kind == tokens_present_before_eof)
       OS << "<TokBeforeEOF>";
-    std::optional<tok::TokenKind> PrevTokenKind;
+    const dependency_directives_scan::Token *PrevTok = nullptr;
+    unsigned TokIdx = 0;
     for (const dependency_directives_scan::Token &Tok : Directive.Tokens) {
-      if (PrevTokenKind && needsSpaceSeparator(*PrevTokenKind, Tok))
+      if (PrevTok && needsSpaceSeparator(*PrevTok, Tok, Directive.Kind, 
TokIdx))
         OS << ' ';
-      PrevTokenKind = Tok.Kind;
+      PrevTok = &Tok;
+      ++TokIdx;
       OS << Source.slice(Tok.Offset, Tok.getEnd());
     }
   }
diff --git a/clang/test/Frontend/minimize_source_to_dependency_directives.c 
b/clang/test/Frontend/minimize_source_to_dependency_directives.c
index 39f608b264a6a4..24ed8ec6b72646 100644
--- a/clang/test/Frontend/minimize_source_to_dependency_directives.c
+++ b/clang/test/Frontend/minimize_source_to_dependency_directives.c
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -print-dependency-directives-minimized-source %s > %t
 // RUN: echo END. >> %t
 // RUN: FileCheck < %t %s
+// RUN: %clang_cc1 -Eonly %t
 
 #ifdef FOO
 #include "a.h"
diff --git 
a/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c 
b/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c
new file mode 100644
index 00000000000000..50786b7b80e150
--- /dev/null
+++ 
b/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -print-dependency-directives-minimized-source %s > %t
+// RUN: %clang_cc1 -E -dM %t | FileCheck %s
+
+// The conditional defines below all rely on the printer preserving the macro
+// definitions and #if conditions accurately.
+
+#define ADD(x, y) ((x) + (y))
+#define SHL(x, n) ((x) << (n))
+#define HAS(x) (x)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define BAR() 42
+
+#if ADD(1, 2) > 0
+#define POSITIVE_SUM
+// CHECK-DAG: #define POSITIVE_SUM
+#endif
+
+#if ADD(1, 2) == 3 && SHL(1, 3) == 8
+#define MATH_OK
+// CHECK-DAG: #define MATH_OK
+#endif
+
+#if HAS(0) || HAS(1)
+#define HAS_EITHER
+// CHECK-DAG: #define HAS_EITHER
+#endif
+
+#if !ADD(0, 0)
+#define NEGATED
+// CHECK-DAG: #define NEGATED
+#endif
+
+#if 1 + HAS(2)
+#define LEADING_NUM
+// CHECK-DAG: #define LEADING_NUM
+#endif
+
+#if BAR() + BAR() == 84
+#define EMPTY_ARGS
+// CHECK-DAG: #define EMPTY_ARGS
+#endif
+
+#if MIN(1, 2) == 1
+#define MIN_OK
+// CHECK-DAG: #define MIN_OK
+#endif
+
+#if HAS(1) - HAS(2) < 0
+#define SUB_OK
+// CHECK-DAG: #define SUB_OK
+#endif
+
+#if HAS(0xff) & 0xf0
+#define BITWISE
+// CHECK-DAG: #define BITWISE
+#endif
+
+#if HAS(1) << 2 | HAS(2)
+#define SHIFT_OR
+// CHECK-DAG: #define SHIFT_OR
+#endif
+
+#if defined(FOO) && ADD(1, 2) + ADD(3, 4) > 5
+#define COMPLEX_BUT_FALSE
+// CHECK-NOT: #define COMPLEX_BUT_FALSE
+#endif
diff --git 
a/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c 
b/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c
index 0971649caf6738..3a4392e34cd079 100644
--- a/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c
+++ b/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c
@@ -1,5 +1,7 @@
 // Test that the required #pragma directives are minimized
-// RUN: %clang_cc1 -print-dependency-directives-minimized-source %s 2>&1 | 
FileCheck %s
+// RUN: %clang_cc1 -print-dependency-directives-minimized-source %s > %t 2>&1
+// RUN: FileCheck %s -input-file %t
+// RUN: %clang_cc1 -Eonly %t
 
 #pragma once
 
@@ -11,11 +13,15 @@
 // pragmas required in the minimized source.
 #pragma push_macro(    "MYMACRO"   )
 #pragma pop_macro("MYMACRO")
+#if IMPORT
 #pragma clang module import mymodule
+#endif
 #pragma include_alias(<string>,   "mystring.h")
 
 // CHECK:      #pragma once
 // CHECK-NEXT: #pragma push_macro("MYMACRO")
 // CHECK-NEXT: #pragma pop_macro("MYMACRO")
+// CHECK-NEXT: #if IMPORT
 // CHECK-NEXT: #pragma clang module import mymodule
+// CHECK-NEXT: #endif
 // CHECK-NEXT: #pragma include_alias(<string>, "mystring.h")
diff --git 
a/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c 
b/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c
index d7c7d04fd1785c..4659db0617472f 100644
--- a/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c
+++ b/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c
@@ -1,6 +1,8 @@
 // Test UTF8 BOM at start of file
 // RUN: cat %S/Inputs/bom-directives.c | od -t x1 | grep -iq 
'ef[[:space:]]*bb[[:space:]]*bf'
-// RUN: %clang_cc1 -DTEST -print-dependency-directives-minimized-source 
%S/Inputs/bom-directives.c 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -DTEST -print-dependency-directives-minimized-source 
%S/Inputs/bom-directives.c > %t 2>&1
+// RUN: FileCheck %s -input-file %t
+// RUN: %clang_cc1 -Eonly %t.min.c
 
 // CHECK:      #ifdef TEST
 // CHECK-NEXT: #include <string>
diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp 
b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
index 6e0a05a3ef7b9c..677190277b710d 100644
--- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
+++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
@@ -181,6 +181,10 @@ TEST(MinimizeSourceToDependencyDirectivesTest, 
DefineMacroArguments) {
   ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO()", Out));
   EXPECT_STREQ("#define MACRO()\n", Out.data());
 
+  ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+      "#define MACRO(a, b)  ((a) + (b ))", Out));
+  EXPECT_STREQ("#define MACRO(a,b)((a)+(b))\n", Out.data());
+
   ASSERT_FALSE(
       minimizeSourceToDependencyDirectives("#define MACRO(a, b...)", Out));
   EXPECT_STREQ("#define MACRO(a,b...)\n", Out.data());
@@ -212,6 +216,21 @@ TEST(MinimizeSourceToDependencyDirectivesTest, 
DefineInvalidMacroArguments) {
   EXPECT_STREQ("#define MACRO(a*b)\n", Out.data());
 }
 
+TEST(MinimizeSourceToDependencyDirectivesTest,
+     ObjectLikeMacroBodyStartsWithParen) {
+  SmallVector<char, 128> Out;
+  ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+      "#define NULL_PTR  ((void *)0)\n", Out));
+  EXPECT_STREQ("#define NULL_PTR ((void*)0)\n", Out.data());
+
+  ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+      "#define FEATURE_ENABLED  (!A || (B && !C))\n", Out));
+  EXPECT_STREQ("#define FEATURE_ENABLED (!A||(B&&!C))\n", Out.data());
+  ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+      "#define WITH_COMMENT /*x*/ (-1)\n", Out));
+  EXPECT_STREQ("#define WITH_COMMENT (-1)\n", Out.data());
+}
+
 TEST(MinimizeSourceToDependencyDirectivesTest, DefineHorizontalWhitespace) {
   SmallVector<char, 128> Out;
 

>From b11a8e59781bc6784938464501c6e910ab721c48 Mon Sep 17 00:00:00 2001
From: Ben Langmuir <[email protected]>
Date: Fri, 29 May 2026 10:27:22 -0700
Subject: [PATCH 2/3] [fixup] Fix test filename that was changed

---
 .../Lexer/minimize_source_to_dependency_directives_utf8bom.c    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git 
a/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c 
b/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c
index 4659db0617472f..3e3722f732c708 100644
--- a/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c
+++ b/clang/test/Lexer/minimize_source_to_dependency_directives_utf8bom.c
@@ -2,7 +2,7 @@
 // RUN: cat %S/Inputs/bom-directives.c | od -t x1 | grep -iq 
'ef[[:space:]]*bb[[:space:]]*bf'
 // RUN: %clang_cc1 -DTEST -print-dependency-directives-minimized-source 
%S/Inputs/bom-directives.c > %t 2>&1
 // RUN: FileCheck %s -input-file %t
-// RUN: %clang_cc1 -Eonly %t.min.c
+// RUN: %clang_cc1 -Eonly %t
 
 // CHECK:      #ifdef TEST
 // CHECK-NEXT: #include <string>

>From 6221d06e67da79c2052ee5538bc4107a567d1170 Mon Sep 17 00:00:00 2001
From: Ben Langmuir <[email protected]>
Date: Fri, 30 Oct 2026 11:59:10 -0700
Subject: [PATCH 3/3] Changes per review: release note, simplified return expr,
 simplified test

---
 clang/docs/ReleaseNotes.md                    |  1 +
 clang/lib/Lex/DependencyDirectivesScanner.cpp |  8 +--
 ...to_dependency_directives_function_macros.c | 71 +++----------------
 3 files changed, 15 insertions(+), 65 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4b9e9228380d1d..f2cc86bf9ccc23 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -824,6 +824,7 @@ documentation](CIR/index.md) for more information regarding 
ClangIR's status and
 - Fixed auto type inference being rejected when the initializer is a 
bit-field. (#GH226280)
 - Fixed failed assertion when creating a compound literal with erroneous 
initializer at file scope. (#GH229888)
 - Fixed conversion from `float` to `bool` in `__builtin_convertvector`. 
(#GH228649)
+- Fixed `-print-dependency-directives-minimized-source` output for object-like 
macros starting with '(' so that it is not incorrectly turned into a 
function-like macro.
 
 #### Bug Fixes to Compiler Builtins
 
diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp 
b/clang/lib/Lex/DependencyDirectivesScanner.cpp
index e39fc55e56df85..8a6cb39d3e28ce 100644
--- a/clang/lib/Lex/DependencyDirectivesScanner.cpp
+++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp
@@ -1113,11 +1113,9 @@ void clang::printDependencyDirectivesAsSource(
     // between the name and the body to avoid it being converted to a
     // function-like macro.
     constexpr unsigned FirstBodyIdx = 3; // `#`, `define`, <NAME>, <BODY...>
-    if (Kind == pp_define && TokIdx == FirstBodyIdx &&
-        Prev.is(tok::raw_identifier) && Tok.is(tok::l_paren) &&
-        Tok.Offset > Prev.getEnd())
-      return true;
-    return false;
+    return Kind == pp_define && TokIdx == FirstBodyIdx &&
+       Prev.is(tok::raw_identifier) && Tok.is(tok::l_paren) &&
+       Tok.Offset > Prev.getEnd();
   };
 
   for (const dependency_directives_scan::Directive &Directive : Directives) {
diff --git 
a/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c 
b/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c
index 50786b7b80e150..f4be815caeda8d 100644
--- 
a/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c
+++ 
b/clang/test/Lexer/minimize_source_to_dependency_directives_function_macros.c
@@ -1,66 +1,17 @@
 // RUN: %clang_cc1 -print-dependency-directives-minimized-source %s > %t
 // RUN: %clang_cc1 -E -dM %t | FileCheck %s
 
-// The conditional defines below all rely on the printer preserving the macro
-// definitions and #if conditions accurately.
-
-#define ADD(x, y) ((x) + (y))
-#define SHL(x, n) ((x) << (n))
-#define HAS(x) (x)
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define BAR() 42
-
-#if ADD(1, 2) > 0
-#define POSITIVE_SUM
-// CHECK-DAG: #define POSITIVE_SUM
-#endif
-
-#if ADD(1, 2) == 3 && SHL(1, 3) == 8
-#define MATH_OK
-// CHECK-DAG: #define MATH_OK
-#endif
-
-#if HAS(0) || HAS(1)
-#define HAS_EITHER
-// CHECK-DAG: #define HAS_EITHER
-#endif
-
-#if !ADD(0, 0)
-#define NEGATED
-// CHECK-DAG: #define NEGATED
-#endif
-
-#if 1 + HAS(2)
-#define LEADING_NUM
-// CHECK-DAG: #define LEADING_NUM
-#endif
-
-#if BAR() + BAR() == 84
-#define EMPTY_ARGS
-// CHECK-DAG: #define EMPTY_ARGS
-#endif
-
-#if MIN(1, 2) == 1
-#define MIN_OK
-// CHECK-DAG: #define MIN_OK
-#endif
-
-#if HAS(1) - HAS(2) < 0
-#define SUB_OK
-// CHECK-DAG: #define SUB_OK
-#endif
-
-#if HAS(0xff) & 0xf0
-#define BITWISE
-// CHECK-DAG: #define BITWISE
-#endif
-
-#if HAS(1) << 2 | HAS(2)
-#define SHIFT_OR
-// CHECK-DAG: #define SHIFT_OR
+// Object-like macro: losing the space would turn this into an invalid 
function-like macro definition.
+#define ENABLED (1)
+#if ENABLED
+#define OBJECT_OK
 #endif
+// CHECK-DAG: #define OBJECT_OK
 
-#if defined(FOO) && ADD(1, 2) + ADD(3, 4) > 5
-#define COMPLEX_BUT_FALSE
-// CHECK-NOT: #define COMPLEX_BUT_FALSE
+// Function-like macro: no space may be inserted between the macro name and 
the opening parenthesis.
+#define ID(x) (x)
+#define NO_ARGS() (1)
+#if ID(1) && !ID(0) && NO_ARGS()
+#define FUNCTION_OK
 #endif
+// CHECK-DAG: #define FUNCTION_OK

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

Reply via email to