diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1993,7 +1993,7 @@ private: PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - StringLiteral *SL); + bool TreatAsStringLiteral, StringLiteral *SL); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); @@ -2009,7 +2009,8 @@ public: /// Create a PredefinedExpr. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, StringLiteral *SL); + QualType FNTy, IdentKind IK, + bool TreatAsStringLiteral, StringLiteral *SL); /// Create an empty PredefinedExpr. static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, @@ -2019,6 +2020,10 @@ return static_cast(PredefinedExprBits.Kind); } + bool getTreatAsStringLiteral() const { + return PredefinedExprBits.TreatAsStringLiteral; + } + SourceLocation getLocation() const { return PredefinedExprBits.Loc; } void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h --- a/clang/include/clang/AST/IgnoreExpr.h +++ b/clang/include/clang/AST/IgnoreExpr.h @@ -166,6 +166,11 @@ return CE->getChosenSubExpr(); } + else if (auto *PE = dyn_cast(E)) { + if (PE->getTreatAsStringLiteral()) + return PE->getFunctionName(); + } + return E; } diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -364,6 +364,8 @@ /// for the predefined identifier. unsigned HasFunctionName : 1; + unsigned TreatAsStringLiteral : 1; + /// The location of this PredefinedExpr. SourceLocation Loc; }; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7068,7 +7068,8 @@ return std::move(Err); return PredefinedExpr::Create(Importer.getToContext(), ToBeginLoc, ToType, - E->getIdentKind(), ToFunctionName); + E->getIdentKind(), E->getTreatAsStringLiteral(), + ToFunctionName); } ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -663,13 +663,14 @@ } PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - StringLiteral *SL) + bool TreatAsStringLiteral, StringLiteral *SL) : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) { PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && "IdentKind do not fit in PredefinedExprBitfields!"); bool HasFunctionName = SL != nullptr; PredefinedExprBits.HasFunctionName = HasFunctionName; + PredefinedExprBits.TreatAsStringLiteral = TreatAsStringLiteral; PredefinedExprBits.Loc = L; if (HasFunctionName) setFunctionName(SL); @@ -683,11 +684,12 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, + bool TreatAsStringLiteral, StringLiteral *SL) { bool HasFunctionName = SL != nullptr; void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); - return new (Mem) PredefinedExpr(L, FNTy, IK, SL); + return new (Mem) PredefinedExpr(L, FNTy, IK, TreatAsStringLiteral, SL); } PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3582,7 +3582,8 @@ } } - return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); + return PredefinedExpr::Create(Context, Loc, ResTy, IK, LangOpts.MicrosoftExt, + SL); } ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -173,6 +173,8 @@ E = GSE->getResultExpr(); } else if (ChooseExpr *CE = dyn_cast(E)) { E = CE->getChosenSubExpr(); + } else if (PredefinedExpr *PE = dyn_cast(E)) { + E = PE->getFunctionName(); } else { llvm_unreachable("unexpected expr in string literal init"); } diff --git a/clang/test/Sema/ms_predefined_expr.cpp b/clang/test/Sema/ms_predefined_expr.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/ms_predefined_expr.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions +// expected-no-diagnostics + +void f() { + const char a[] = __FUNCTION__; + const char b[] = __FUNCDNAME__; + const char c[] = __FUNCSIG__; + const char d[] = __func__; + const char e[] = __PRETTY_FUNCTION__; +}