RIscRIpt updated this revision to Diff 538025.
RIscRIpt added a comment.

Rebased onto main


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153914/new/

https://reviews.llvm.org/D153914

Files:
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/TokenKinds.h
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseExpr.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/Sema/ms_predefined_expr.cpp

Index: clang/test/Sema/ms_predefined_expr.cpp
===================================================================
--- clang/test/Sema/ms_predefined_expr.cpp
+++ clang/test/Sema/ms_predefined_expr.cpp
@@ -6,4 +6,47 @@
  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 concatenation
+
+void eat_const_char_p(const char*);
+void eat_const_wchar_p(const wchar_t*);
+
+void test_concat() {
+  eat_const_char_p("s" __FUNCTION__); // expected-warning{{concatenation of predefined identifier '__FUNCTION__' is a Microsoft extension}}
+  eat_const_char_p("s" __FUNCDNAME__); // expected-warning{{concatenation of predefined identifier '__FUNCDNAME__' is a Microsoft extension}}
+  eat_const_char_p("s" __FUNCSIG__); // expected-warning{{concatenation of predefined identifier '__FUNCSIG__' is a Microsoft extension}}
+
+  eat_const_char_p(__FUNCTION__ "s"); // expected-warning{{concatenation of predefined identifier '__FUNCTION__' is a Microsoft extension}}
+  eat_const_char_p(__FUNCDNAME__ "s"); // expected-warning{{concatenation of predefined identifier '__FUNCDNAME__' is a Microsoft extension}}
+  eat_const_char_p(__FUNCSIG__ "s"); // expected-warning{{concatenation of predefined identifier '__FUNCSIG__' is a Microsoft extension}}
+
+  eat_const_char_p("s" __FUNCTION__ "s"); // expected-warning{{concatenation of predefined identifier '__FUNCTION__' is a Microsoft extension}}
+  eat_const_char_p("s" __FUNCDNAME__ "s"); // expected-warning{{concatenation of predefined identifier '__FUNCDNAME__' is a Microsoft extension}}
+  eat_const_char_p("s" __FUNCSIG__ "s"); // expected-warning{{concatenation of predefined identifier '__FUNCSIG__' is a Microsoft extension}}
+}
+
+void test_wide_concat() {
+  eat_const_wchar_p(L"s" L__FUNCTION__); // expected-warning{{concatenation of predefined identifier 'L__FUNCTION__' is a Microsoft extension}}
+  eat_const_wchar_p(L"s" L__FUNCSIG__); // expected-warning{{concatenation of predefined identifier 'L__FUNCSIG__' is a Microsoft extension}}
+
+  eat_const_wchar_p(L__FUNCTION__ L"s"); // expected-warning{{concatenation of predefined identifier 'L__FUNCTION__' is a Microsoft extension}}
+  eat_const_wchar_p(L__FUNCSIG__ L"s"); // expected-warning{{concatenation of predefined identifier 'L__FUNCSIG__' is a Microsoft extension}}
+
+  eat_const_wchar_p(L"s" L__FUNCTION__ L"s"); // expected-warning{{concatenation of predefined identifier 'L__FUNCTION__' is a Microsoft extension}}
+  eat_const_wchar_p(L"s" L__FUNCSIG__ L"s"); // expected-warning{{concatenation of predefined identifier 'L__FUNCSIG__' is a Microsoft extension}}
+}
+
+const char* test_return() {
+  return __FUNCTION__ "s" __FUNCSIG__; // expected-warning{{concatenation of predefined identifier '__FUNCTION__' is a Microsoft extension}} \
+                                       // expected-warning{{concatenation of predefined identifier '__FUNCSIG__' is a Microsoft extension}}
+}
+
+void test_struct_init_fn() {
+  struct test_struct_init {
+    const char* str;
+  } struct_init = { "struct: " __FUNCSIG__ }; // expected-warning{{concatenation of predefined identifier '__FUNCSIG__' is a Microsoft extension}}
 }
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -1882,6 +1882,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;
+  }
+}
+
 /// 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,
