diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1207,6 +1207,8 @@ def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">; def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">; def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">; +def MicrosoftStringLiteralFromPredefined : DiagGroup< + "microsoft-string-literal-from-predefined">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; @@ -1224,7 +1226,8 @@ MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast, MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag, MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftStaticAssert, - MicrosoftInitFromPredefined, MicrosoftInconsistentDllImport]>; + MicrosoftInitFromPredefined, MicrosoftStringLiteralFromPredefined, + MicrosoftInconsistentDllImport]>; def ClangClPch : DiagGroup<"clang-cl-pch">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -115,6 +115,9 @@ def ext_init_from_predefined : ExtWarn< "initializing an array from a '%0' predefined identifier is a Microsoft extension">, InGroup; +def ext_string_literal_from_predefined : ExtWarn< + "expansion of predefined identifier '%0' to a string literal is a Microsoft extension">, + InGroup; def warn_float_overflow : Warning< "magnitude of floating-point constant too large for type %0; maximum is %1">, InGroup; diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -36,6 +36,15 @@ /// Copy characters from Input to Buf, expanding any UCNs. void expandUCNs(SmallVectorImpl &Buf, StringRef Input); +/// Return true if the token corresponds to a function local predefined macro, +/// which expands to a string literal, that can be concatenated with other +/// string literals (only in Microsoft mode). +bool isFunctionLocalStringLiteralMacro(tok::TokenKind K, const LangOptions &LO); + +/// Return true if the token is a string literal, or a function local +/// predefined macro, which expands to a string literal. +bool tokenIsLikeStringLiteral(const Token &Tok, const LangOptions &LO); + /// NumericLiteralParser - This performs strict semantic analysis of the content /// of a ppnumber, classifying it as either integer, floating, or erroneous, /// determines the radix of the value and can convert it to a useful value. 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 @@ -3603,6 +3603,10 @@ /// in a 'block', this returns the containing context. NamedDecl *getCurFunctionOrMethodDecl() const; + /// getCurLocalScopeDecl - Return the Decl for either of: + /// block, lambda, captured statement, function, or nullptr. + Decl *getCurLocalScopeDecl(); + /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); @@ -5698,6 +5702,11 @@ SourceLocation LitEndLoc, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); + // ExpandFunctionLocalPredefinedMacros - Returns a new vector of Tokens, + // where Tokens representing function local predefined macros (such as + // __FUNCTION__) are replaced (expanded) with string-literal Tokens. + std::vector ExpandFunctionLocalPredefinedMacros(ArrayRef Toks); + ExprResult BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); 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 @@ -417,6 +417,19 @@ } } +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__); +} + +bool clang::tokenIsLikeStringLiteral(const Token &Tok, const LangOptions &LO) { + return tok::isStringLiteral(Tok.getKind()) || + isFunctionLocalStringLiteralMacro(Tok.getKind(), LO); +} + static bool ProcessNumericUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, const char *ThisTokEnd, uint32_t &UcnVal, diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -1016,7 +1017,7 @@ return nullptr; } - if (isTokenStringLiteral()) + if (tokenIsLikeStringLiteral(Tok, getLangOpts())) AssertMessage = ParseUnevaluatedStringLiteralExpression(); else if (getLangOpts().CPlusPlus26) AssertMessage = ParseConstantExpressionInExprEvalContext(); 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 @@ -23,6 +23,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" @@ -1297,9 +1298,17 @@ case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] - Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); - ConsumeToken(); - break; + // Function local predefined macros are represented by PredefinedExpr except + // when Microsoft extensions are enabled and one of these macros is adjacent + // to a string literal or another one of these macros. + if (!(getLangOpts().MicrosoftExt && + tokenIsLikeStringLiteral(Tok, getLangOpts()) && + tokenIsLikeStringLiteral(NextToken(), getLangOpts()))) { + Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); + ConsumeToken(); + break; + } + [[fallthrough]]; // treat MS function local macros as concatenable strings case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: case tok::utf8_string_literal: @@ -3267,16 +3276,18 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral, bool Unevaluated) { - assert(isTokenStringLiteral() && "Not a string literal!"); + assert(tokenIsLikeStringLiteral(Tok, getLangOpts()) && + "Not a string-literal-like token!"); - // String concat. Note that keywords like __func__ and __FUNCTION__ are not - // considered to be strings for concatenation purposes. + // String concatenation. + // Note: some keywords like __FUNCTION__ are not considered to be strings + // for concatenation purposes, unless Microsoft extensions are enabled. SmallVector StringToks; do { StringToks.push_back(Tok); - ConsumeStringToken(); - } while (isTokenStringLiteral()); + ConsumeAnyToken(); + } while (tokenIsLikeStringLiteral(Tok, getLangOpts())); if (Unevaluated) { assert(!AllowUserDefinedLiteral && "UDL are always evaluated"); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1491,6 +1491,19 @@ return nullptr; } +Decl *Sema::getCurLocalScopeDecl() { + if (const BlockScopeInfo *BSI = getCurBlock()) + return BSI->TheDecl; + else if (const LambdaScopeInfo *LSI = getCurLambda()) + return LSI->CallOperator; + else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion()) + return CSI->TheCapturedDecl; + else if (NamedDecl *ND = getCurFunctionOrMethodDecl()) + return ND; + else + return nullptr; +} + LangAS Sema::getDefaultCXXMethodAddrSpace() const { if (getLangOpts().OpenCL) return getASTContext().getDefaultOpenCLPointeeAddrSpace(); 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,6 +1883,27 @@ ContainsUnexpandedParameterPack, ResultIndex); } +static PredefinedExpr::IdentKind getPredefinedExprKind(tok::TokenKind Kind) { + switch (Kind) { + default: + llvm_unreachable("unexpected TokenKind"); + case tok::kw___func__: + return PredefinedExpr::Func; // [C99 6.4.2.2] + case tok::kw___FUNCTION__: + return PredefinedExpr::Function; + case tok::kw___FUNCDNAME__: + return PredefinedExpr::FuncDName; // [MS] + case tok::kw___FUNCSIG__: + return PredefinedExpr::FuncSig; // [MS] + case tok::kw_L__FUNCTION__: + return PredefinedExpr::LFunction; // [MS] + case tok::kw_L__FUNCSIG__: + return PredefinedExpr::LFuncSig; // [MS] + case tok::kw___PRETTY_FUNCTION__: + return PredefinedExpr::PrettyFunction; // [GNU] + } +} + /// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the /// location of the token and the offset of the ud-suffix within it. static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc, @@ -1923,6 +1944,10 @@ } ExprResult Sema::ActOnUnevaluatedStringLiteral(ArrayRef StringToks) { + std::vector ExpandedToks; + if (getLangOpts().MicrosoftExt) + StringToks = ExpandedToks = ExpandFunctionLocalPredefinedMacros(StringToks); + StringLiteralParser Literal(StringToks, PP, StringLiteralEvalMethod::Unevaluated); if (Literal.hadError) @@ -1946,6 +1971,56 @@ return Lit; } +std::vector +Sema::ExpandFunctionLocalPredefinedMacros(ArrayRef Toks) { + // MSVC treats some predefined identifiers (e.g. __FUNCTION__) as function + // local macros that expand to string literals that may be concatenated. + // These macros are expanded here (in Sema), because StringLiteralParser + // (in Lex) doesn't know the enclosing function (because it hasn't been + // parsed yet). + assert(getLangOpts().MicrosoftExt); + + // Note: Although function local macros are defined only inside functions, + // we ensure a valid `currentDecl` even outside of a function. This allows + // expansion of macros into empty string literals without additional checks. + Decl *currentDecl = getCurLocalScopeDecl(); + if (!currentDecl) + currentDecl = Context.getTranslationUnitDecl(); + + std::vector ExpandedToks; + ExpandedToks.reserve(Toks.size()); + for (const Token &Tok : Toks) { + if (!isFunctionLocalStringLiteralMacro(Tok.getKind(), getLangOpts())) { + assert(tok::isStringLiteral(Tok.getKind())); + ExpandedToks.emplace_back(Tok); + continue; + } + if (isa(currentDecl)) { + Diag(Tok.getLocation(), diag::ext_predef_outside_function); + } + // Stringify predefined expression + Diag(Tok.getLocation(), diag::ext_string_literal_from_predefined) + << 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__) { + OS << 'L'; + Exp.setKind(tok::wide_string_literal); + } else { + Exp.setKind(tok::string_literal); + } + OS << '"' + << Lexer::Stringify(PredefinedExpr::ComputeName( + getPredefinedExprKind(Tok.getKind()), currentDecl)) + << '"'; + PP.CreateString(OS.str(), Exp, Tok.getLocation(), Tok.getEndLoc()); + } + return ExpandedToks; +} + /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string /// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from @@ -1956,6 +2031,10 @@ Sema::ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope) { assert(!StringToks.empty() && "Must have at least one string!"); + std::vector ExpandedToks; + if (getLangOpts().MicrosoftExt) + StringToks = ExpandedToks = ExpandFunctionLocalPredefinedMacros(StringToks); + StringLiteralParser Literal(StringToks, PP); if (Literal.hadError) return ExprError(); @@ -3625,17 +3704,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK) { - // Pick the current block, lambda, captured statement or function. - Decl *currentDecl = nullptr; - if (const BlockScopeInfo *BSI = getCurBlock()) - currentDecl = BSI->TheDecl; - else if (const LambdaScopeInfo *LSI = getCurLambda()) - currentDecl = LSI->CallOperator; - else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion()) - currentDecl = CSI->TheCapturedDecl; - else - currentDecl = getCurFunctionOrMethodDecl(); - + Decl *currentDecl = getCurLocalScopeDecl(); if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); currentDecl = Context.getTranslationUnitDecl(); @@ -3700,20 +3769,7 @@ } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { - PredefinedExpr::IdentKind IK; - - switch (Kind) { - default: llvm_unreachable("Unknown simple primary expr!"); - case tok::kw___func__: IK = PredefinedExpr::Func; break; // [C99 6.4.2.2] - case tok::kw___FUNCTION__: IK = PredefinedExpr::Function; break; - case tok::kw___FUNCDNAME__: IK = PredefinedExpr::FuncDName; break; // [MS] - case tok::kw___FUNCSIG__: IK = PredefinedExpr::FuncSig; break; // [MS] - case tok::kw_L__FUNCTION__: IK = PredefinedExpr::LFunction; break; // [MS] - case tok::kw_L__FUNCSIG__: IK = PredefinedExpr::LFuncSig; break; // [MS] - case tok::kw___PRETTY_FUNCTION__: IK = PredefinedExpr::PrettyFunction; break; - } - - return BuildPredefinedExpr(Loc, IK); + return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind)); } ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { 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,9 +1,170 @@ // RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions -void f() { +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}} +} + +// Test function local identifiers outside of a function +const char* g_function = __FUNCTION__; // expected-warning{{predefined identifier is only valid inside function}} +const char* g_function_lconcat = "" __FUNCTION__; // expected-warning{{predefined identifier is only valid inside function}} \ + // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} +const char* g_function_rconcat = __FUNCTION__ ""; // expected-warning{{predefined identifier is only valid inside function}} \ + // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + +namespace NS +{ + const char* function = __FUNCTION__; // expected-warning{{predefined identifier is only valid inside function}} + const char* function_lconcat = "" __FUNCTION__; // expected-warning{{predefined identifier is only valid inside function}} \ + // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + const char* function_rconcat = __FUNCTION__ ""; // expected-warning{{predefined identifier is only valid inside function}} \ + // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + + struct S + { + static constexpr const char* function = __FUNCTION__; // expected-warning{{predefined identifier is only valid inside function}} + static constexpr const char* function_lconcat = "" __FUNCTION__; // expected-warning{{predefined identifier is only valid inside function}} \ + // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + static constexpr const char* function_rconcat = __FUNCTION__ ""; // expected-warning{{predefined identifier is only valid inside function}} \ + // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + }; +} + +template +constexpr bool is_same = false; +template +constexpr bool is_same = true; + +template +constexpr bool equal(const T (&a)[N], const T (&b)[N]) { + for (size_t i = 0; i < N; i++) + if (a[i] != b[i]) + return false; + return true; +} + +#define ASSERT_EQ(X, Y) static_assert(equal(X, Y)) +#define ASSERT_EQ_TY(X, Y) static_assert(is_same) + +#define _WIDE(s) L##s +#define WIDE(s) _WIDE(s) + +// Test value +extern "C" void test_value() { + ASSERT_EQ(__FUNCTION__, "test_value"); + ASSERT_EQ(__FUNCSIG__, "void __cdecl test_value(void)"); + + ASSERT_EQ(WIDE(__FUNCTION__), L"test_value"); + ASSERT_EQ(WIDE(__FUNCSIG__), L"void __cdecl test_value(void)"); +} + +namespace PR13206 { + template class A { + public: + void method() { + ASSERT_EQ(L__FUNCTION__, L"method"); + } + }; + + void test_template_value() { + A x; + x.method(); + } +} + +// Test concatenation +extern "C" void test_concat() { + ASSERT_EQ("left_" __FUNCTION__, "left_test_concat"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ("left_" __FUNCDNAME__, "left_test_concat"); // expected-warning{{expansion of predefined identifier '__FUNCDNAME__' to a string literal is a Microsoft extension}} + ASSERT_EQ("left " __FUNCSIG__, "left void __cdecl test_concat(void)"); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} + + ASSERT_EQ(__FUNCTION__ "_right", "test_concat_right"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(__FUNCDNAME__ "_right", "test_concat_right"); // expected-warning{{expansion of predefined identifier '__FUNCDNAME__' to a string literal is a Microsoft extension}} + ASSERT_EQ(__FUNCSIG__ " right", "void __cdecl test_concat(void) right"); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} + + ASSERT_EQ("left_" __FUNCTION__ "_right", "left_test_concat_right"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ("left_" __FUNCDNAME__ "_right", "left_test_concat_right"); // expected-warning{{expansion of predefined identifier '__FUNCDNAME__' to a string literal is a Microsoft extension}} + ASSERT_EQ("left " __FUNCSIG__ " right", "left void __cdecl test_concat(void) right"); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} + + ASSERT_EQ(__FUNCTION__ "/" __FUNCSIG__, "test_concat/void __cdecl test_concat(void)"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} \ + // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} +} + +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}} + + // 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"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__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__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__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}} +} + +void test_encoding() { + ASSERT_EQ_TY("" __FUNCTION__, ""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(L"" __FUNCTION__, L""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(L"" L__FUNCTION__, L""); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY("" L__FUNCTION__, L""); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(u8"" __FUNCTION__, u8""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(u"" __FUNCTION__, u""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(U"" __FUNCTION__, U""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + // + ASSERT_EQ_TY(__FUNCTION__ L"", L""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(__FUNCTION__ u8"", u8""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(__FUNCTION__ u"", u""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ_TY(__FUNCTION__ U"", U""); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} +} + +extern "C" void test_𐀀() { + ASSERT_EQ(U"" __FUNCTION__, U"test_𐀀"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(u"" __FUNCTION__, u"test_𐀀"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ(u8"" __FUNCTION__, u8"test_𐀀"); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} +} + +template +void unused(T); + +void test_invalid_encoding() { + unused(u8"" L__FUNCTION__); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} \ + // expected-error{{unsupported non-standard concatenation of string literals}} + unused(u"" L__FUNCTION__); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} \ + // expected-error{{unsupported non-standard concatenation of string literals}} + unused(U"" L__FUNCTION__); // expected-warning{{expansion of predefined identifier 'L__FUNCTION__' to a string literal is a Microsoft extension}} \ + // expected-error{{unsupported non-standard concatenation of string literals}} +} + +constexpr size_t operator""_len(const char*, size_t len) { + return len; +} + +void test_udliteral() { + static_assert(__FUNCTION__ ""_len == 14); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} +} + +void test_static_assert() { + static_assert(true, __FUNCTION__); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} +} + +void test_char_injection(decltype(sizeof('"')), decltype(sizeof("()"))) { + unused("" __FUNCSIG__); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} } diff --git a/clang/test/Sema/ms_wide_predefined_expr.cpp b/clang/test/Sema/ms_wide_predefined_expr.cpp deleted file mode 100644 --- a/clang/test/Sema/ms_wide_predefined_expr.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions -// expected-no-diagnostics - -// Wide character predefined identifiers -#define _STR2WSTR(str) L##str -#define STR2WSTR(str) _STR2WSTR(str) -void abcdefghi12(void) { - const wchar_t (*ss)[12] = &STR2WSTR(__FUNCTION__); - static int arr[sizeof(STR2WSTR(__FUNCTION__))==12*sizeof(wchar_t) ? 1 : -1]; - const wchar_t (*ss2)[31] = &STR2WSTR(__FUNCSIG__); - static int arr2[sizeof(STR2WSTR(__FUNCSIG__))==31*sizeof(wchar_t) ? 1 : -1]; -} - -namespace PR13206 { -void foo(const wchar_t *); - -template class A { -public: - void method() { - foo(L__FUNCTION__); - } -}; - -void bar() { - A x; - x.method(); -} -}