[clang] [clang] Add support for optional func-name argument in #pragma init_seg (PR #167133)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Nov 8 04:15:01 PST 2025
https://github.com/Shriiraz created https://github.com/llvm/llvm-project/pull/167133
This patch implements parsing of the optional [, func-name] argument of MSVC's #pragma init_seg directive. The function identifier is now parsed and stored in Sema, matching MSVC's accepted syntax.
No behavior changes to code generation yet.
Fixes the FIXME comment in ParsePragma.cpp.
>From bf1b6fbc5e23ff9b2b7d48b4ca7134fcf47693b5 Mon Sep 17 00:00:00 2001
From: Shriiraz Kukatla <shriiraz at lolMBP.local>
Date: Sat, 8 Nov 2025 17:34:53 +0530
Subject: [PATCH] [clang] Add support for optional func-name argument in
#pragma init_seg
This patch implements parsing of the optional [, func-name] argument of
MSVC's #pragma init_seg directive. The function identifier is now parsed
and stored in Sema, matching MSVC's accepted syntax.
No behavior changes to code generation yet.
Fixes the FIXME comment in ParsePragma.cpp.
Signed-off-by: Shriiraz Kukatla <shriiraz at lolMBP.local>
---
clang/include/clang/Sema/Sema.h | 10 +++++++-
clang/lib/Parse/ParsePragma.cpp | 34 ++++++++++++++++++++++++--
clang/lib/Sema/Sema.cpp | 2 +-
clang/lib/Sema/SemaAttr.cpp | 15 ++++++++----
clang/test/SemaCXX/pragma-init_seg.cpp | 3 +++
5 files changed, 55 insertions(+), 9 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0470645a9e7ad..ef9e993ed4ab3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2075,6 +2075,10 @@ class Sema final : public SemaBase {
/// Last section used with #pragma init_seg.
StringLiteral *CurInitSeg;
SourceLocation CurInitSegLoc;
+ /// Optional function name provided to #pragma init_seg([seg][, func-name]).
+ /// When present, stores the IdentifierInfo and its location.
+ IdentifierInfo *CurInitSegFn;
+ SourceLocation CurInitSegFnLoc;
/// Sections used with #pragma alloc_text.
llvm::StringMap<std::tuple<StringRef, SourceLocation>> FunctionToSectionMap;
@@ -2245,8 +2249,12 @@ class Sema final : public SemaBase {
StringLiteral *SegmentName);
/// Called on well-formed \#pragma init_seg().
+ /// If a function name is provided (", func-name"), it will be passed
+ /// via Func and FuncLoc.
void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
- StringLiteral *SegmentName);
+ StringLiteral *SegmentName,
+ IdentifierInfo *Func = nullptr,
+ SourceLocation FuncLoc = SourceLocation());
/// Called on well-formed \#pragma alloc_text().
void ActOnPragmaMSAllocText(
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 7c2b9280f0b76..8f7f256c5ce0a 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1229,6 +1229,11 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
// Parse either the known section names or the string section name.
StringLiteral *SegmentName = nullptr;
+ // Optional function identifier provided as the second argument to
+ // #pragma init_seg([segment][, func-name]). Declared here so it's in scope
+ // for the call to ActOnPragmaMSInitSeg below.
+ IdentifierInfo *FuncII = nullptr;
+ SourceLocation FuncLoc;
if (Tok.isAnyIdentifier()) {
auto *II = Tok.getIdentifierInfo();
StringRef Section = llvm::StringSwitch<StringRef>(II->getName())
@@ -1259,7 +1264,31 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
<< PragmaName;
return false;
}
- // FIXME: Add support for the '[, func-name]' part of the pragma.
+ // Nothing else here; the optional ', func-name' (if present) will be
+ // parsed after the segment parsing so it works whether the segment was
+ // specified as a known identifier or as a string literal.
+ }
+
+ // After parsing the segment name (either via identifier mapping or a
+ // string literal), optionally parse a comma and an identifier naming the
+ // helper function to be used in place of atexit.
+ // Only consume the comma if an identifier follows; otherwise leave it
+ // for ExpectAndConsume(tok::r_paren) to report the error naturally (e.g.,
+ // for malformed pragmas like #pragma init_seg("a", "b")).
+ if (Tok.is(tok::comma)) {
+ // Save current token state for potential backtrack.
+ Token SavedTok = Tok;
+ PP.Lex(Tok); // tentatively consume comma
+ if (Tok.is(tok::identifier)) {
+ // The comma is followed by an identifier; keep both consumed.
+ FuncII = Tok.getIdentifierInfo();
+ FuncLoc = Tok.getLocation();
+ PP.Lex(Tok); // consume identifier and move to next token
+ } else {
+ // Not an identifier after comma; restore and don't consume the comma.
+ // The r_paren check below will produce the expected diagnostics.
+ Tok = SavedTok;
+ }
}
if (!SegmentName) {
@@ -1273,7 +1302,8 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
PragmaName))
return false;
- Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName);
+ Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName, FuncII,
+ FuncLoc);
return true;
}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 46addea232b03..1620c2890d911 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -313,7 +313,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
CodeSegStack(nullptr), StrictGuardStackCheckStack(false),
FpPragmaStack(FPOptionsOverride()), CurInitSeg(nullptr),
- VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
+ CurInitSegFn(nullptr), CurInitSegFnLoc(), VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
StdCoroutineTraitsCache(nullptr), IdResolver(pp),
OriginalLexicalContext(nullptr), StdInitializerList(nullptr),
StdTypeIdentity(nullptr),
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 8411a3da8322d..eec8326dabad7 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -888,12 +888,17 @@ void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
}
void Sema::ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
- StringLiteral *SegmentName) {
- // There's no stack to maintain, so we just have a current section. When we
- // see the default section, reset our current section back to null so we stop
- // tacking on unnecessary attributes.
- CurInitSeg = SegmentName->getString() == ".CRT$XCU" ? nullptr : SegmentName;
+ StringLiteral *SegmentName,
+ IdentifierInfo *Func,
+ SourceLocation FuncLoc) {
+
+ // When we see the default section, reset back to null.
+ CurInitSeg = (SegmentName->getString() == ".CRT$XCU") ? nullptr : SegmentName;
CurInitSegLoc = PragmaLocation;
+
+ // Store optional function identifier (may be null).
+ CurInitSegFn = Func;
+ CurInitSegFnLoc = Func ? FuncLoc : SourceLocation();
}
void Sema::ActOnPragmaMSAllocText(
diff --git a/clang/test/SemaCXX/pragma-init_seg.cpp b/clang/test/SemaCXX/pragma-init_seg.cpp
index 1b22939f18e33..7e5d58e608ce1 100644
--- a/clang/test/SemaCXX/pragma-init_seg.cpp
+++ b/clang/test/SemaCXX/pragma-init_seg.cpp
@@ -17,6 +17,9 @@
#pragma init_seg("a" L"b") // expected-warning {{expected non-wide string literal in '#pragma init_seg'}}
#pragma init_seg(compiler)
+// Test optional func-name parsing: declare an identifier and use it.
+int myexit();
+#pragma init_seg(compiler, myexit)
#else
#pragma init_seg(compiler) // expected-warning {{'#pragma init_seg' is only supported when targeting a Microsoft environment}}
#endif
More information about the cfe-commits
mailing list