Fix a couple of issues with literal-operator-id parsing, and provide recovery
for a few kinds of error. Specifically: Since we're after translation phase 6, the "" token might be formed by multiple source-level string literals. Checking the token width is not a correct way of detecting empty string literals, due to escaped newlines. Diagnose and recover from a missing space between "" and suffix, and from string literals other than "", which are followed by a suffix. llvm-svn: 152348
This commit is contained in:
parent
f7fc1d4859
commit
7d182a7909
|
@ -429,6 +429,8 @@ def err_parser_impl_limit_overflow : Error<
|
|||
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
|
||||
|
||||
// C++ operator overloading
|
||||
def err_literal_operator_string_prefix : Error<
|
||||
"string literal after 'operator' cannot have an encoding prefix">;
|
||||
def err_literal_operator_string_not_empty : Error<
|
||||
"string literal after 'operator' must be '\"\"'">;
|
||||
def err_literal_operator_missing_space : Error<
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "clang/Parse/Parser.h"
|
||||
#include "RAIIObjectsForParser.h"
|
||||
#include "clang/Basic/PrettyStackTrace.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ParsedTemplate.h"
|
||||
|
@ -1903,24 +1904,68 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
|||
// literal-operator-id: [C++0x 13.5.8]
|
||||
// operator "" identifier
|
||||
|
||||
if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) {
|
||||
if (getLang().CPlusPlus0x && isTokenStringLiteral()) {
|
||||
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
|
||||
// FIXME: Add a FixIt to insert a space before the suffix, and recover.
|
||||
if (Tok.hasUDSuffix()) {
|
||||
Diag(Tok.getLocation(), diag::err_literal_operator_missing_space);
|
||||
return true;
|
||||
}
|
||||
if (Tok.getLength() != 2)
|
||||
Diag(Tok.getLocation(), diag::err_literal_operator_string_not_empty);
|
||||
ConsumeStringToken();
|
||||
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
SourceLocation DiagLoc;
|
||||
unsigned DiagId = 0;
|
||||
|
||||
// We're past translation phase 6, so perform string literal concatenation
|
||||
// before checking for "".
|
||||
llvm::SmallVector<Token, 4> Toks;
|
||||
llvm::SmallVector<SourceLocation, 4> TokLocs;
|
||||
while (isTokenStringLiteral()) {
|
||||
if (!Tok.is(tok::string_literal) && !DiagId) {
|
||||
DiagLoc = Tok.getLocation();
|
||||
DiagId = diag::err_literal_operator_string_prefix;
|
||||
}
|
||||
Toks.push_back(Tok);
|
||||
TokLocs.push_back(ConsumeStringToken());
|
||||
}
|
||||
|
||||
StringLiteralParser Literal(Toks.data(), Toks.size(), PP);
|
||||
if (Literal.hadError)
|
||||
return true;
|
||||
|
||||
// Grab the literal operator's suffix, which will be either the next token
|
||||
// or a ud-suffix from the string literal.
|
||||
IdentifierInfo *II = 0;
|
||||
SourceLocation SuffixLoc;
|
||||
if (!Literal.getUDSuffix().empty()) {
|
||||
II = &PP.getIdentifierTable().get(Literal.getUDSuffix());
|
||||
SuffixLoc =
|
||||
Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
|
||||
Literal.getUDSuffixOffset(),
|
||||
PP.getSourceManager(), getLang());
|
||||
// This form is not permitted by the standard (yet).
|
||||
DiagLoc = SuffixLoc;
|
||||
DiagId = diag::err_literal_operator_missing_space;
|
||||
} else if (Tok.is(tok::identifier)) {
|
||||
II = Tok.getIdentifierInfo();
|
||||
SuffixLoc = ConsumeToken();
|
||||
TokLocs.push_back(SuffixLoc);
|
||||
} else {
|
||||
Diag(Tok.getLocation(), diag::err_expected_ident);
|
||||
return true;
|
||||
}
|
||||
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken());
|
||||
// The string literal must be empty.
|
||||
if (!Literal.GetString().empty() || Literal.Pascal) {
|
||||
DiagLoc = TokLocs.front();
|
||||
DiagId = diag::err_literal_operator_string_not_empty;
|
||||
}
|
||||
|
||||
if (DiagId) {
|
||||
// This isn't a valid literal-operator-id, but we think we know
|
||||
// what the user meant. Tell them what they should have written.
|
||||
llvm::SmallString<32> Str;
|
||||
Str += "\"\" ";
|
||||
Str += II->getName();
|
||||
Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement(
|
||||
SourceRange(TokLocs.front(), TokLocs.back()), Str);
|
||||
}
|
||||
|
||||
Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,3 +65,15 @@ void S2::f(int i) {
|
|||
const char *p = "foo"bar; // expected-error {{requires a space between}}
|
||||
#define ord - '0'
|
||||
int k = '4'ord; // expected-error {{requires a space between}}
|
||||
|
||||
void operator""_x(char); // expected-error {{requires a space}}
|
||||
void operator"x" _y(char); // expected-error {{must be '""'}}
|
||||
void operator L"" _z(char); // expected-error {{encoding prefix}}
|
||||
void operator "x" "y" U"z" ""_whoops "z" "y"(char); // expected-error {{must be '""'}}
|
||||
|
||||
void f() {
|
||||
'a'_x;
|
||||
'b'_y;
|
||||
'c'_z;
|
||||
'd'_whoops;
|
||||
}
|
||||
|
|
|
@ -92,3 +92,21 @@ _no_such_suffix; // expected-error {{'_no_such_suffix'}}
|
|||
int k =
|
||||
1234567.89\
|
||||
_no_such_suffix; // expected-error {{'_no_such_suffix'}}
|
||||
|
||||
// Make sure we handle more interesting ways of writing a string literal which
|
||||
// is "" in translation phase 7.
|
||||
void operator "\
|
||||
" _foo(unsigned long long); // ok
|
||||
|
||||
void operator R"xyzzy()xyzzy" _foo(long double); // ok
|
||||
|
||||
void operator"" "" R"()" "" _foo(const char *); // ok
|
||||
|
||||
// Ensure we diagnose the bad cases.
|
||||
void operator "\0" _non_empty(const char *); // expected-error {{must be '""'}}
|
||||
void operator ""_no_space(const char *); // expected-error {{C++11 requires a space}}
|
||||
void operator L"" _not_char(const char *); // expected-error {{cannot have an encoding prefix}}
|
||||
void operator "" ""
|
||||
U"" // expected-error {{cannot have an encoding prefix}}
|
||||
"" _also_not_char(const char *);
|
||||
void operator "" u8"" "\u0123" "hello"_all_of_the_things ""(const char*); // expected-error {{must be '""'}}
|
||||
|
|
Loading…
Reference in New Issue