@@ -6261,60 +6261,72 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
}
/* Parse an asm statement, a GNU extension. This is a full-blown asm
- statement with inputs, outputs, clobbers, and volatile tag
+ statement with inputs, outputs, clobbers, and volatile and goto tag
allowed.
+ asm-qualifier:
+ volatile
+ goto
+
+ asm-qualifier-list:
+ asm-qualifier-list asm-qualifier
+ asm-qualifier
+
asm-statement:
- asm type-qualifier[opt] ( asm-argument ) ;
- asm type-qualifier[opt] goto ( asm-goto-argument ) ;
+ asm asm-qualifier-list[opt] ( asm-argument ) ;
asm-argument:
asm-string-literal
asm-string-literal : asm-operands[opt]
asm-string-literal : asm-operands[opt] : asm-operands[opt]
- asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers[opt]
-
- asm-goto-argument:
+ asm-string-literal : asm-operands[opt] : asm-operands[opt] \
+ : asm-clobbers[opt]
asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \
: asm-goto-operands
- Qualifiers other than volatile are accepted in the syntax but
- warned for. */
+ The form with asm-goto-operands is valid if and only if the
+ asm-qualifier-list contains goto, and is the only allowed form in that case.
+ Duplicate asm-qualifiers are not allowed. */
static tree
c_parser_asm_statement (c_parser *parser)
{
tree quals, str, outputs, inputs, clobbers, labels, ret;
- bool simple, is_goto;
+ bool simple, is_volatile, is_goto;
location_t asm_loc = c_parser_peek_token (parser)->location;
int section, nsections;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
c_parser_consume_token (parser);
- if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
- {
- quals = c_parser_peek_token (parser)->value;
- c_parser_consume_token (parser);
- }
- else if (c_parser_next_token_is_keyword (parser, RID_CONST)
- || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
- {
- warning_at (c_parser_peek_token (parser)->location,
- 0,
- "%E qualifier ignored on asm",
- c_parser_peek_token (parser)->value);
- quals = NULL_TREE;
- c_parser_consume_token (parser);
- }
- else
- quals = NULL_TREE;
+ quals = NULL_TREE;
+ is_volatile = false;
is_goto = false;
- if (c_parser_next_token_is_keyword (parser, RID_GOTO))
- {
- c_parser_consume_token (parser);
- is_goto = true;
- }
+ for (bool done = false; !done; )
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_VOLATILE:
+ if (!is_volatile)
+ {
+ is_volatile = true;
+ quals = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ done = true;
+ break;
+ case RID_GOTO:
+ if (!is_goto)
+ {
+ is_goto = true;
+ c_parser_consume_token (parser);
+ }
+ else
+ done = true;
+ break;
+ default:
+ done = true;
+ }
/* ??? Follow the C++ parser rather than using the
lex_untranslated_string kludge. */
@@ -19067,22 +19067,34 @@ cp_parser_using_directive (cp_parser* parser)
/* Parse an asm-definition.
+ asm-qualifier:
+ volatile
+ goto
+
+ asm-qualifier-list:
+ asm-qualifier
+ asm-qualifier-list asm-qualifier
+
asm-definition:
asm ( string-literal ) ;
GNU Extension:
asm-definition:
- asm volatile [opt] ( string-literal ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( string-literal ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ : asm-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ : asm-operand-list [opt]
: asm-clobber-list [opt] ) ;
- asm volatile [opt] goto ( string-literal : : asm-operand-list [opt]
- : asm-clobber-list [opt]
- : asm-goto-list ) ; */
+ asm asm-qualifier-list [opt] ( string-literal : : asm-operand-list [opt]
+ : asm-clobber-list [opt]
+ : asm-goto-list ) ;
+
+ The form with asm-goto-list is valid if and only if the asm-qualifier-list
+ contains goto, and is the only allowed form in that case. No duplicates are
+ allowed in an asm-qualifier-list. */
static void
cp_parser_asm_definition (cp_parser* parser)
@@ -19111,23 +19123,36 @@ cp_parser_asm_definition (cp_parser* parser)
}
/* See if the next token is `volatile'. */
- if (cp_parser_allow_gnu_extensions_p (parser)
- && cp_lexer_next_token_is_keyword (parser->lexer, RID_VOLATILE))
- {
- /* Remember that we saw the `volatile' keyword. */
- volatile_p = true;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- }
- if (cp_parser_allow_gnu_extensions_p (parser)
- && parser->in_function_body
- && cp_lexer_next_token_is_keyword (parser->lexer, RID_GOTO))
- {
- /* Remember that we saw the `goto' keyword. */
- goto_p = true;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- }
+ if (cp_parser_allow_gnu_extensions_p (parser))
+ for (bool done = false; !done ; )
+ switch (cp_lexer_peek_token (parser->lexer)->keyword)
+ {
+ case RID_VOLATILE:
+ if (!volatile_p)
+ {
+ /* Remember that we saw the `volatile' keyword. */
+ volatile_p = true;
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ done = true;
+ break;
+ case RID_GOTO:
+ if (!goto_p && parser->in_function_body)
+ {
+ /* Remember that we saw the `goto' keyword. */
+ goto_p = true;
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ done = true;
+ break;
+ default:
+ done = true;
+ }
+
/* Look for the opening `('. */
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return;
@@ -8147,7 +8147,7 @@ for a C symbol, or to place a C variable in a specific register.
A basic @code{asm} statement has the following syntax:
@example
-asm @r{[} volatile @r{]} ( @var{AssemblerInstructions} )
+asm @var{asm-qualifiers} ( @var{AssemblerInstructions} )
@end example
The @code{asm} keyword is a GNU extension.
@@ -8275,17 +8275,19 @@ Extended @code{asm} syntax uses colons (@samp{:}) to delimit
the operand parameters after the assembler template:
@example
-asm @r{[}volatile@r{]} ( @var{AssemblerTemplate}
+asm @var{asm-qualifiers} ( @var{AssemblerTemplate}
: @var{OutputOperands}
@r{[} : @var{InputOperands}
@r{[} : @var{Clobbers} @r{]} @r{]})
-asm @r{[}volatile@r{]} goto ( @var{AssemblerTemplate}
+asm @var{asm-qualifiers} ( @var{AssemblerTemplate}
:
: @var{InputOperands}
: @var{Clobbers}
: @var{GotoLabels})
@end example
+where in the last form, @var{asm-qualifiers} contains @code{goto} (and in the
+first form, not).
The @code{asm} keyword is a GNU extension.
When writing code that can be compiled with @option{-ansi} and the
@@ -1,4 +1,4 @@
-/* Test that qualifiers other than volatile are ignored on asm. */
+/* Test that qualifiers other than volatile are disallowed on asm. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99" } */
@@ -7,6 +7,10 @@ void
f (void)
{
asm volatile ("");
- asm const (""); /* { dg-warning "const qualifier ignored on asm" } */
- asm restrict (""); /* { dg-warning "restrict qualifier ignored on asm" } */
+
+ asm const (""); /* { dg-error {expected '\(' before 'const'} } */
+ /* { dg-error {expected identifier} {} {target *-*-*} .-1 } */
+
+ asm restrict (""); /* { dg-error {expected '\(' before 'restrict'} } */
+ /* { dg-error {expected identifier} {} {target *-*-*} .-1 } */
}
new file mode 100644
@@ -0,0 +1,21 @@
+/* Test that qualifiers on asm are allowed in any order. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+void
+f (void)
+{
+ asm volatile goto ("" :::: lab);
+ asm goto volatile ("" :::: lab);
+
+ /* Duplicates are not allowed. */
+ asm goto volatile volatile ("" :::: lab); /* { dg-error "" } */
+ asm volatile goto volatile ("" :::: lab); /* { dg-error "" } */
+ asm volatile volatile goto ("" :::: lab); /* { dg-error "" } */
+ asm goto goto volatile ("" :::: lab); /* { dg-error "" } */
+ asm goto volatile goto ("" :::: lab); /* { dg-error "" } */
+ asm volatile goto goto ("" :::: lab); /* { dg-error "" } */
+
+lab:
+ ;
+}