Skip to content

Commit 856f384

Browse files
committed
[clang] Make predefined expressions string literals under -fms-extensions
MSVC makes these string literals [1][2]. [1] https://godbolt.org/z/6vnTzbExx [2] https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 Fixes swiftlang#114 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D146764
1 parent 5545f1b commit 856f384

14 files changed

+82
-8
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,9 @@ Bug Fixes to C++ Support
416416
initialization.
417417
(`#61567 <https://github.com/llvm/llvm-project/issues/61567>`_)
418418
- Fix a crash when expanding a pack as the index of a subscript expression.
419+
- Some predefined expressions are now treated as string literals in MSVC
420+
compatibility mode.
421+
(`#114 <https://github.com/llvm/llvm-project/issues/114>`_)
419422

420423
Bug Fixes to AST Handling
421424
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/Expr.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,7 +1992,7 @@ class PredefinedExpr final
19921992

19931993
private:
19941994
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
1995-
StringLiteral *SL);
1995+
bool IsTransparent, StringLiteral *SL);
19961996

19971997
explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName);
19981998

@@ -2007,8 +2007,12 @@ class PredefinedExpr final
20072007

20082008
public:
20092009
/// Create a PredefinedExpr.
2010+
///
2011+
/// If IsTransparent, the PredefinedExpr is transparently handled as a
2012+
/// StringLiteral.
20102013
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
2011-
QualType FNTy, IdentKind IK, StringLiteral *SL);
2014+
QualType FNTy, IdentKind IK, bool IsTransparent,
2015+
StringLiteral *SL);
20122016

20132017
/// Create an empty PredefinedExpr.
20142018
static PredefinedExpr *CreateEmpty(const ASTContext &Ctx,
@@ -2018,6 +2022,8 @@ class PredefinedExpr final
20182022
return static_cast<IdentKind>(PredefinedExprBits.Kind);
20192023
}
20202024

2025+
bool isTransparent() const { return PredefinedExprBits.IsTransparent; }
2026+
20212027
SourceLocation getLocation() const { return PredefinedExprBits.Loc; }
20222028
void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; }
20232029

clang/include/clang/AST/IgnoreExpr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ inline Expr *IgnoreParensSingleStep(Expr *E) {
166166
return CE->getChosenSubExpr();
167167
}
168168

169+
else if (auto *PE = dyn_cast<PredefinedExpr>(E)) {
170+
if (PE->isTransparent())
171+
return PE->getFunctionName();
172+
}
173+
169174
return E;
170175
}
171176

clang/include/clang/AST/Stmt.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ class alignas(void *) Stmt {
364364
/// for the predefined identifier.
365365
unsigned HasFunctionName : 1;
366366

367+
/// True if this PredefinedExpr should be treated as a StringLiteral (for
368+
/// MSVC compatibility).
369+
unsigned IsTransparent : 1;
370+
367371
/// The location of this PredefinedExpr.
368372
SourceLocation Loc;
369373
};

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">;
11901190
def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">;
11911191
def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">;
11921192
def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">;
1193+
def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">;
11931194

11941195
// Aliases.
11951196
def : DiagGroup<"msvc-include", [MicrosoftInclude]>;
@@ -1207,7 +1208,7 @@ def Microsoft : DiagGroup<"microsoft",
12071208
MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast,
12081209
MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag,
12091210
MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftStaticAssert,
1210-
MicrosoftInconsistentDllImport]>;
1211+
MicrosoftInitFromPredefined, MicrosoftInconsistentDllImport]>;
12111212

12121213
def ClangClPch : DiagGroup<"clang-cl-pch">;
12131214

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ def err_expr_not_string_literal : Error<"expression is not a string literal">;
112112
def ext_predef_outside_function : Warning<
113113
"predefined identifier is only valid inside function">,
114114
InGroup<DiagGroup<"predefined-identifier-outside-function">>;
115+
def ext_init_from_predefined : ExtWarn<
116+
"initializing an array from a '%0' predefined identifier is a Microsoft extension">,
117+
InGroup<MicrosoftInitFromPredefined>;
115118
def warn_float_overflow : Warning<
116119
"magnitude of floating-point constant too large for type %0; maximum is %1">,
117120
InGroup<LiteralRange>;

clang/lib/AST/ASTImporter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7068,7 +7068,8 @@ ExpectedStmt ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) {
70687068
return std::move(Err);
70697069

70707070
return PredefinedExpr::Create(Importer.getToContext(), ToBeginLoc, ToType,
7071-
E->getIdentKind(), ToFunctionName);
7071+
E->getIdentKind(), E->isTransparent(),
7072+
ToFunctionName);
70727073
}
70737074

70747075
ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {

clang/lib/AST/Expr.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -663,13 +663,14 @@ std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context,
663663
}
664664