@@ -1931,6 +1952,44 @@
 Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
   assert(!StringToks.empty() && "Must have at least one string!");
 
+  // MSVC treats some of predefined identifiers (e.g. __FUNCTION__) as
+  // expandable predefined macros defined as string literals,
+  // which may be concatenated. Expand them here (in Sema),
+  // because StringLiteralParser (in Lex) doesn't have access to AST.
+  std::vector<Token> ExpandedToks;
+  if (getLangOpts().MicrosoftExt) {
+    ExpandedToks = StringToks.vec();
+    Decl *currentDecl = getCurScopeDecl();
+    for (Token &Tok : ExpandedToks) {
+      if (!tok::isMSPredefinedMacro(Tok.getKind())) {
+        continue;
+      }
+      // Stringify predefined expression
+      Diag(Tok.getLocation(), diag::ext_concat_predef_ms) << Tok.getKind();
+      if (isa<TranslationUnitDecl>(currentDecl)) {
+        Diag(Tok.getLocation(), diag::ext_predef_outside_function);
+      }
+      SmallString<64> Str;
+      llvm::raw_svector_ostream OS(Str);
+      Token Exp;
+      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());
+      Tok = Exp;
+    }
+    StringToks = ExpandedToks;
+  }
+
   StringLiteralParser Literal(StringToks, PP);
   if (Literal.hadError)
     return ExprError();
@@ -3600,20 +3659,9 @@
 
 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();
-
-  if (!currentDecl) {
+  Decl *currentDecl = getCurScopeDecl();
+  if (isa<TranslationUnitDecl>(currentDecl)) {
     Diag(Loc, diag::ext_predef_outside_function);
-    currentDecl = Context.getTranslationUnitDecl();
   }
 
   QualType ResTy;
@@ -3675,20 +3723,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) {
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -1491,6 +1491,19 @@
   return nullptr;
 }
 
+Decl *Sema::getCurScopeDecl() {
+  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 Context.getTranslationUnitDecl();
+}
+
 LangAS Sema::getDefaultCXXMethodAddrSpace() const {
   if (getLangOpts().OpenCL)
     return getASTContext().getDefaultOpenCLPointeeAddrSpace();
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -1297,8 +1297,7 @@
   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();
+    Res = ParsePredefinedExpression(true);
     break;
   case tok::string_literal:    // primary-expression: string-literal
   case tok::wide_string_literal:
@@ -3247,6 +3246,33 @@
   return Result;
 }
 
+/// ParsePredefinedExpression
+ExprResult Parser::ParsePredefinedExpression(bool AllowUserDefinedLiteral) {
+  if (getLangOpts().MicrosoftExt && isTokenConcatenable()) {
+    SmallVector<Token, 4> ConcatToks;
+    do {
+      ConcatToks.push_back(Tok);
+      if (isTokenStringLiteral())
+        ConsumeStringToken();
+      else
+        ConsumeToken();
+    } while (isTokenConcatenable());
+
+    // Treat as string literal only if we are trying to concat multiple tokens,
+    // otherwise fallback to PredefinedExpr.
+    if (ConcatToks.size() > 1)
+      return Actions.ActOnStringLiteral(
+          ConcatToks, AllowUserDefinedLiteral ? getCurScope() : nullptr);
+    else
+      return Actions.ActOnPredefinedExpr(ConcatToks.front().getLocation(),
+                                         ConcatToks.front().getKind());
+  }
+
+  auto Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), Tok.getKind());
+  ConsumeToken();
+  return Res;
+}
+
 /// ParseStringLiteralExpression - This handles the various token types that
 /// form string literals, and also handles string concatenation [C99 5.1.1.2,
 /// translation phase #6].
@@ -3256,16 +3282,21 @@
 ///         string-literal
 /// \verbatim
 ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
-  assert(isTokenStringLiteral() && "Not a string literal!");
+  assert(isTokenConcatenable() && "Not a concatenable token!");
 
