[clang] Add `pragma clang scope [push|pop]` (PR #121025)
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)
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)
@@ -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)
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)
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)
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)
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
