[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2025-03-12 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> I wonder if we had an rfc for this. Maybe we should solicit some feedback 
> before moving forward with this extension.

Agreed, I think this should have an RFC for wider discussion.

https://github.com/llvm/llvm-project/pull/121025
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2025-03-01 Thread Vassil Vassilev via cfe-commits

vgvassilev wrote:

I wonder if we had an rfc for this. Maybe we should solicit some feedback 
before moving forward with this extension.

https://github.com/llvm/llvm-project/pull/121025
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2025-02-28 Thread Michael Spencer via cfe-commits


@@ -254,7 +285,7 @@ void Preprocessor::updateModuleMacroInfo(const 
IdentifierInfo *II,
 }
 
 void Preprocessor::dumpMacroInfo(const IdentifierInfo *II) {
-  ArrayRef Leaf;
+  ArrayRef Leaf;

Bigcheese wrote:

This patch has a bunch of unrelated formatting changes, so I'm not sure if 
anything else in this file actually changes.

https://github.com/llvm/llvm-project/pull/121025
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2025-02-28 Thread Michael Spencer via cfe-commits

Bigcheese wrote:

Given that some `#pragma`s also impact Sema things, I think `scope` is a bit 
confusing for what it applies to. I think something like `macro_scope` would be 
a better name.

As for the extension itself, I think it could be useful, but I'm not sure how 
our language extension policy applies here for pragmas. This is kind of a 
general purpose extension and would make the code only usable with Clang, as 
conditionally applying the pragma would mean the macros still show up and your 
code breaks (otherwise why would you have the pragma in the first place).

This also hides include guards, and I don't think it does anything about 
include skipping, so it may behave as if the include guard was still there.

https://github.com/llvm/llvm-project/pull/121025
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2024-12-23 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff 2c95e60df53ba1a5765b3fad9e8ddaff70f21994 
5433a9134beb8faf1e2b662c96f76d7e8bc814de --extensions h,c,cpp -- 
clang/test/Lexer/Inputs/SomeHeaderThatDefinesAwfulThings.h 
clang/test/Lexer/pragma-scope.c clang/include/clang/Lex/Preprocessor.h 
clang/lib/Lex/PPMacroExpansion.cpp clang/lib/Lex/Pragma.cpp
``





View the diff from clang-format here.


``diff
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 96240533de..7d9292d072 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1059,7 +1059,8 @@ private:
   /// Warning information for macro annotations.
   llvm::DenseMap AnnotationInfos;
 
-  using MacroScopeVec = llvm::SmallVector >;
+  using MacroScopeVec =
+  llvm::SmallVector>;
   MacroScopeVec *CurScope = nullptr;
   llvm::SmallVector MacroScopeStack;
 
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp 
b/clang/lib/Lex/PPMacroExpansion.cpp
index f47a2eb1a3..ecc37bbd01 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -80,9 +80,9 @@ void Preprocessor::popMacroScope(SourceLocation Loc) {
   for (auto It = CurScope->rbegin(); It != CurScope->rend(); ++It) {
 MacroDirective *Prev = It->second->getPrevious();
 if (Prev && Prev->getKind() == MacroDirective::MD_Define) {
-DefMacroDirective *MD =
-AllocateDefMacroDirective(Prev->getMacroInfo(), Loc);
-appendMacroDirective(It->first, MD);
+  DefMacroDirective *MD =
+  AllocateDefMacroDirective(Prev->getMacroInfo(), Loc);
+  appendMacroDirective(It->first, MD);
 } else {
   UndefMacroDirective *Undef = AllocateUndefMacroDirective(Loc);
   appendMacroDirective(It->first, Undef);
@@ -105,7 +105,7 @@ void Preprocessor::appendMacroDirective(IdentifierInfo *II,
   StoredMD.overrideActiveModuleMacros(*this, II);
 
   if (CurScope)
-CurScope->push_back(std::make_pair(II,MD));
+CurScope->push_back(std::make_pair(II, MD));
 
   if (needModuleMacros()) {
 // Track that we created a new macro directive, so we know we should
@@ -1192,8 +1192,8 @@ static bool HasExtension(const Preprocessor &PP, 
StringRef Extension) {
   Extension.size() >= 4)
 Extension = Extension.substr(2, Extension.size() - 4);
 
-  // Because we inherit the feature list from HasFeature, this string switch
-  // must be less restrictive than HasFeature's.
+// Because we inherit the feature list from HasFeature, this string switch
+// must be less restrictive than HasFeature's.
 #define EXTENSION(Name, Predicate) .Case(#Name, Predicate)
   return llvm::StringSwitch(Extension)
 #include "clang/Basic/Features.def"

``




https://github.com/llvm/llvm-project/pull/121025
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2024-12-23 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Chris B (llvm-beanz)


Changes

Have you ever had that horrible realization that some header you included 
defines a macro that matches a commonly used word that appears throughout your 
codebase? What kind of horrible person would define `max` or `min` as a macro 
and put it into a public header that ships in an SDK?!?!

Well, I have the solution for you!

Enter "Macro Scopes": with this new preprocessor extension you can wrap pesky 
includes with `#pragma clang scope push` and `#pragma clang scope pop` to 
protect your carefully curated source from preprocessor macros that bleed from 
your dependencies.

---

Patch is 42.58 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/121025.diff


7 Files Affected:

- (modified) clang/docs/LanguageExtensions.rst (+34) 
- (modified) clang/include/clang/Basic/DiagnosticLexKinds.td (+2-2) 
- (modified) clang/include/clang/Lex/Preprocessor.h (+7) 
- (modified) clang/lib/Lex/PPMacroExpansion.cpp (+266-233) 
- (modified) clang/lib/Lex/Pragma.cpp (+23-2) 
- (added) clang/test/Lexer/Inputs/SomeHeaderThatDefinesAwfulThings.h (+1) 
- (added) clang/test/Lexer/pragma-scope.c (+36) 


``diff
diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index cc5f1d4ddf4477..a81fa833eafdc9 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -5738,6 +5738,40 @@ in user headers or code. This is controlled by 
``-Wpedantic-macros``. Final
 macros will always warn on redefinition, including situations with identical
 bodies and in system headers.
 
+Macro Scope
+===
+
+Clang supports the pragma ``#pragma clang scope`` which is provided with an
+argument ``push`` or ``pop`` to denote entering and leaving macro scopes. On
+entering a macro scope all macro definitions and undefinitions are recorded so
+that they can be reverted on leaving the scope.
+
+.. code-block:: c
+
+   #define NUM_DOGGOS 2
+
+   #pragma clang scope push
+   #define NUM_DOGGOS 3
+   #pragma clang scope pop // NUM_DOGGOS is restored to 2
+
+   #pragma clang scope push
+   #undef NUM_DOGGOS
+   #pragma clang scope pop // NUM_DOGGOS is restored to 2
+
+   #undef NUM_DOGGOS
+   #pragma clang scope push
+   #define NUM_DOGGOS 1
+   #pragma clang scope pop // NUM_DOGGOS is restored to undefined
+
+A macro scope can be used to wrap header includes to isolate headers from
+leaking macros to the outer source file.
+
+.. code-block:: c
+
+   #pragma clang scope push
+   #include 
+   #pragma clang scope pop // None of the defines from the included header 
persist.
+
 Line Control
 
 
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 959376b0847216..a1f57aafb51bf7 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -693,8 +693,8 @@ def warn_pragma_diagnostic_invalid :
ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal',"
 " 'push', or 'pop'">,
InGroup;
-def warn_pragma_diagnostic_cannot_pop :
-   ExtWarn<"pragma diagnostic pop could not pop, no matching push">,
+def warn_pragma_cannot_pop :
+   ExtWarn<"pragma %select{diagnostic|scope}0 pop could not pop, no matching 
push">,
InGroup;
 def warn_pragma_diagnostic_invalid_option :
ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">,
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 3d223c345ea156..96240533deff5e 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1059,6 +1059,10 @@ class Preprocessor {
   /// Warning information for macro annotations.
   llvm::DenseMap AnnotationInfos;
 
+  using MacroScopeVec = llvm::SmallVector >;
+  MacroScopeVec *CurScope = nullptr;
+  llvm::SmallVector MacroScopeStack;
+
   /// A "freelist" of MacroArg objects that can be
   /// reused for quick allocation.
   MacroArgs *MacroArgCache = nullptr;
@@ -2896,6 +2900,9 @@ class Preprocessor {
 AnnotationInfos[II].FinalAnnotationLoc = AnnotationLoc;
   }
 
+  void pushMacroScope();
+  void popMacroScope(SourceLocation Loc);
+
   const MacroAnnotations &getMacroAnnotations(const IdentifierInfo *II) const {
 return AnnotationInfos.find(II)->second;
   }
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp 
b/clang/lib/Lex/PPMacroExpansion.cpp
index 347c13da0ad215..f47a2eb1a37caf 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -66,7 +66,35 @@ Preprocessor::getLocalMacroDirectiveHistory(const 
IdentifierInfo *II) const {
 : Pos->second.getLatest();
 }
 
-void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective 
*MD){
+void Preprocessor::pushMacroScope() {
+  MacroScopeStack.emplace_back(MacroScopeVec());
+  C

[clang] Add `pragma clang scope [push|pop]` (PR #121025)

2024-12-23 Thread Chris B via cfe-commits

https://github.com/llvm-beanz created 
https://github.com/llvm/llvm-project/pull/121025

Have you ever had that horrible realization that some header you included 
defines a macro that matches a commonly used word that appears throughout your 
codebase? What kind of horrible person would define `max` or `min` as a macro 
and put it into a public header that ships in an SDK?!?!

Well, I have the solution for you!

Enter "Macro Scopes": with this new preprocessor extension you can wrap pesky 
includes with `#pragma clang scope push` and `#pragma clang scope pop` to 
protect your carefully curated source from preprocessor macros that bleed from 
your dependencies.

>From 5433a9134beb8faf1e2b662c96f76d7e8bc814de Mon Sep 17 00:00:00 2001
From: Chris Bieneman 
Date: Mon, 23 Dec 2024 21:22:28 -0600
Subject: [PATCH] Add `pragma clang scope [push|pop]`

Have you ever had that horrible realization that some header you
included defines a macro that matches a commonly used word that appears
throughout your codebase? What kind of horrible person would define
`max` or `min` as a macro and put it into a public header that ships in
an SDK?!?!

Well, I have the solution for you!

Enter "Macro Scopes": with this new preprocessor extension you can wrap
pesky includes with `#pragma clang scope push` and `#pragma clang scope
pop` to protect your carefully curated source from preprocessor macros
that bleed from your dependencies.
---
 clang/docs/LanguageExtensions.rst |  34 ++
 .../include/clang/Basic/DiagnosticLexKinds.td |   4 +-
 clang/include/clang/Lex/Preprocessor.h|   7 +
 clang/lib/Lex/PPMacroExpansion.cpp| 499 ++
 clang/lib/Lex/Pragma.cpp  |  25 +-
 .../Inputs/SomeHeaderThatDefinesAwfulThings.h |   1 +
 clang/test/Lexer/pragma-scope.c   |  36 ++
 7 files changed, 369 insertions(+), 237 deletions(-)
 create mode 100644 clang/test/Lexer/Inputs/SomeHeaderThatDefinesAwfulThings.h
 create mode 100644 clang/test/Lexer/pragma-scope.c

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index cc5f1d4ddf4477..a81fa833eafdc9 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -5738,6 +5738,40 @@ in user headers or code. This is controlled by 
``-Wpedantic-macros``. Final
 macros will always warn on redefinition, including situations with identical
 bodies and in system headers.
 
+Macro Scope
+===
+
+Clang supports the pragma ``#pragma clang scope`` which is provided with an
+argument ``push`` or ``pop`` to denote entering and leaving macro scopes. On
+entering a macro scope all macro definitions and undefinitions are recorded so
+that they can be reverted on leaving the scope.
+
+.. code-block:: c
+
+   #define NUM_DOGGOS 2
+
+   #pragma clang scope push
+   #define NUM_DOGGOS 3
+   #pragma clang scope pop // NUM_DOGGOS is restored to 2
+
+   #pragma clang scope push
+   #undef NUM_DOGGOS
+   #pragma clang scope pop // NUM_DOGGOS is restored to 2
+
+   #undef NUM_DOGGOS
+   #pragma clang scope push
+   #define NUM_DOGGOS 1
+   #pragma clang scope pop // NUM_DOGGOS is restored to undefined
+
+A macro scope can be used to wrap header includes to isolate headers from
+leaking macros to the outer source file.
+
+.. code-block:: c
+
+   #pragma clang scope push
+   #include 
+   #pragma clang scope pop // None of the defines from the included header 
persist.
+
 Line Control
 
 
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 959376b0847216..a1f57aafb51bf7 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -693,8 +693,8 @@ def warn_pragma_diagnostic_invalid :
ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal',"
 " 'push', or 'pop'">,
InGroup;
-def warn_pragma_diagnostic_cannot_pop :
-   ExtWarn<"pragma diagnostic pop could not pop, no matching push">,
+def warn_pragma_cannot_pop :
+   ExtWarn<"pragma %select{diagnostic|scope}0 pop could not pop, no matching 
push">,
InGroup;
 def warn_pragma_diagnostic_invalid_option :
ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">,
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 3d223c345ea156..96240533deff5e 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1059,6 +1059,10 @@ class Preprocessor {
   /// Warning information for macro annotations.
   llvm::DenseMap AnnotationInfos;
 
+  using MacroScopeVec = llvm::SmallVector >;
+  MacroScopeVec *CurScope = nullptr;
+  llvm::SmallVector MacroScopeStack;
+
   /// A "freelist" of MacroArg objects that can be
   /// reused for quick allocation.
   MacroArgs *MacroArgCache = nullptr;
@@ -2896,6 +2900,9 @@ class Preprocessor {
 AnnotationInfos[II].FinalAnnotationLoc = Annotat