Disallow an empty string literal in an asm label
An empty string literal in an asm label does not make a whole lot of sense. GCC
does not diagnose such a construct, but it also generates code that cannot be
assembled by gas should two symbols have an empty asm label within the same TU.
This does not affect an asm statement with an empty string literal, which is
still a useful construct.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index a90147c..514a2ed 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2197,7 +2197,7 @@
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopBeforeMatch);
return true;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index ca2497e..af34034 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2325,7 +2325,7 @@
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid())
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index fecd70b..a399984 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2017,7 +2017,7 @@
// simple-asm-expr[opt]
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi, StopAtSemi);
return Sema::ConditionError();
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp
index d35973d..ea2c871 100644
--- a/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/clang/lib/Parse/ParseStmtAsm.cpp
@@ -743,7 +743,7 @@
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprResult AsmString(ParseAsmStringLiteral());
+ ExprResult AsmString(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
// Check if GNU-style InlineAsm is disabled.
// Error on anything other than empty string.
@@ -823,7 +823,7 @@
// Parse the asm-string list for clobbers if present.
if (!AteExtraColon && isTokenStringLiteral()) {
while (1) {
- ExprResult Clobber(ParseAsmStringLiteral());
+ ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
if (Clobber.isInvalid())
break;
@@ -920,7 +920,7 @@
} else
Names.push_back(nullptr);
- ExprResult Constraint(ParseAsmStringLiteral());
+ ExprResult Constraint(ParseAsmStringLiteral(/*ForAsmLabel*/ false));
if (Constraint.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return true;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index ed4e6ff..4249de3 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -803,7 +803,7 @@
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
- ExprResult Result(ParseSimpleAsm(&EndLoc));
+ ExprResult Result(ParseSimpleAsm(/*ForAsmLabel*/ false, &EndLoc));
// Check if GNU-style InlineAsm is disabled.
// Empty asm string is allowed because it will not introduce
@@ -1467,11 +1467,14 @@
/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
/// allowed to be a wide string, and is not subject to character translation.
+/// Unlike GCC, we also diagnose an empty string literal when parsing for an
+/// asm label as opposed to an asm statement, because such a construct does not
+/// behave well.
///
/// [GNU] asm-string-literal:
/// string-literal
///
-ExprResult Parser::ParseAsmStringLiteral() {
+ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) {
if (!isTokenStringLiteral()) {
Diag(Tok, diag::err_expected_string_literal)
<< /*Source='in...'*/0 << "'asm'";
@@ -1487,6 +1490,11 @@
<< SL->getSourceRange();
return ExprError();
}
+ if (ForAsmLabel && SL->getString().empty()) {
+ Diag(Tok, diag::err_asm_operand_wide_string_literal)
+ << 2 /* an empty */ << SL->getSourceRange();
+ return ExprError();
+ }
}
return AsmString;
}
@@ -1496,7 +1504,7 @@
/// [GNU] simple-asm-expr:
/// 'asm' '(' asm-string-literal ')'
///
-ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
+ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_asm) && "Not an asm!");
SourceLocation Loc = ConsumeToken();
@@ -1516,7 +1524,7 @@
return ExprError();
}
- ExprResult Result(ParseAsmStringLiteral());
+ ExprResult Result(ParseAsmStringLiteral(ForAsmLabel));
if (!Result.isInvalid()) {
// Close the paren and get the location of the end bracket