diff --git a/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp @@ -88,7 +88,7 @@ "inside a lambda, '%0' expands to the name of the function call " "operator; consider capturing the name of the enclosing function " "explicitly") - << PredefinedExpr::getIdentKindName(E->getIdentKind()); + << E->getIdentKindName(); } } // namespace clang::tidy::bugprone 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 @@ -1994,10 +1994,8 @@ enum IdentKind { Func, Function, - LFunction, // Same as Function, but as wide string. FuncDName, FuncSig, - LFuncSig, // Same as FuncSig, but as wide string PrettyFunction, /// The same as PrettyFunction, except that the /// 'virtual' keyword is omitted for virtual member functions. @@ -2006,7 +2004,8 @@ private: PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - bool IsTransparent, StringLiteral *SL); + StringLiteral::StringKind E, bool IsTransparent, + StringLiteral *SL); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); @@ -2025,7 +2024,8 @@ /// If IsTransparent, the PredefinedExpr is transparently handled as a /// StringLiteral. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, bool IsTransparent, + QualType FNTy, IdentKind IK, + StringLiteral::StringKind E, bool IsTransparent, StringLiteral *SL); /// Create an empty PredefinedExpr. @@ -2036,6 +2036,10 @@ return static_cast(PredefinedExprBits.Kind); } + StringLiteral::StringKind getEncoding() const { + return static_cast(PredefinedExprBits.Encoding); + } + bool isTransparent() const { return PredefinedExprBits.IsTransparent; } SourceLocation getLocation() const { return PredefinedExprBits.Loc; } @@ -2053,9 +2057,10 @@ : nullptr; } - static StringRef getIdentKindName(IdentKind IK); + static StringRef getIdentKindName(IdentKind IK, + StringLiteral::StringKind Encoding); StringRef getIdentKindName() const { - return getIdentKindName(getIdentKind()); + return getIdentKindName(getIdentKind(), getEncoding()); } static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); 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 @@ -358,7 +358,11 @@ /// The kind of this PredefinedExpr. One of the enumeration values /// in PredefinedExpr::IdentKind. - unsigned Kind : 4; + unsigned Kind : 3; + + /// The encoding of this predefined expression. + /// One of the enumeration values of StringLiteral::StringKind. + unsigned Encoding : 3; /// True if this PredefinedExpr has a trailing "StringLiteral *" /// for the predefined identifier. diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -466,7 +466,17 @@ KEYWORD(__FUNCDNAME__ , KEYMS) KEYWORD(__FUNCSIG__ , KEYMS) KEYWORD(L__FUNCTION__ , KEYMS) +KEYWORD(L__FUNCDNAME__ , KEYMS) KEYWORD(L__FUNCSIG__ , KEYMS) +KEYWORD(u8__FUNCTION__ , KEYMS) +KEYWORD(u8__FUNCDNAME__ , KEYMS) +KEYWORD(u8__FUNCSIG__ , KEYMS) +KEYWORD(u__FUNCTION__ , KEYMS) +KEYWORD(u__FUNCDNAME__ , KEYMS) +KEYWORD(u__FUNCSIG__ , KEYMS) +KEYWORD(U__FUNCTION__ , KEYMS) +KEYWORD(U__FUNCDNAME__ , KEYMS) +KEYWORD(U__FUNCSIG__ , KEYMS) TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS) TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5718,7 +5718,8 @@ std::vector ExpandFunctionLocalPredefinedMacros(ArrayRef Toks); ExprResult BuildPredefinedExpr(SourceLocation Loc, - PredefinedExpr::IdentKind IK); + PredefinedExpr::IdentKind IK, + StringLiteral::StringKind E); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); 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 @@ -7160,8 +7160,8 @@ return std::move(Err); return PredefinedExpr::Create(Importer.getToContext(), ToBeginLoc, ToType, - E->getIdentKind(), E->isTransparent(), - ToFunctionName); + E->getIdentKind(), E->getEncoding(), + E->isTransparent(), 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 @@ -665,11 +665,15 @@ } PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - bool IsTransparent, StringLiteral *SL) + StringLiteral::StringKind E, bool IsTransparent, + StringLiteral *SL) : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) { PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && "IdentKind do not fit in PredefinedExprBitfields!"); + PredefinedExprBits.Encoding = E; + assert((getEncoding() == E) && + "Encoding do not fit in PredefinedExprBitfields!"); bool HasFunctionName = SL != nullptr; PredefinedExprBits.HasFunctionName = HasFunctionName; PredefinedExprBits.IsTransparent = IsTransparent; @@ -686,11 +690,12 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, + StringLiteral::StringKind E, bool IsTransparent, StringLiteral *SL) { bool HasFunctionName = SL != nullptr; void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); - return new (Mem) PredefinedExpr(L, FNTy, IK, IsTransparent, SL); + return new (Mem) PredefinedExpr(L, FNTy, IK, E, IsTransparent, SL); } PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx, @@ -700,22 +705,62 @@ return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName); } -StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) { +StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK, + StringLiteral::StringKind E) { switch (IK) { case Func: return "__func__"; + case Function: - return "__FUNCTION__"; + switch (E) { + case StringLiteral::Ordinary: + return "__FUNCTION__"; + case StringLiteral::Wide: + return "L__FUNCTION__"; + case StringLiteral::UTF8: + return "u8__FUNCTION__"; + case StringLiteral::UTF16: + return "u__FUNCTION__"; + case StringLiteral::UTF32: + return "U__FUNCTION__"; + case StringLiteral::Unevaluated: + llvm_unreachable("unexpected PredefinedExpr encoding"); + } + case FuncDName: - return "__FUNCDNAME__"; - case LFunction: - return "L__FUNCTION__"; + switch (E) { + case StringLiteral::Ordinary: + return "__FUNCDNAME__"; + case StringLiteral::Wide: + return "L__FUNCDNAME__"; + case StringLiteral::UTF8: + return "u8__FUNCDNAME__"; + case StringLiteral::UTF16: + return "u__FUNCDNAME__"; + case StringLiteral::UTF32: + return "U__FUNCDNAME__"; + case StringLiteral::Unevaluated: + llvm_unreachable("unexpected PredefinedExpr encoding"); + } + + case FuncSig: + switch (E) { + case StringLiteral::Ordinary: + return "__FUNCSIG__"; + case StringLiteral::Wide: + return "L__FUNCSIG__"; + case StringLiteral::UTF8: + return "u8__FUNCSIG__"; + case StringLiteral::UTF16: + return "u__FUNCSIG__"; + case StringLiteral::UTF32: + return "U__FUNCSIG__"; + case StringLiteral::Unevaluated: + llvm_unreachable("unexpected PredefinedExpr encoding"); + } + case PrettyFunction: return "__PRETTY_FUNCTION__"; - case FuncSig: - return "__FUNCSIG__"; - case LFuncSig: - return "L__FUNCSIG__"; case PrettyFunctionNoVirtual: break; } @@ -772,8 +817,7 @@ return std::string(Out.str()); } if (const FunctionDecl *FD = dyn_cast(CurrentDecl)) { - if (IK != PrettyFunction && IK != PrettyFunctionNoVirtual && - IK != FuncSig && IK != LFuncSig) + if (IK != PrettyFunction && IK != PrettyFunctionNoVirtual && IK != FuncSig) return FD->getNameAsString(); SmallString<256> Name; @@ -812,7 +856,7 @@ if (FD->hasWrittenPrototype()) FT = dyn_cast(AFT); - if (IK == FuncSig || IK == LFuncSig) { + if (IK == FuncSig) { switch (AFT->getCallConv()) { case CC_C: POut << "__cdecl "; break; case CC_X86StdCall: POut << "__stdcall "; break; @@ -837,8 +881,7 @@ if (FT->isVariadic()) { if (FD->getNumParams()) POut << ", "; POut << "..."; - } else if ((IK == FuncSig || IK == LFuncSig || - !Context.getLangOpts().CPlusPlus) && + } else if ((IK == FuncSig || !Context.getLangOpts().CPlusPlus) && !Decl->getNumParams()) { POut << "void"; } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1261,7 +1261,7 @@ } void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) { - JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind())); + JOS.attribute("name", PE->getIdentKindName()); } void JSONNodeDumper::VisitUnaryOperator(const UnaryOperator *UO) { diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1247,7 +1247,7 @@ } void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { - OS << PredefinedExpr::getIdentKindName(Node->getIdentKind()); + OS << Node->getIdentKindName(); } void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1084,7 +1084,7 @@ } void TextNodeDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { - OS << " " << PredefinedExpr::getIdentKindName(Node->getIdentKind()); + OS << " " << Node->getIdentKindName(); } void TextNodeDumper::VisitCharacterLiteral(const CharacterLiteral *Node) { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3020,8 +3020,7 @@ StringRef FnName = CurFn->getName(); if (FnName.startswith("\01")) FnName = FnName.substr(1); - StringRef NameItems[] = { - PredefinedExpr::getIdentKindName(E->getIdentKind()), FnName}; + StringRef NameItems[] = {E->getIdentKindName(), FnName}; std::string GVName = llvm::join(NameItems, NameItems + 2, "."); if (auto *BD = dyn_cast_or_null(CurCodeDecl)) { std::string Name = std::string(SL->getString()); diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -442,9 +442,14 @@ bool clang::isFunctionLocalStringLiteralMacro(tok::TokenKind K, const LangOptions &LO) { return LO.MicrosoftExt && - (K == tok::kw___FUNCTION__ || K == tok::kw_L__FUNCTION__ || - K == tok::kw___FUNCSIG__ || K == tok::kw_L__FUNCSIG__ || - K == tok::kw___FUNCDNAME__); + (K == tok::kw___FUNCTION__ || K == tok::kw___FUNCDNAME__ || + K == tok::kw___FUNCSIG__ || K == tok::kw_L__FUNCTION__ || + K == tok::kw_L__FUNCDNAME__ || K == tok::kw_L__FUNCSIG__ || + K == tok::kw_u8__FUNCTION__ || K == tok::kw_u8__FUNCDNAME__ || + K == tok::kw_u8__FUNCSIG__ || K == tok::kw_u__FUNCTION__ || + K == tok::kw_u__FUNCDNAME__ || K == tok::kw_u__FUNCSIG__ || + K == tok::kw_U__FUNCTION__ || K == tok::kw_U__FUNCDNAME__ || + K == tok::kw_U__FUNCSIG__); } bool clang::tokenIsLikeStringLiteral(const Token &Tok, const LangOptions &LO) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1296,7 +1296,17 @@ case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS] case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS] case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] + case tok::kw_L__FUNCDNAME__: // primary-expression: L__FUNCDNAME__ [MS] case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS] + case tok::kw_u8__FUNCTION__: // primary-expression: u8__FUNCTION__ [MS] + case tok::kw_u8__FUNCDNAME__: // primary-expression: u8__FUNCDNAME__ [MS] + case tok::kw_u8__FUNCSIG__: // primary-expression: u8__FUNCSIG__ [MS] + case tok::kw_u__FUNCTION__: // primary-expression: u__FUNCTION__ [MS] + case tok::kw_u__FUNCDNAME__: // primary-expression: u__FUNCDNAME__ [MS] + case tok::kw_u__FUNCSIG__: // primary-expression: u__FUNCSIG__ [MS] + case tok::kw_U__FUNCTION__: // primary-expression: U__FUNCTION__ [MS] + case tok::kw_U__FUNCDNAME__: // primary-expression: U__FUNCDNAME__ [MS] + case tok::kw_U__FUNCSIG__: // primary-expression: U__FUNCSIG__ [MS] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] // Function local predefined macros are represented by PredefinedExpr except // when Microsoft extensions are enabled and one of these macros is adjacent 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 @@ -1883,24 +1883,45 @@ ContainsUnexpandedParameterPack, ResultIndex); } -static PredefinedExpr::IdentKind getPredefinedExprKind(tok::TokenKind Kind) { +static std::pair +getPredefinedExprKind(tok::TokenKind Kind) { switch (Kind) { default: llvm_unreachable("unexpected TokenKind"); case tok::kw___func__: - return PredefinedExpr::Func; // [C99 6.4.2.2] + return {PredefinedExpr::Func, StringLiteral::Ordinary}; // [C99 6.4.2.2] case tok::kw___FUNCTION__: - return PredefinedExpr::Function; + return {PredefinedExpr::Function, StringLiteral::Ordinary}; case tok::kw___FUNCDNAME__: - return PredefinedExpr::FuncDName; // [MS] + return {PredefinedExpr::FuncDName, StringLiteral::Ordinary}; // [MS] case tok::kw___FUNCSIG__: - return PredefinedExpr::FuncSig; // [MS] + return {PredefinedExpr::FuncSig, StringLiteral::Ordinary}; // [MS] case tok::kw_L__FUNCTION__: - return PredefinedExpr::LFunction; // [MS] + return {PredefinedExpr::Function, StringLiteral::Wide}; // [MS] + case tok::kw_L__FUNCDNAME__: + return {PredefinedExpr::FuncDName, StringLiteral::Wide}; // [MS] case tok::kw_L__FUNCSIG__: - return PredefinedExpr::LFuncSig; // [MS] + return {PredefinedExpr::FuncSig, StringLiteral::Wide}; // [MS] + case tok::kw_u8__FUNCTION__: + return {PredefinedExpr::Function, StringLiteral::UTF8}; // [MS] + case tok::kw_u8__FUNCDNAME__: + return {PredefinedExpr::FuncDName, StringLiteral::UTF8}; // [MS] + case tok::kw_u8__FUNCSIG__: + return {PredefinedExpr::FuncSig, StringLiteral::UTF8}; // [MS] + case tok::kw_u__FUNCTION__: + return {PredefinedExpr::Function, StringLiteral::UTF16}; // [MS] + case tok::kw_u__FUNCDNAME__: + return {PredefinedExpr::FuncDName, StringLiteral::UTF16}; // [MS] + case tok::kw_u__FUNCSIG__: + return {PredefinedExpr::FuncSig, StringLiteral::UTF16}; // [MS] + case tok::kw_U__FUNCTION__: + return {PredefinedExpr::Function, StringLiteral::UTF32}; // [MS] + case tok::kw_U__FUNCDNAME__: + return {PredefinedExpr::FuncDName, StringLiteral::UTF32}; // [MS] + case tok::kw_U__FUNCSIG__: + return {PredefinedExpr::FuncSig, StringLiteral::UTF32}; // [MS] case tok::kw___PRETTY_FUNCTION__: - return PredefinedExpr::PrettyFunction; // [GNU] + return {PredefinedExpr::PrettyFunction, StringLiteral::Ordinary}; // [GNU] } } @@ -2001,20 +2022,36 @@ // Stringify predefined expression Diag(Tok.getLocation(), diag::ext_string_literal_from_predefined) << Tok.getKind(); + auto [ExprKind, Encoding] = getPredefinedExprKind(Tok.getKind()); SmallString<64> Str; llvm::raw_svector_ostream OS(Str); Token &Exp = ExpandedToks.emplace_back(); Exp.startToken(); - if (Tok.getKind() == tok::kw_L__FUNCTION__ || - Tok.getKind() == tok::kw_L__FUNCSIG__) { + switch (Encoding) { + case StringLiteral::Ordinary: + Exp.setKind(tok::string_literal); + break; + case StringLiteral::Wide: OS << 'L'; Exp.setKind(tok::wide_string_literal); - } else { - Exp.setKind(tok::string_literal); + break; + case StringLiteral::UTF8: + OS << "u8"; + Exp.setKind(tok::utf8_string_literal); + break; + case StringLiteral::UTF16: + OS << 'u'; + Exp.setKind(tok::utf16_string_literal); + break; + case StringLiteral::UTF32: + OS << 'U'; + Exp.setKind(tok::utf32_string_literal); + break; + case StringLiteral::Unevaluated: + llvm_unreachable("unexpected encoding"); } OS << '"' - << Lexer::Stringify(PredefinedExpr::ComputeName( - getPredefinedExprKind(Tok.getKind()), CurrentDecl)) + << Lexer::Stringify(PredefinedExpr::ComputeName(ExprKind, CurrentDecl)) << '"'; PP.CreateString(OS.str(), Exp, Tok.getLocation(), Tok.getEndLoc()); } @@ -3692,7 +3729,7 @@ } static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, - SmallString<32> &Target) { + SmallVectorImpl &Target) { Target.resize(CharByteWidth * (Source.size() + 1)); char *ResultPtr = &Target[0]; const llvm::UTF8 *ErrorPtr; @@ -3704,7 +3741,8 @@ } ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, - PredefinedExpr::IdentKind IK) { + PredefinedExpr::IdentKind IK, + StringLiteral::StringKind E) { Decl *currentDecl = getCurLocalScopeDecl(); if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); @@ -3716,35 +3754,43 @@ if (cast(currentDecl)->isDependentContext()) ResTy = Context.DependentTy; else { - // Pre-defined identifiers are of type char[x], where x is the length of - // the string. + // Pre-defined identifiers are of type CharT[x], + // where x is the length of the string. + SmallString<128> RawChars; auto Str = PredefinedExpr::ComputeName(IK, currentDecl); - unsigned Length = Str.length(); - - llvm::APInt LengthI(32, Length + 1); - if (IK == PredefinedExpr::LFunction || IK == PredefinedExpr::LFuncSig) { - ResTy = - Context.adjustStringLiteralBaseType(Context.WideCharTy.withConst()); - SmallString<32> RawChars; - ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), - Str, RawChars); - ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, - ArrayType::Normal, - /*IndexTypeQuals*/ 0); - SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide, - /*Pascal*/ false, ResTy, Loc); - } else { - ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); - ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, - ArrayType::Normal, - /*IndexTypeQuals*/ 0); - SL = StringLiteral::Create(Context, Str, StringLiteral::Ordinary, - /*Pascal*/ false, ResTy, Loc); + llvm::APInt LengthI(32, Str.length() + 1); + + switch (E) { + case StringLiteral::Ordinary: + ResTy = Context.CharTy; + break; + case StringLiteral::Wide: + ResTy = Context.WideCharTy; + break; + case StringLiteral::UTF8: + ResTy = Context.Char8Ty; + break; + case StringLiteral::UTF16: + ResTy = Context.Char16Ty; + break; + case StringLiteral::UTF32: + ResTy = Context.Char32Ty; + break; + default: + llvm_unreachable("unexpected PredefinedExpr encoding"); } + + ResTy = Context.adjustStringLiteralBaseType(ResTy.withConst()); + ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), + Str, RawChars); + ResTy = Context.getConstantArrayType( + ResTy, LengthI, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0); + SL = StringLiteral::Create(Context, RawChars, E, /*Pascal*/ false, ResTy, + Loc); } - return PredefinedExpr::Create(Context, Loc, ResTy, IK, LangOpts.MicrosoftExt, - SL); + return PredefinedExpr::Create(Context, Loc, ResTy, IK, E, + LangOpts.MicrosoftExt, SL); } ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, @@ -3770,7 +3816,8 @@ } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { - return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind)); + auto [ExprKind, Encoding] = getPredefinedExprKind(Kind); + return BuildPredefinedExpr(Loc, ExprKind, Encoding); } ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1772,7 +1772,8 @@ if (!E->isTypeDependent()) return E; - return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentKind()); + return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentKind(), + E->getEncoding()); } ExprResult diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2617,8 +2617,9 @@ /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildPredefinedExpr(SourceLocation Loc, - PredefinedExpr::IdentKind IK) { - return getSema().BuildPredefinedExpr(Loc, IK); + PredefinedExpr::IdentKind IK, + StringLiteral::StringKind E) { + return getSema().BuildPredefinedExpr(Loc, IK, E); } /// Build a new expression that references a declaration. @@ -10813,8 +10814,8 @@ if (!E->isTypeDependent()) return E; - return getDerived().RebuildPredefinedExpr(E->getLocation(), - E->getIdentKind()); + return getDerived().RebuildPredefinedExpr(E->getLocation(), E->getIdentKind(), + E->getEncoding()); } template diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -991,11 +991,10 @@ } void foo() { - static_assert(strings_match(__FUNCSIG__, "void __cdecl PredefinedExprs::foo(void)"), ""); - static_assert(strings_match(L__FUNCSIG__, L"void __cdecl PredefinedExprs::foo(void)"), ""); - static_assert(strings_match(L__FUNCTION__, L"foo"), ""); - static_assert(strings_match(__FUNCTION__, "foo"), ""); static_assert(strings_match(__func__, "foo"), ""); + static_assert(strings_match(__FUNCTION__, "foo"), ""); + static_assert(strings_match(__FUNCDNAME__, "_ZN15PredefinedExprs3fooEv"), ""); + static_assert(strings_match(__FUNCSIG__, "void __cdecl PredefinedExprs::foo(void)"), ""); static_assert(strings_match(__PRETTY_FUNCTION__, "void PredefinedExprs::foo()"), ""); } diff --git a/clang/test/Sema/ms_predefined_expr.cpp b/clang/test/Sema/ms_predefined_expr.cpp --- a/clang/test/Sema/ms_predefined_expr.cpp +++ b/clang/test/Sema/ms_predefined_expr.cpp @@ -1,16 +1,31 @@ -// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions +// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions -std=c++20 using size_t = __SIZE_TYPE__; // Test array initialization void array_init() { - const char a[] = __FUNCTION__; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}} - const char b[] = __FUNCDNAME__; // expected-warning{{initializing an array from a '__FUNCDNAME__' predefined identifier is a Microsoft extension}} - const char c[] = __FUNCSIG__; // expected-warning{{initializing an array from a '__FUNCSIG__' predefined identifier is a Microsoft extension}} - const char d[] = __func__; // expected-warning{{initializing an array from a '__func__' predefined identifier is a Microsoft extension}} - const char e[] = __PRETTY_FUNCTION__; // expected-warning{{initializing an array from a '__PRETTY_FUNCTION__' predefined identifier is a Microsoft extension}} - const wchar_t f[] = L__FUNCTION__; // expected-warning{{initializing an array from a 'L__FUNCTION__' predefined identifier is a Microsoft extension}} - const wchar_t g[] = L__FUNCSIG__; // expected-warning{{initializing an array from a 'L__FUNCSIG__' predefined identifier is a Microsoft extension}} + const char a_f[] = __func__; // expected-warning{{initializing an array from a '__func__' predefined identifier is a Microsoft extension}} + const char a_P[] = __PRETTY_FUNCTION__; // expected-warning{{initializing an array from a '__PRETTY_FUNCTION__' predefined identifier is a Microsoft extension}} + + const char a_F[] = __FUNCTION__; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}} + const char a_D[] = __FUNCDNAME__; // expected-warning{{initializing an array from a '__FUNCDNAME__' predefined identifier is a Microsoft extension}} + const char a_S[] = __FUNCSIG__; // expected-warning{{initializing an array from a '__FUNCSIG__' predefined identifier is a Microsoft extension}} + + const wchar_t L_F[] = L__FUNCTION__; // expected-warning{{initializing an array from a 'L__FUNCTION__' predefined identifier is a Microsoft extension}} + const wchar_t L_D[] = L__FUNCDNAME__; // expected-warning{{initializing an array from a 'L__FUNCDNAME__' predefined identifier is a Microsoft extension}} + const wchar_t L_S[] = L__FUNCSIG__; // expected-warning{{initializing an array from a 'L__FUNCSIG__' predefined identifier is a Microsoft extension}} + + const char8_t u8_F[] = u8__FUNCTION__; // expected-warning{{initializing an array from a 'u8__FUNCTION__' predefined identifier is a Microsoft extension}} + const char8_t u8_D[] = u8__FUNCDNAME__; // expected-warning{{initializing an array from a 'u8__FUNCDNAME__' predefined identifier is a Microsoft extension}} + const char8_t u8_S[] = u8__FUNCSIG__; // expected-warning{{initializing an array from a 'u8__FUNCSIG__' predefined identifier is a Microsoft extension}} + + const char16_t u_F[] = u__FUNCTION__; // expected-warning{{initializing an array from a 'u__FUNCTION__' predefined identifier is a Microsoft extension}} + const char16_t u_D[] = u__FUNCDNAME__; // expected-warning{{initializing an array from a 'u__FUNCDNAME__' predefined identifier is a Microsoft extension}} + const char16_t u_S[] = u__FUNCSIG__; // expected-warning{{initializing an array from a 'u__FUNCSIG__' predefined identifier is a Microsoft extension}} + + const char32_t U_F[] = U__FUNCTION__; // expected-warning{{initializing an array from a 'U__FUNCTION__' predefined identifier is a Microsoft extension}} + const char32_t U_D[] = U__FUNCDNAME__; // expected-warning{{initializing an array from a 'U__FUNCDNAME__' predefined identifier is a Microsoft extension}} + const char32_t U_S[] = U__FUNCSIG__; // expected-warning{{initializing an array from a 'U__FUNCSIG__' predefined identifier is a Microsoft extension}} } // Test function local identifiers outside of a function @@ -100,24 +115,31 @@ extern "C" void test_wide_concat() { // test L"" + "" - ASSERT_EQ(L"" __FUNCTION__, L__FUNCTION__); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} - ASSERT_EQ(L"" __FUNCSIG__, L__FUNCSIG__); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L"" __FUNCTION__, L__FUNCTION__); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L"" __FUNCDNAME__, L__FUNCDNAME__); // expected-warning{{expansion of predefined identifier '__FUNCDNAME__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L"" __FUNCSIG__, L__FUNCSIG__); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} // test Lx + "" - ASSERT_EQ(L__FUNCTION__, L__FUNCTION__ ""); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} - ASSERT_EQ(L__FUNCSIG__, L__FUNCSIG__ ""); // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L__FUNCTION__, L__FUNCTION__ ""); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L__FUNCDNAME__, L__FUNCDNAME__ ""); // expected-warning{{expansion of predefined identifier 'L__FUNCDNAME__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L__FUNCSIG__, L__FUNCSIG__ ""); // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} ASSERT_EQ(L"left_" L__FUNCTION__, L"left_test_wide_concat"); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L"left_" L__FUNCDNAME__, L"left_test_wide_concat"); // expected-warning{{expansion of predefined identifier 'L__FUNCDNAME__' to a string literal is a Microsoft extension}} ASSERT_EQ(L"left " L__FUNCSIG__, L"left void __cdecl test_wide_concat(void)"); // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} ASSERT_EQ(L__FUNCTION__ L"_right", L"test_wide_concat_right"); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L__FUNCDNAME__ L"_right", L"test_wide_concat_right"); // expected-warning{{expansion of predefined identifier 'L__FUNCDNAME__' to a string literal is a Microsoft extension}} ASSERT_EQ(L__FUNCSIG__ L" right", L"void __cdecl test_wide_concat(void) right"); // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} ASSERT_EQ(L"left_" L__FUNCTION__ L"_right", L"left_test_wide_concat_right"); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L"left_" L__FUNCDNAME__ L"_right", L"left_test_wide_concat_right"); // expected-warning{{expansion of predefined identifier 'L__FUNCDNAME__' to a string literal is a Microsoft extension}} ASSERT_EQ(L"left " L__FUNCSIG__ L" right", L"left void __cdecl test_wide_concat(void) right"); // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} - ASSERT_EQ(L__FUNCTION__ L"/" L__FUNCSIG__, L"test_wide_concat/void __cdecl test_wide_concat(void)"); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} \ - // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} + ASSERT_EQ(L__FUNCTION__ L"/" L__FUNCSIG__ L"/" L__FUNCDNAME__, L"test_wide_concat/void __cdecl test_wide_concat(void)/test_wide_concat"); // \ + // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} \ + // expected-warning{{expansion of predefined identifier 'L__FUNCDNAME__' to a string literal is a Microsoft extension}} \ + // expected-warning{{expansion of predefined identifier 'L__FUNCSIG__' to a string literal is a Microsoft extension}} } void test_encoding() {