forked from OSchip/llvm-project
User-defined literals: reject string and character UDLs in all places where the
grammar requires a string-literal and not a user-defined-string-literal. The two constructs are still represented by the same TokenKind, in order to prevent a combinatorial explosion of different kinds of token. A flag on Token tracks whether a ud-suffix is present, in order to prevent clients from needing to look at the token's spelling. llvm-svn: 152098
This commit is contained in:
parent
8de0744441
commit
d67aea28f6
|
@ -41,6 +41,8 @@ def err_expected_colon : Error<"expected ':'">;
|
||||||
def err_expected_colon_after_setter_name : Error<
|
def err_expected_colon_after_setter_name : Error<
|
||||||
"method name referenced in property setter attribute "
|
"method name referenced in property setter attribute "
|
||||||
"must end with ':'">;
|
"must end with ':'">;
|
||||||
|
def err_invalid_string_udl : Error<
|
||||||
|
"string literal with user-defined suffix cannot be used here">;
|
||||||
|
|
||||||
// Parse && Sema
|
// Parse && Sema
|
||||||
def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
|
def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
|
||||||
|
|
|
@ -136,6 +136,9 @@ def err_unsupported_string_concat : Error<
|
||||||
def err_string_concat_mixed_suffix : Error<
|
def err_string_concat_mixed_suffix : Error<
|
||||||
"differing user-defined suffixes ('%0' and '%1') in string literal "
|
"differing user-defined suffixes ('%0' and '%1') in string literal "
|
||||||
"concatenation">;
|
"concatenation">;
|
||||||
|
def err_pp_invalid_char_udl : Error<
|
||||||
|
"character literal with user-defined suffix cannot be used in preprocessor "
|
||||||
|
"constant expression">;
|
||||||
def err_bad_string_encoding : Error<
|
def err_bad_string_encoding : Error<
|
||||||
"illegal character encoding in string literal">;
|
"illegal character encoding in string literal">;
|
||||||
def warn_bad_string_encoding : ExtWarn<
|
def warn_bad_string_encoding : ExtWarn<
|
||||||
|
|
|
@ -200,7 +200,7 @@ def err_address_of_label_outside_fn : Error<
|
||||||
"use of address-of-label extension outside of a function body">;
|
"use of address-of-label extension outside of a function body">;
|
||||||
def err_expected_string_literal : Error<"expected string literal">;
|
def err_expected_string_literal : Error<"expected string literal">;
|
||||||
def err_asm_operand_wide_string_literal : Error<
|
def err_asm_operand_wide_string_literal : Error<
|
||||||
"cannot use wide string literal in 'asm'">;
|
"cannot use %select{unicode|wide}0 string literal in 'asm'">;
|
||||||
def err_expected_selector_for_method : Error<
|
def err_expected_selector_for_method : Error<
|
||||||
"expected selector for Objective-C method">;
|
"expected selector for Objective-C method">;
|
||||||
def err_expected_property_name : Error<"expected property name">;
|
def err_expected_property_name : Error<"expected property name">;
|
||||||
|
@ -425,8 +425,11 @@ def err_parser_impl_limit_overflow : Error<
|
||||||
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
|
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
|
||||||
|
|
||||||
// C++ operator overloading
|
// C++ operator overloading
|
||||||
def err_operator_string_not_empty : Error<
|
def err_literal_operator_string_not_empty : Error<
|
||||||
"string literal after 'operator' must be '\"\"'">;
|
"string literal after 'operator' must be '\"\"'">;
|
||||||
|
def err_literal_operator_missing_space : Error<
|
||||||
|
"C++11 requires a space between the \"\" and the user-defined suffix in a "
|
||||||
|
"literal operator">;
|
||||||
def warn_cxx98_compat_literal_operator : Warning<
|
def warn_cxx98_compat_literal_operator : Warning<
|
||||||
"literal operators are incompatible with C++98">,
|
"literal operators are incompatible with C++98">,
|
||||||
InGroup<CXX98Compat>, DefaultIgnore;
|
InGroup<CXX98Compat>, DefaultIgnore;
|
||||||
|
|
|
@ -75,7 +75,8 @@ public:
|
||||||
LeadingSpace = 0x02, // Whitespace exists before this token.
|
LeadingSpace = 0x02, // Whitespace exists before this token.
|
||||||
DisableExpand = 0x04, // This identifier may never be macro expanded.
|
DisableExpand = 0x04, // This identifier may never be macro expanded.
|
||||||
NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
|
NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
|
||||||
LeadingEmptyMacro = 0x10 // Empty macro exists before this token.
|
LeadingEmptyMacro = 0x10, // Empty macro exists before this token.
|
||||||
|
HasUDSuffix = 0x20 // This string or character literal has a ud-suffix.
|
||||||
};
|
};
|
||||||
|
|
||||||
tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
|
tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
|
||||||
|
@ -263,6 +264,9 @@ public:
|
||||||
return (Flags & LeadingEmptyMacro) ? true : false;
|
return (Flags & LeadingEmptyMacro) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return true if this token is a string or character literal which
|
||||||
|
/// has a ud-suffix.
|
||||||
|
bool hasUDSuffix() const { return (Flags & HasUDSuffix) ? true : false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// PPConditionalInfo - Information about the conditional stack (#if directives)
|
/// PPConditionalInfo - Information about the conditional stack (#if directives)
|
||||||
|
|
|
@ -1359,7 +1359,7 @@ private:
|
||||||
SourceLocation LParenLoc,
|
SourceLocation LParenLoc,
|
||||||
SourceLocation RParenLoc);
|
SourceLocation RParenLoc);
|
||||||
|
|
||||||
ExprResult ParseStringLiteralExpression();
|
ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false);
|
||||||
|
|
||||||
ExprResult ParseGenericSelectionExpression();
|
ExprResult ParseGenericSelectionExpression();
|
||||||
|
|
||||||
|
|
|
@ -1582,6 +1582,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
|
||||||
unsigned Size;
|
unsigned Size;
|
||||||
char C = getCharAndSize(CurPtr, Size);
|
char C = getCharAndSize(CurPtr, Size);
|
||||||
if (isIdentifierHead(C)) {
|
if (isIdentifierHead(C)) {
|
||||||
|
Result.setFlag(Token::HasUDSuffix);
|
||||||
do {
|
do {
|
||||||
CurPtr = ConsumeChar(CurPtr, Size, Result);
|
CurPtr = ConsumeChar(CurPtr, Size, Result);
|
||||||
C = getCharAndSize(CurPtr, Size);
|
C = getCharAndSize(CurPtr, Size);
|
||||||
|
|
|
@ -617,6 +617,12 @@ retry:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tok::string_literal: {
|
case tok::string_literal: {
|
||||||
|
if (LToken.hasUDSuffix()) {
|
||||||
|
Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
|
||||||
|
HadError = true;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the string literal.
|
// Parse the string literal.
|
||||||
LangOptions LangOpts;
|
LangOptions LangOpts;
|
||||||
StringLiteralParser StringLiteral(<oken, 1, SourceMgr, LangOpts, *Target);
|
StringLiteralParser StringLiteral(<oken, 1, SourceMgr, LangOpts, *Target);
|
||||||
|
|
|
@ -822,8 +822,10 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
|
||||||
; // ok
|
; // ok
|
||||||
else if (StrTok.isNot(tok::string_literal)) {
|
else if (StrTok.isNot(tok::string_literal)) {
|
||||||
Diag(StrTok, diag::err_pp_line_invalid_filename);
|
Diag(StrTok, diag::err_pp_line_invalid_filename);
|
||||||
DiscardUntilEndOfDirective();
|
return DiscardUntilEndOfDirective();
|
||||||
return;
|
} else if (StrTok.hasUDSuffix()) {
|
||||||
|
Diag(StrTok, diag::err_invalid_string_udl);
|
||||||
|
return DiscardUntilEndOfDirective();
|
||||||
} else {
|
} else {
|
||||||
// Parse and validate the string, converting it into a unique ID.
|
// Parse and validate the string, converting it into a unique ID.
|
||||||
StringLiteralParser Literal(&StrTok, 1, *this);
|
StringLiteralParser Literal(&StrTok, 1, *this);
|
||||||
|
@ -957,6 +959,9 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
||||||
else if (StrTok.isNot(tok::string_literal)) {
|
else if (StrTok.isNot(tok::string_literal)) {
|
||||||
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
|
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
|
||||||
return DiscardUntilEndOfDirective();
|
return DiscardUntilEndOfDirective();
|
||||||
|
} else if (StrTok.hasUDSuffix()) {
|
||||||
|
Diag(StrTok, diag::err_invalid_string_udl);
|
||||||
|
return DiscardUntilEndOfDirective();
|
||||||
} else {
|
} else {
|
||||||
// Parse and validate the string, converting it into a unique ID.
|
// Parse and validate the string, converting it into a unique ID.
|
||||||
StringLiteralParser Literal(&StrTok, 1, *this);
|
StringLiteralParser Literal(&StrTok, 1, *this);
|
||||||
|
@ -1047,6 +1052,11 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StrTok.hasUDSuffix()) {
|
||||||
|
Diag(StrTok, diag::err_invalid_string_udl);
|
||||||
|
return DiscardUntilEndOfDirective();
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that there is nothing after the string, other than EOD.
|
// Verify that there is nothing after the string, other than EOD.
|
||||||
CheckEndOfDirective("ident");
|
CheckEndOfDirective("ident");
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
|
||||||
case tok::wide_char_constant: { // L'x'
|
case tok::wide_char_constant: { // L'x'
|
||||||
case tok::utf16_char_constant: // u'x'
|
case tok::utf16_char_constant: // u'x'
|
||||||
case tok::utf32_char_constant: // U'x'
|
case tok::utf32_char_constant: // U'x'
|
||||||
|
// Complain about, and drop, any ud-suffix.
|
||||||
|
if (PeekTok.hasUDSuffix())
|
||||||
|
PP.Diag(PeekTok, diag::err_pp_invalid_char_udl);
|
||||||
|
|
||||||
SmallString<32> CharBuffer;
|
SmallString<32> CharBuffer;
|
||||||
bool CharInvalid = false;
|
bool CharInvalid = false;
|
||||||
StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
|
StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
|
||||||
|
|
|
@ -825,6 +825,16 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get ')'.
|
||||||
|
PP.LexNonComment(Tok);
|
||||||
|
|
||||||
|
// Ensure we have a trailing ).
|
||||||
|
if (Tok.isNot(tok::r_paren)) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
|
||||||
|
PP.Diag(LParenLoc, diag::note_matching) << "(";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
|
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
|
||||||
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
|
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
|
||||||
// error.
|
// error.
|
||||||
|
@ -836,20 +846,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
|
||||||
const FileEntry *File =
|
const FileEntry *File =
|
||||||
PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL);
|
PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL);
|
||||||
|
|
||||||
// Get the result value. Result = true means the file exists.
|
// Get the result value. A result of true means the file exists.
|
||||||
bool Result = File != 0;
|
return File != 0;
|
||||||
|
|
||||||
// Get ')'.
|
|
||||||
PP.LexNonComment(Tok);
|
|
||||||
|
|
||||||
// Ensure we have a trailing ).
|
|
||||||
if (Tok.isNot(tok::r_paren)) {
|
|
||||||
PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
|
|
||||||
PP.Diag(LParenLoc, diag::note_matching) << "(";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EvaluateHasInclude - Process a '__has_include("path")' expression.
|
/// EvaluateHasInclude - Process a '__has_include("path")' expression.
|
||||||
|
@ -1091,6 +1089,9 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
|
||||||
// from macro expansion.
|
// from macro expansion.
|
||||||
SmallVector<Token, 4> StrToks;
|
SmallVector<Token, 4> StrToks;
|
||||||
while (Tok.is(tok::string_literal)) {
|
while (Tok.is(tok::string_literal)) {
|
||||||
|
// Complain about, and drop, any ud-suffix.
|
||||||
|
if (Tok.hasUDSuffix())
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
StrToks.push_back(Tok);
|
StrToks.push_back(Tok);
|
||||||
LexUnexpandedToken(Tok);
|
LexUnexpandedToken(Tok);
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,20 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
|
||||||
Lex(Tok);
|
Lex(Tok);
|
||||||
if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
|
if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
|
||||||
Diag(PragmaLoc, diag::err__Pragma_malformed);
|
Diag(PragmaLoc, diag::err__Pragma_malformed);
|
||||||
|
// Skip this token, and the ')', if present.
|
||||||
|
if (Tok.isNot(tok::r_paren))
|
||||||
|
Lex(Tok);
|
||||||
|
if (Tok.is(tok::r_paren))
|
||||||
|
Lex(Tok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tok.hasUDSuffix()) {
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
|
// Skip this token, and the ')', if present.
|
||||||
|
Lex(Tok);
|
||||||
|
if (Tok.is(tok::r_paren))
|
||||||
|
Lex(Tok);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,6 +456,8 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
|
||||||
// "foo " "bar" "Baz"
|
// "foo " "bar" "Baz"
|
||||||
SmallVector<Token, 4> StrToks;
|
SmallVector<Token, 4> StrToks;
|
||||||
while (Tok.is(tok::string_literal)) {
|
while (Tok.is(tok::string_literal)) {
|
||||||
|
if (Tok.hasUDSuffix())
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
StrToks.push_back(Tok);
|
StrToks.push_back(Tok);
|
||||||
Lex(Tok);
|
Lex(Tok);
|
||||||
}
|
}
|
||||||
|
@ -518,6 +534,8 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
|
||||||
// "foo " "bar" "Baz"
|
// "foo " "bar" "Baz"
|
||||||
SmallVector<Token, 4> StrToks;
|
SmallVector<Token, 4> StrToks;
|
||||||
while (Tok.is(tok::string_literal)) {
|
while (Tok.is(tok::string_literal)) {
|
||||||
|
if (Tok.hasUDSuffix())
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
StrToks.push_back(Tok);
|
StrToks.push_back(Tok);
|
||||||
Lex(Tok);
|
Lex(Tok);
|
||||||
}
|
}
|
||||||
|
@ -577,6 +595,11 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Tok.hasUDSuffix()) {
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Remember the macro string.
|
// Remember the macro string.
|
||||||
std::string StrVal = getSpelling(Tok);
|
std::string StrVal = getSpelling(Tok);
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,19 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
|
||||||
TokenInfo[tok::hash ] |= aci_custom_firstchar;
|
TokenInfo[tok::hash ] |= aci_custom_firstchar;
|
||||||
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
|
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
|
||||||
|
|
||||||
|
// These tokens have custom code in C++11 mode.
|
||||||
|
if (PP.getLangOptions().CPlusPlus0x) {
|
||||||
|
TokenInfo[tok::string_literal ] |= aci_custom;
|
||||||
|
TokenInfo[tok::wide_string_literal ] |= aci_custom;
|
||||||
|
TokenInfo[tok::utf8_string_literal ] |= aci_custom;
|
||||||
|
TokenInfo[tok::utf16_string_literal] |= aci_custom;
|
||||||
|
TokenInfo[tok::utf32_string_literal] |= aci_custom;
|
||||||
|
TokenInfo[tok::char_constant ] |= aci_custom;
|
||||||
|
TokenInfo[tok::wide_char_constant ] |= aci_custom;
|
||||||
|
TokenInfo[tok::utf16_char_constant ] |= aci_custom;
|
||||||
|
TokenInfo[tok::utf32_char_constant ] |= aci_custom;
|
||||||
|
}
|
||||||
|
|
||||||
// These tokens change behavior if followed by an '='.
|
// These tokens change behavior if followed by an '='.
|
||||||
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
|
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
|
||||||
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
|
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
|
||||||
|
@ -183,6 +196,28 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
|
||||||
case tok::raw_identifier:
|
case tok::raw_identifier:
|
||||||
llvm_unreachable("tok::raw_identifier in non-raw lexing mode!");
|
llvm_unreachable("tok::raw_identifier in non-raw lexing mode!");
|
||||||
|
|
||||||
|
case tok::string_literal:
|
||||||
|
case tok::wide_string_literal:
|
||||||
|
case tok::utf8_string_literal:
|
||||||
|
case tok::utf16_string_literal:
|
||||||
|
case tok::utf32_string_literal:
|
||||||
|
case tok::char_constant:
|
||||||
|
case tok::wide_char_constant:
|
||||||
|
case tok::utf16_char_constant:
|
||||||
|
case tok::utf32_char_constant:
|
||||||
|
if (!PP.getLangOptions().CPlusPlus0x)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// In C++11, a string or character literal followed by an identifier is a
|
||||||
|
// single token.
|
||||||
|
if (Tok.getIdentifierInfo())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// A ud-suffix is an identifier. If the previous token ends with one, treat
|
||||||
|
// it as an identifier.
|
||||||
|
if (!PrevTok.hasUDSuffix())
|
||||||
|
return false;
|
||||||
|
// FALL THROUGH.
|
||||||
case tok::identifier: // id+id or id+number or id+L"foo".
|
case tok::identifier: // id+id or id+number or id+L"foo".
|
||||||
// id+'.'... will not append.
|
// id+'.'... will not append.
|
||||||
if (Tok.is(tok::numeric_constant))
|
if (Tok.is(tok::numeric_constant))
|
||||||
|
@ -201,9 +236,11 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
|
||||||
// Otherwise, this is a narrow character or string. If the *identifier*
|
// Otherwise, this is a narrow character or string. If the *identifier*
|
||||||
// is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo".
|
// is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo".
|
||||||
return IsIdentifierStringPrefix(PrevTok);
|
return IsIdentifierStringPrefix(PrevTok);
|
||||||
|
|
||||||
case tok::numeric_constant:
|
case tok::numeric_constant:
|
||||||
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
|
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
|
||||||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
|
FirstChar == '+' || FirstChar == '-' || FirstChar == '.' ||
|
||||||
|
(PP.getLangOptions().CPlusPlus0x && FirstChar == '_');
|
||||||
case tok::period: // ..., .*, .1234
|
case tok::period: // ..., .*, .1234
|
||||||
return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
|
return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
|
||||||
isdigit(FirstChar) ||
|
isdigit(FirstChar) ||
|
||||||
|
|
|
@ -272,6 +272,11 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
|
||||||
if (Invalid)
|
if (Invalid)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// FIXME: This is incorrect: linkage-specifiers are parsed in translation
|
||||||
|
// phase 7, so string-literal concatenation is supposed to occur.
|
||||||
|
// extern "" "C" "" "+" "+" { } is legal.
|
||||||
|
if (Tok.hasUDSuffix())
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
SourceLocation Loc = ConsumeStringToken();
|
SourceLocation Loc = ConsumeStringToken();
|
||||||
|
|
||||||
ParseScope LinkageScope(this, Scope::DeclScope);
|
ParseScope LinkageScope(this, Scope::DeclScope);
|
||||||
|
@ -617,8 +622,10 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult AssertMessage(ParseStringLiteralExpression());
|
ExprResult AssertMessage(ParseStringLiteralExpression());
|
||||||
if (AssertMessage.isInvalid())
|
if (AssertMessage.isInvalid()) {
|
||||||
|
SkipUntil(tok::semi);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
T.consumeClose();
|
T.consumeClose();
|
||||||
|
|
||||||
|
|
|
@ -497,14 +497,14 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
|
||||||
/// unary-operator cast-expression
|
/// unary-operator cast-expression
|
||||||
/// 'sizeof' unary-expression
|
/// 'sizeof' unary-expression
|
||||||
/// 'sizeof' '(' type-name ')'
|
/// 'sizeof' '(' type-name ')'
|
||||||
/// [C++0x] 'sizeof' '...' '(' identifier ')'
|
/// [C++11] 'sizeof' '...' '(' identifier ')'
|
||||||
/// [GNU] '__alignof' unary-expression
|
/// [GNU] '__alignof' unary-expression
|
||||||
/// [GNU] '__alignof' '(' type-name ')'
|
/// [GNU] '__alignof' '(' type-name ')'
|
||||||
/// [C++0x] 'alignof' '(' type-id ')'
|
/// [C++11] 'alignof' '(' type-id ')'
|
||||||
/// [GNU] '&&' identifier
|
/// [GNU] '&&' identifier
|
||||||
|
/// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7]
|
||||||
/// [C++] new-expression
|
/// [C++] new-expression
|
||||||
/// [C++] delete-expression
|
/// [C++] delete-expression
|
||||||
/// [C++0x] 'noexcept' '(' expression ')'
|
|
||||||
///
|
///
|
||||||
/// unary-operator: one of
|
/// unary-operator: one of
|
||||||
/// '&' '*' '+' '-' '~' '!'
|
/// '&' '*' '+' '-' '~' '!'
|
||||||
|
@ -516,7 +516,8 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
|
||||||
/// constant
|
/// constant
|
||||||
/// string-literal
|
/// string-literal
|
||||||
/// [C++] boolean-literal [C++ 2.13.5]
|
/// [C++] boolean-literal [C++ 2.13.5]
|
||||||
/// [C++0x] 'nullptr' [C++0x 2.14.7]
|
/// [C++11] 'nullptr' [C++11 2.14.7]
|
||||||
|
/// [C++11] user-defined-literal
|
||||||
/// '(' expression ')'
|
/// '(' expression ')'
|
||||||
/// [C11] generic-selection
|
/// [C11] generic-selection
|
||||||
/// '__func__' [C99 6.4.2.2]
|
/// '__func__' [C99 6.4.2.2]
|
||||||
|
@ -535,9 +536,9 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
|
||||||
/// [OBJC] '@encode' '(' type-name ')'
|
/// [OBJC] '@encode' '(' type-name ')'
|
||||||
/// [OBJC] objc-string-literal
|
/// [OBJC] objc-string-literal
|
||||||
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
|
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
|
||||||
/// [C++0x] simple-type-specifier braced-init-list [C++ 5.2.3]
|
/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3]
|
||||||
/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
|
/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
|
||||||
/// [C++0x] typename-specifier braced-init-list [C++ 5.2.3]
|
/// [C++11] typename-specifier braced-init-list [C++11 5.2.3]
|
||||||
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||||
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||||
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
||||||
|
@ -850,7 +851,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
case tok::utf8_string_literal:
|
case tok::utf8_string_literal:
|
||||||
case tok::utf16_string_literal:
|
case tok::utf16_string_literal:
|
||||||
case tok::utf32_string_literal:
|
case tok::utf32_string_literal:
|
||||||
Res = ParseStringLiteralExpression();
|
Res = ParseStringLiteralExpression(true);
|
||||||
break;
|
break;
|
||||||
case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1]
|
case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1]
|
||||||
Res = ParseGenericSelectionExpression();
|
Res = ParseGenericSelectionExpression();
|
||||||
|
@ -2102,7 +2103,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty,
|
||||||
///
|
///
|
||||||
/// primary-expression: [C99 6.5.1]
|
/// primary-expression: [C99 6.5.1]
|
||||||
/// string-literal
|
/// string-literal
|
||||||
ExprResult Parser::ParseStringLiteralExpression() {
|
ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
|
||||||
assert(isTokenStringLiteral() && "Not a string literal!");
|
assert(isTokenStringLiteral() && "Not a string literal!");
|
||||||
|
|
||||||
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
|
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
|
||||||
|
@ -2110,6 +2111,12 @@ ExprResult Parser::ParseStringLiteralExpression() {
|
||||||
SmallVector<Token, 4> StringToks;
|
SmallVector<Token, 4> StringToks;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if (!AllowUserDefinedLiteral && Tok.hasUDSuffix()) {
|
||||||
|
Diag(Tok, diag::err_invalid_string_udl);
|
||||||
|
do ConsumeStringToken(); while (isTokenStringLiteral());
|
||||||
|
return ExprError();
|
||||||
|
}
|
||||||
|
|
||||||
StringToks.push_back(Tok);
|
StringToks.push_back(Tok);
|
||||||
ConsumeStringToken();
|
ConsumeStringToken();
|
||||||
} while (isTokenStringLiteral());
|
} while (isTokenStringLiteral());
|
||||||
|
|
|
@ -1905,8 +1905,13 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
|
|
||||||
if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) {
|
if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) {
|
||||||
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
|
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)
|
if (Tok.getLength() != 2)
|
||||||
Diag(Tok.getLocation(), diag::err_operator_string_not_empty);
|
Diag(Tok.getLocation(), diag::err_literal_operator_string_not_empty);
|
||||||
ConsumeStringToken();
|
ConsumeStringToken();
|
||||||
|
|
||||||
if (Tok.isNot(tok::identifier)) {
|
if (Tok.isNot(tok::identifier)) {
|
||||||
|
|
|
@ -2011,6 +2011,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
||||||
|
|
||||||
case tok::string_literal: // primary-expression: string-literal
|
case tok::string_literal: // primary-expression: string-literal
|
||||||
case tok::wide_string_literal:
|
case tok::wide_string_literal:
|
||||||
|
if (Tok.hasUDSuffix())
|
||||||
|
return ExprError(Diag(Tok, diag::err_invalid_string_udl));
|
||||||
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
|
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
|
||||||
default:
|
default:
|
||||||
if (Tok.getIdentifierInfo() == 0)
|
if (Tok.getIdentifierInfo() == 0)
|
||||||
|
|
|
@ -1797,10 +1797,8 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
|
||||||
|
|
||||||
ExprResult AsmString(ParseAsmStringLiteral());
|
ExprResult AsmString(ParseAsmStringLiteral());
|
||||||
if (AsmString.isInvalid()) {
|
if (AsmString.isInvalid()) {
|
||||||
// If the reason we are recovering is because of an improper string
|
// Consume up to and including the closing paren.
|
||||||
// literal, it makes the most sense just to consume to the ')'.
|
T.skipToEnd();
|
||||||
if (isTokenStringLiteral())
|
|
||||||
T.skipToEnd();
|
|
||||||
return StmtError();
|
return StmtError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1127,9 +1127,13 @@ Parser::ExprResult Parser::ParseAsmStringLiteral() {
|
||||||
switch (Tok.getKind()) {
|
switch (Tok.getKind()) {
|
||||||
case tok::string_literal:
|
case tok::string_literal:
|
||||||
break;
|
break;
|
||||||
|
case tok::utf8_string_literal:
|
||||||
|
case tok::utf16_string_literal:
|
||||||
|
case tok::utf32_string_literal:
|
||||||
case tok::wide_string_literal: {
|
case tok::wide_string_literal: {
|
||||||
SourceLocation L = Tok.getLocation();
|
SourceLocation L = Tok.getLocation();
|
||||||
Diag(Tok, diag::err_asm_operand_wide_string_literal)
|
Diag(Tok, diag::err_asm_operand_wide_string_literal)
|
||||||
|
<< (Tok.getKind() == tok::wide_string_literal)
|
||||||
<< SourceRange(L, L);
|
<< SourceRange(L, L);
|
||||||
return ExprError();
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
@ -1138,10 +1142,7 @@ Parser::ExprResult Parser::ParseAsmStringLiteral() {
|
||||||
return ExprError();
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult Res(ParseStringLiteralExpression());
|
return ParseStringLiteralExpression();
|
||||||
if (Res.isInvalid()) return move(Res);
|
|
||||||
|
|
||||||
return move(Res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseSimpleAsm
|
/// ParseSimpleAsm
|
||||||
|
|
|
@ -409,6 +409,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
|
||||||
--TokLen;
|
--TokLen;
|
||||||
// FALL THROUGH.
|
// FALL THROUGH.
|
||||||
case tok::string_literal:
|
case tok::string_literal:
|
||||||
|
// FIXME: Exclude the optional ud-suffix from the highlighted range.
|
||||||
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
|
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
|
||||||
"<span class='string_literal'>", "</span>");
|
"<span class='string_literal'>", "</span>");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,7 +10,7 @@ string operator "" _i18n(const char*, std::size_t); // ok
|
||||||
// FIXME: This should be accepted once we support UCNs
|
// FIXME: This should be accepted once we support UCNs
|
||||||
template<char...> int operator "" \u03C0(); // ok, UCN for lowercase pi // expected-error {{expected identifier}}
|
template<char...> int operator "" \u03C0(); // ok, UCN for lowercase pi // expected-error {{expected identifier}}
|
||||||
// FIXME: Accept this as an extension, with a fix-it to add the space
|
// FIXME: Accept this as an extension, with a fix-it to add the space
|
||||||
float operator ""E(const char *); // expected-error {{must be '""'}} expected-error {{expected identifier}}
|
float operator ""E(const char *); // expected-error {{C++11 requires a space between the "" and the user-defined suffix in a literal operator}}
|
||||||
float operator " " B(const char *); // expected-error {{must be '""'}} expected-warning {{hexfloat}}
|
float operator " " B(const char *); // expected-error {{must be '""'}} expected-warning {{hexfloat}}
|
||||||
string operator "" 5X(const char *, std::size_t); // expected-error {{expected identifier}}
|
string operator "" 5X(const char *, std::size_t); // expected-error {{expected identifier}}
|
||||||
double operator "" _miles(double); // expected-error {{parameter}}
|
double operator "" _miles(double); // expected-error {{parameter}}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// RUN: %clang_cc1 -E -std=c++11 -o - %s | FileCheck %s
|
||||||
|
|
||||||
|
#define id(x) x
|
||||||
|
id("s")_x // CHECK: "s" _x
|
||||||
|
id(L"s")_x // CHECK: L"s" _x
|
||||||
|
id(u8"s")_x // CHECK: u8"s" _x
|
||||||
|
id(u"s")_x // CHECK: u"s" _x
|
||||||
|
id(U"s")_x // CHECK: U"s" _x
|
||||||
|
id('s')_x // CHECK: 's' _x
|
||||||
|
id(L's')_x // CHECK: L's' _x
|
||||||
|
id(u's')_x // CHECK: u's' _x
|
||||||
|
id(U's')_x // CHECK: U's' _x
|
||||||
|
id("s"_x)_y // CHECK: "s"_x _y
|
||||||
|
id(1.0_)f // CHECK: 1.0_ f
|
||||||
|
id(1.0)_f // CHECK: 1.0 _f
|
||||||
|
id(0xface+)b_count // CHECK: 0xface+ b_count
|
||||||
|
id("s")1 // CHECK: "s"1
|
||||||
|
id("s"_x)1 // CHECK: "s"_x 1
|
||||||
|
id(1)_2_x // CHECK: 1 _2_x
|
|
@ -0,0 +1,8 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
|
||||||
|
int foo1 asm ("bar1");
|
||||||
|
int foo2 asm (L"bar2"); // expected-error {{cannot use wide string literal in 'asm'}}
|
||||||
|
int foo3 asm (u8"bar3"); // expected-error {{cannot use unicode string literal in 'asm'}}
|
||||||
|
int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in 'asm'}}
|
||||||
|
int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
|
||||||
|
int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
|
|
@ -0,0 +1,60 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++11 -verify %s -fms-extensions -triple x86_64-apple-darwin9.0.0
|
||||||
|
|
||||||
|
// A ud-suffix cannot be used on string literals in a whole bunch of contexts:
|
||||||
|
|
||||||
|
#include "foo"_bar // expected-error {{expected "FILENAME" or <FILENAME>}}
|
||||||
|
#line 1 "foo"_bar // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
# 1 "foo"_bar 1 // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
#ident "foo"_bar // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
_Pragma("foo"_bar) // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
#pragma comment(lib, "foo"_bar) // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
_Pragma("comment(lib, \"foo\"_bar)") // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
#pragma message "hi"_there // expected-error {{user-defined suffix cannot be used here}} expected-warning {{hi}}
|
||||||
|
#pragma push_macro("foo"_bar) // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
#if __has_warning("-Wan-island-to-discover"_bar) // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
#elif __has_include("foo"_bar) // expected-error {{expected "FILENAME" or <FILENAME>}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C++"_x {} // expected-error {{user-defined suffix cannot be used here}} expected-error {{unknown linkage language}}
|
||||||
|
|
||||||
|
int f() {
|
||||||
|
asm("mov %eax, %rdx"_foo); // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(true, "foo"_bar); // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
|
||||||
|
int cake() __attribute__((availability(macosx, unavailable, message = "is a lie"_x))); // expected-error {{user-defined suffix cannot be used here}}
|
||||||
|
|
||||||
|
// A ud-suffix cannot be used on character literals in preprocessor constant
|
||||||
|
// expressions:
|
||||||
|
#if 'x'_y - u'x'_z // expected-error 2{{character literal with user-defined suffix cannot be used in preprocessor constant expression}}
|
||||||
|
#error error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// But they can appear in expressions.
|
||||||
|
constexpr char operator"" _id(char c) { return c; }
|
||||||
|
constexpr wchar_t operator"" _id(wchar_t c) { return c; }
|
||||||
|
constexpr char16_t operator"" _id(char16_t c) { return c; }
|
||||||
|
constexpr char32_t operator"" _id(char32_t c) { return c; }
|
||||||
|
|
||||||
|
using size_t = decltype(sizeof(int));
|
||||||
|
constexpr const char operator"" _id(const char *p, size_t n) { return *p; }
|
||||||
|
constexpr const wchar_t operator"" _id(const wchar_t *p, size_t n) { return *p; }
|
||||||
|
constexpr const char16_t operator"" _id(const char16_t *p, size_t n) { return *p; }
|
||||||
|
constexpr const char32_t operator"" _id(const char32_t *p, size_t n) { return *p; }
|
||||||
|
|
||||||
|
template<int n> struct S {};
|
||||||
|
S<"a"_id[0]> sa;
|
||||||
|
S<L"b"_id[0]> sb;
|
||||||
|
S<u8"c"_id[0]> sc;
|
||||||
|
S<u"d"_id[0]> sd;
|
||||||
|
S<U"e"_id[0]> se;
|
||||||
|
|
||||||
|
S<'w'_id> sw;
|
||||||
|
S<L'x'_id> sx;
|
||||||
|
S<u'y'_id> sy;
|
||||||
|
S<U'z'_id> sz;
|
||||||
|
|
||||||
|
void h() {
|
||||||
|
(void)"test"_id "test" L"test";
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
|
||||||
|
id x = @"foo"_bar; // expected-error{{user-defined suffix cannot be used here}}
|
Loading…
Reference in New Issue