diff options
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 2 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 67 | ||||
-rw-r--r-- | test/FixIt/fixit-cxx0x.cpp | 12 | ||||
-rw-r--r-- | test/Parser/cxx11-user-defined-literals.cpp | 18 |
4 files changed, 88 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index fa54990c16..c5cab868c7 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index c735c6f2b3..847b3964fb 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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; + + 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()); } - if (Tok.getLength() != 2) - Diag(Tok.getLocation(), diag::err_literal_operator_string_not_empty); - ConsumeStringToken(); - if (Tok.isNot(tok::identifier)) { + 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; } diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index 2bf9b20326..dcd9f74a10 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -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; +} diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp index b34680d080..7a4df2b459 100644 --- a/test/Parser/cxx11-user-defined-literals.cpp +++ b/test/Parser/cxx11-user-defined-literals.cpp @@ -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 '""'}} |