665665
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
666-
StringLiteral *SL)
666+
bool IsTransparent, StringLiteral *SL)
667667
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) {
668668
PredefinedExprBits.Kind = IK;
669669
assert((getIdentKind() == IK) &&
670670
"IdentKind do not fit in PredefinedExprBitfields!");
671671
bool HasFunctionName = SL != nullptr;
672672
PredefinedExprBits.HasFunctionName = HasFunctionName;
673+
PredefinedExprBits.IsTransparent = IsTransparent;
673674
PredefinedExprBits.Loc = L;
674675
if (HasFunctionName)
675676
setFunctionName(SL);
@@ -683,11 +684,11 @@ PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName)
683684

684685
PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
685686
QualType FNTy, IdentKind IK,
686-
StringLiteral *SL) {
687+
bool IsTransparent, StringLiteral *SL) {
687688
bool HasFunctionName = SL != nullptr;
688689
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
689690
alignof(PredefinedExpr));
690-
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
691+
return new (Mem) PredefinedExpr(L, FNTy, IK, IsTransparent, SL);
691692
}
692693

693694
PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx,

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3581,7 +3581,8 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
35813581
}
35823582
}
35833583

3584-
return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL);
3584+
return PredefinedExpr::Create(Context, Loc, ResTy, IK, LangOpts.MicrosoftExt,
3585+
SL);
35853586
}
35863587

35873588
ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,

clang/lib/Sema/SemaInit.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ static void updateStringLiteralType(Expr *E, QualType Ty) {
174174
E = GSE->getResultExpr();
175175
} else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
176176
E = CE->getChosenSubExpr();
177+
} else if (PredefinedExpr *PE = dyn_cast<PredefinedExpr>(E)) {
178+
E = PE->getFunctionName();
177179
} else {
178180
llvm_unreachable("unexpected expr in string literal init");
179181
}
@@ -8501,6 +8503,15 @@ ExprResult InitializationSequence::Perform(Sema &S,
85018503
<< Init->getSourceRange();
85028504
}
85038505

8506+
if (S.getLangOpts().MicrosoftExt && Args.size() == 1 &&
8507+
isa<PredefinedExpr>(Args[0]) && Entity.getType()->isArrayType()) {
8508+
// Produce a Microsoft compatibility warning when initializing from a
8509+
// predefined expression since MSVC treats predefined expressions as string
8510+
// literals.
8511+
Expr *Init = Args[0];
8512+
S.Diag(Init->getBeginLoc(), diag::ext_init_from_predefined) << Init;
8513+
}
8514+
85048515
// OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope
85058516
QualType ETy = Entity.getType();
85068517
bool HasGlobalAS = ETy.hasAddressSpace() &&

clang/lib/Serialization/ASTReaderStmt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
582582
bool HasFunctionName = Record.readInt();
583583
E->PredefinedExprBits.HasFunctionName = HasFunctionName;
584584
E->PredefinedExprBits.Kind = Record.readInt();
585+
E->PredefinedExprBits.IsTransparent = Record.readInt();
585586
E->setLocation(readSourceLocation());
586587
if (HasFunctionName)
587588
E->setFunctionName(cast<StringLiteral>(Record.readSubExpr()));

clang/lib/Serialization/ASTWriterStmt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
593593
bool HasFunctionName = E->getFunctionName() != nullptr;
594594
Record.push_back(HasFunctionName);
595595
Record.push_back(E->getIdentKind()); // FIXME: stable encoding
596+
Record.push_back(E->isTransparent());
596597
Record.AddSourceLocation(E->getLocation());
597598
if (HasFunctionName)
598599
Record.AddStmt(E->getFunctionName());

clang/test/Modules/predefined.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: cd %t
4+
5+
// RUN: %clang_cc1 -x c++ -std=c++20 -emit-module-interface a.h -o a.pcm -fms-extensions -verify
6+
// RUN: %clang_cc1 -std=c++20 a.cpp -fmodule-file=A=a.pcm -fms-extensions -fsyntax-only -verify
7+
8+
//--- a.h
9+
10+
// expected-no-diagnostics
11+
12+
export module A;
13+
14+
export template <typename T>
15+
void f() {
16+
char a[] = __func__;
17+
}
18+
19+
//--- a.cpp
20+
21+
// [email protected]:8 {{initializing an array from a '__func__' predefined identifier is a Microsoft extension}}
22+
23+
import A;
24+
25+
void g() {
26+
f<int>(); // expected-note {{in instantiation of function template specialization 'f<int>' requested here}}
27+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions
2+
3+
void f() {
4+
const char a[] = __FUNCTION__; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}}
5+
const char b[] = __FUNCDNAME__; // expected-warning{{initializing an array from a '__FUNCDNAME__' predefined identifier is a Microsoft extension}}
6+
const char c[] = __FUNCSIG__; // expected-warning{{initializing an array from a '__FUNCSIG__' predefined identifier is a Microsoft extension}}
7+
const char d[] = __func__; // expected-warning{{initializing an array from a '__func__' predefined identifier is a Microsoft extension}}
8+
const char e[] = __PRETTY_FUNCTION__; // expected-warning{{initializing an array from a '__PRETTY_FUNCTION__' predefined identifier is a Microsoft extension}}
9+
}

0 commit comments

Comments
 (0)