Commit 49e0495f authored by Corentin Jabot's avatar Corentin Jabot
Browse files

[Clang] Produce a warning instead of an error in unevaluated strings before C++26

Emiting an error on unexpected encoding prefix - which was allowed before C++26 -
caused build errors for a few users.
This downgrade the error to a warning on older language modes and C.

Reviewed By: aaron.ballman, hubert.reinterpretcast

Differential Revision: https://reviews.llvm.org/D156596
parent b720dcba
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -285,6 +285,10 @@ def ext_ms_reserved_user_defined_literal : ExtWarn<
def err_unsupported_string_concat : Error<
  "unsupported non-standard concatenation of string literals">;

def warn_unevaluated_string_prefix : Warning<
  "encoding prefix '%0' on an unevaluated string literal has no effect"
  "%select{| and is incompatible with c++2c}1">,
  InGroup<DiagGroup<"invalid-unevaluated-string">>;
def err_unevaluated_string_prefix : Error<
  "an unevaluated string literal cannot have an encoding prefix">;
def err_unevaluated_string_udl : Error<
+38 −3
Original line number Diff line number Diff line
@@ -57,6 +57,26 @@ static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
  }
}

static unsigned getEncodingPrefixLen(tok::TokenKind kind) {
  switch (kind) {
  default:
    llvm_unreachable("Unknown token type!");
  case tok::char_constant:
  case tok::string_literal:
    return 0;
  case tok::utf8_char_constant:
  case tok::utf8_string_literal:
    return 2;
  case tok::wide_char_constant:
  case tok::wide_string_literal:
  case tok::utf16_char_constant:
  case tok::utf16_string_literal:
  case tok::utf32_char_constant:
  case tok::utf32_string_literal:
    return 1;
  }
}

static CharSourceRange MakeCharSourceRange(const LangOptions &Features,
                                           FullSourceLoc TokLoc,
                                           const char *TokBegin,
@@ -343,7 +363,9 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
    Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
         diag::err_unevaluated_string_invalid_escape_sequence)
        << StringRef(EscapeBegin, ThisTokBuf - EscapeBegin);
    HadError = true;
  }

  return ResultChar;
}

@@ -1930,8 +1952,21 @@ void StringLiteralParser::init(ArrayRef<Token> StringToks){
    // Remember if we see any wide or utf-8/16/32 strings.
    // Also check for illegal concatenations.
    if (isUnevaluated() && Tok.getKind() != tok::string_literal) {
      if (Diags)
        Diags->Report(Tok.getLocation(), diag::err_unevaluated_string_prefix);
      if (Diags) {
        SourceLocation PrefixEndLoc = Lexer::AdvanceToTokenCharacter(
            Tok.getLocation(), getEncodingPrefixLen(Tok.getKind()), SM,
            Features);
        CharSourceRange Range =
            CharSourceRange::getCharRange({Tok.getLocation(), PrefixEndLoc});
        StringRef Prefix(SM.getCharacterData(Tok.getLocation()),
                         getEncodingPrefixLen(Tok.getKind()));
        Diags->Report(Tok.getLocation(),
                      Features.CPlusPlus26
                          ? diag::err_unevaluated_string_prefix
                          : diag::warn_unevaluated_string_prefix)
            << Prefix << Features.CPlusPlus << FixItHint::CreateRemoval(Range);
      }
      if (Features.CPlusPlus26)
        hadError = true;
    } else if (Tok.isNot(Kind) && Tok.isNot(tok::string_literal)) {
      if (isOrdinary()) {
+1 −1
Original line number Diff line number Diff line
@@ -1023,7 +1023,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
        const Token &T = GetLookAheadToken(I);
        if (T.is(tok::r_paren))
          break;
        if (T.isNot(tok::string_literal)) {
        if (!tokenIsLikeStringLiteral(T, getLangOpts())) {
          ParseAsExpression = true;
          break;
        }
+4 −4
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ extern "C" {
extern "C" plusplus {
}

extern u8"C" {}  // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
extern L"C" {}   // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
extern u"C++" {} // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
extern U"C" {}   // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
extern u8"C" {}  // expected-warning {{encoding prefix 'u8' on an unevaluated string literal has no effect and is incompatible with c++2c}}
extern L"C" {}   // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}}
extern u"C++" {} // expected-warning {{encoding prefix 'u' on an unevaluated string literal has no effect and is incompatible with c++2c}}
extern U"C" {}   // expected-warning {{encoding prefix 'U' on an unevaluated string literal has no effect and is incompatible with c++2c}}
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ static_assert(S(false), "not so fast"); // expected-error {{not so fast}}
static_assert(T(), "");
static_assert(U(), ""); // expected-error {{ambiguous}}

static_assert(false, L"\x14hi" // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
static_assert(false, L"\x14hi" // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
                               // expected-error {{invalid escape sequence '\x14' in an unevaluated string literal}}
                     "!"
                     R"x(")x");
Loading