-  // String concat.  Note that keywords like __func__ and __FUNCTION__ are not
-  // considered to be strings for concatenation purposes.
+  // String concatenation.
+  // Note that keywords like __func__ and __FUNCTION__
+  // are not considered to be strings for concatenation purposes,
+  // unless Microsoft extensions are enabled.
   SmallVector<Token, 4> StringToks;
 
   do {
     StringToks.push_back(Tok);
-    ConsumeStringToken();
-  } while (isTokenStringLiteral());
+    if (isTokenStringLiteral())
+      ConsumeStringToken();
+    else
+      ConsumeToken();
+  } while (isTokenConcatenable());
 
   // Pass the set of string tokens, ready for concatenation, to the actions.
   return Actions.ActOnStringLiteral(StringToks,
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3588,6 +3588,10 @@
   /// in a 'block', this returns the containing context.
   NamedDecl *getCurFunctionOrMethodDecl() const;
 
+  /// getCurScopeDecl - Return the Decl for either of:
+  /// block, lambda, captured statement, function, or translation unit.
+  Decl *getCurScopeDecl();
+
   /// Add this decl to the scope shadowed decl chains.
   void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true);
 
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -574,6 +574,12 @@
   bool isTokenStringLiteral() const {
     return tok::isStringLiteral(Tok.getKind());
   }
+  /// isTokenConcatenable - Return true if the cur token is concatenable.
+  bool isTokenConcatenable() const {
+    return isTokenStringLiteral() ||
+           getLangOpts().MicrosoftExt &&
+               tok::isMSPredefinedMacro(Tok.getKind());
+  }
   /// isTokenSpecial - True if this token requires special consumption methods.
   bool isTokenSpecial() const {
     return isTokenStringLiteral() || isTokenParen() || isTokenBracket() ||
@@ -1787,6 +1793,7 @@
                                   unsigned &NumLineToksConsumed,
                                   bool IsUnevaluated);
 
+  ExprResult ParsePredefinedExpression(bool AllowUserDefinedLiteral = false);
   ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false);
 
 private:
Index: clang/include/clang/Basic/TokenKinds.h
===================================================================
--- clang/include/clang/Basic/TokenKinds.h
+++ clang/include/clang/Basic/TokenKinds.h
@@ -84,6 +84,13 @@
   return (K == tok::identifier) || (K == tok::raw_identifier);
 }
 
+/// Return true if this token is a predefined macro, for MSVC.
+inline bool isMSPredefinedMacro(TokenKind K) {
+  return K == tok::kw___FUNCTION__ || K == tok::kw___FUNCSIG__ ||
+         K == tok::kw_L__FUNCTION__ || K == tok::kw_L__FUNCSIG__ ||
+         K == tok::kw___FUNCDNAME__;
+}
+
 /// Return true if this is a C or C++ string-literal (or
 /// C++11 user-defined-string-literal) token.
 inline bool isStringLiteral(TokenKind K) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ 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<MicrosoftInitFromPredefined>;
+def ext_concat_predef_ms : ExtWarn<
+  "concatenation of predefined identifier '%0' is a Microsoft extension">,
+  InGroup<MicrosoftConcatPredefined>;
 def warn_float_overflow : Warning<
   "magnitude of floating-point constant too large for type %0; maximum is %1">,
    InGroup<LiteralRange>;
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -1202,6 +1202,7 @@
 def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">;
 def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">;
 def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">;
+def MicrosoftConcatPredefined : DiagGroup<"microsoft-concat-predefined">;
 
 // Aliases.
 def : DiagGroup<"msvc-include", [MicrosoftInclude]>;
@@ -1219,7 +1220,8 @@
      MicrosoftFlexibleArray, MicrosoftExtraQualification, MicrosoftCast,
      MicrosoftConstInit, MicrosoftVoidPseudoDtor, MicrosoftAnonTag,
      MicrosoftCommentPaste, MicrosoftEndOfFile, MicrosoftStaticAssert,
-     MicrosoftInitFromPredefined, MicrosoftInconsistentDllImport]>;
+     MicrosoftInitFromPredefined, MicrosoftConcatPredefined,
+     MicrosoftInconsistentDllImport]>;
 
 def ClangClPch : DiagGroup<"clang-cl-pch">;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to