Commit 93313b94 by Joseph Myers Committed by Joseph Myers

Handle :: tokens in C for C2x.

As part of adding [[]]-style attributes, C2x adds the token :: for use
in scoped attribute names.

This patch adds corresponding support for that token in C to GCC.  The
token is supported both for C2x and for older gnu* standards (on the
basis that extensions are normally supported in older gnu* versions;
people will expect to be able to use [[]] attributes, before C2x is
the default, without needing to use -std=gnu2x).

There are no cases in older C standards where the token : can be
followed by a token starting with : in syntactically valid sources;
the only cases the :: token could break in older standard C thus are
ones involving concatenation of pp-tokens where the result does not
end up as tokens (e.g., gets stringized).  In GNU C extensions, the
main case where :: might appear in existing sources is in asm
statements, and the C parser is thus made to handle it like two
consecutive : tokens, which the C++ parser already does.  A limited
test of various positionings of :: in asm statements is added to the
testsuite (in particular, to cover the syntax error when :: means too
many colons but a single : would be OK), but existing tests cover a
variety of styles there anyway.

Technically there are cases in Objective-C and OpenMP for which this
also changes how previously valid code is lexed: the objc-selector-arg
syntax allows multiple consecutive : tokens (although I don't think
they are particularly useful there), while OpenMP syntax includes
array section syntax such as [:] which, before :: was a token, could
also be written as [::> (there might be other OpenMP cases potentially
affected, I didn't check all the OpenMP syntax in detail).  I don't
think either of those cases affects the basis for supporting the ::
token in all -std=gnu* modes, or that there is any obvious need to
special-case handling of CPP_SCOPE tokens for those constructs the way
there is for asm statements.

cpp_avoid_paste, which determines when spaces need adding between
tokens in preprocessed output where there wouldn't otherwise be
whitespace between them (e.g. if stringized), already inserts space
between : and : unconditionally, rather than only for C++, so no
change is needed there (but a C2x test is added that such space is
indeed inserted).

Bootstrapped with no regressions on x86-64-pc-linux-gnu.

gcc/c:
	* c-parser.c (c_parser_asm_statement): Handle CPP_SCOPE like two
	CPP_COLON tokens.

gcc/testsuite:
	* gcc.dg/asm-scope-1.c, gcc.dg/cpp/c11-scope-1.c,
	gcc.dg/cpp/c17-scope-1.c, gcc.dg/cpp/c2x-scope-1.c,
	gcc.dg/cpp/c2x-scope-2.c, gcc.dg/cpp/c90-scope-1.c,
	gcc.dg/cpp/c94-scope-1.c, gcc.dg/cpp/c99-scope-1.c,
	gcc.dg/cpp/gnu11-scope-1.c, gcc.dg/cpp/gnu17-scope-1.c,
	gcc.dg/cpp/gnu89-scope-1.c, gcc.dg/cpp/gnu99-scope-1.c: New tests.

libcpp:
	* include/cpplib.h (struct cpp_options): Add member scope.
	* init.c (struct lang_flags, lang_defaults): Likewise.
	(cpp_set_lang): Set scope member of pfile.
	* lex.c (_cpp_lex_direct): Test CPP_OPTION (pfile, scope) not
	CPP_OPTION (pfile, cplusplus) for creating CPP_SCOPE tokens.

From-SVN: r276434
parent e9c9a142
2019-10-02 Joseph Myers <joseph@codesourcery.com>
* c-parser.c (c_parser_asm_statement): Handle CPP_SCOPE like two
CPP_COLON tokens.
2019-10-01 Richard Sandiford <richard.sandiford@arm.com> 2019-10-01 Richard Sandiford <richard.sandiford@arm.com>
* c-objc-common.c (useful_aka_type_p): New function. * c-objc-common.c (useful_aka_type_p): New function.
......
...@@ -6411,7 +6411,9 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, ...@@ -6411,7 +6411,9 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
The form with asm-goto-operands is valid if and only if the 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. asm-qualifier-list contains goto, and is the only allowed form in that case.
Duplicate asm-qualifiers are not allowed. */ Duplicate asm-qualifiers are not allowed.
The :: token is considered equivalent to two consecutive : tokens. */
static tree static tree
c_parser_asm_statement (c_parser *parser) c_parser_asm_statement (c_parser *parser)
...@@ -6509,17 +6511,28 @@ c_parser_asm_statement (c_parser *parser) ...@@ -6509,17 +6511,28 @@ c_parser_asm_statement (c_parser *parser)
nsections = 3 + is_goto; nsections = 3 + is_goto;
for (section = 0; section < nsections; ++section) for (section = 0; section < nsections; ++section)
{ {
if (!c_parser_require (parser, CPP_COLON, if (c_parser_next_token_is (parser, CPP_SCOPE))
is_goto {
? G_("expected %<:%>") ++section;
: G_("expected %<:%> or %<)%>"), if (section == nsections)
UNKNOWN_LOCATION, is_goto)) {
c_parser_error (parser, "expected %<)%>");
goto error_close_paren;
}
c_parser_consume_token (parser);
}
else if (!c_parser_require (parser, CPP_COLON,
is_goto
? G_("expected %<:%>")
: G_("expected %<:%> or %<)%>"),
UNKNOWN_LOCATION, is_goto))
goto error_close_paren; goto error_close_paren;
/* Once past any colon, we're no longer a simple asm. */ /* Once past any colon, we're no longer a simple asm. */
simple = false; simple = false;
if ((!c_parser_next_token_is (parser, CPP_COLON) if ((!c_parser_next_token_is (parser, CPP_COLON)
&& !c_parser_next_token_is (parser, CPP_SCOPE)
&& !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
|| section == 3) || section == 3)
switch (section) switch (section)
......
2019-10-02 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/asm-scope-1.c, gcc.dg/cpp/c11-scope-1.c,
gcc.dg/cpp/c17-scope-1.c, gcc.dg/cpp/c2x-scope-1.c,
gcc.dg/cpp/c2x-scope-2.c, gcc.dg/cpp/c90-scope-1.c,
gcc.dg/cpp/c94-scope-1.c, gcc.dg/cpp/c99-scope-1.c,
gcc.dg/cpp/gnu11-scope-1.c, gcc.dg/cpp/gnu17-scope-1.c,
gcc.dg/cpp/gnu89-scope-1.c, gcc.dg/cpp/gnu99-scope-1.c: New tests.
2019-10-01 David Malcolm <dmalcolm@redhat.com> 2019-10-01 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/plugin/diagnostic_group_plugin.c (test_begin_group_cb): * gcc.dg/plugin/diagnostic_group_plugin.c (test_begin_group_cb):
......
/* Test :: token handling in asm. */
/* { dg-do compile } */
/* { dg-options "-std=gnu2x" } */
void
f (void)
{
asm ("");
asm ("" : );
asm ("" : :);
asm ("" ::);
asm ("" : : :);
asm ("" :: :);
asm ("" : ::);
asm goto ("" : : : : lab);
asm goto ("" :: : : lab);
asm goto ("" : :: : lab);
asm goto ("" : : :: lab);
asm goto ("" :: :: lab);
lab: ;
/* Test errors when :: is at the end of asm and only one : allowed. */
asm ("" : : ::); /* { dg-error "expected" } */
asm ("" :: ::); /* { dg-error "expected" } */
asm goto ("" : : : :: lab); /* { dg-error "expected" } */
asm goto ("" :: : :: lab); /* { dg-error "expected" } */
asm goto ("" : :: :: lab); /* { dg-error "expected" } */
}
/* Test :: token not in C11. */
/* { dg-do preprocess } */
/* { dg-options "-std=c11 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */
CONCAT (::, >)
/* Test :: token not in C17. */
/* { dg-do preprocess } */
/* { dg-options "-std=c17 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */
CONCAT (::, >)
/* Test :: token in C2x. */
/* { dg-do preprocess } */
/* { dg-options "-std=c2x -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :)
CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */
/* Test :: token in C2x: preprocessed output. */
/* { dg-do preprocess } */
/* { dg-options "-std=c2x -pedantic-errors -P" } */
#define COLON() :
#define TEST() ABC
/* This must have a space inserted between the two ':' tokens in
preprocessed output. */
TEST()COLON()COLON()TEST()
/* { dg-final { scan-file c2x-scope-2.i "ABC: :ABC" } } */
/* Test :: token not in C90. */
/* { dg-do preprocess } */
/* { dg-options "-std=c90 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */
/* Test :: token not in C94. */
/* { dg-do preprocess } */
/* { dg-options "-std=iso9899:199409 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */
CONCAT (::, >)
/* Test :: token not in C99. */
/* { dg-do preprocess } */
/* { dg-options "-std=c99 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :) /* { dg-error "does not give a valid preprocessing token" } */
CONCAT (::, >)
/* Test :: token in gnu11. */
/* { dg-do preprocess } */
/* { dg-options "-std=gnu11 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :)
CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */
/* Test :: token in gnu17. */
/* { dg-do preprocess } */
/* { dg-options "-std=gnu17 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :)
CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */
/* Test :: token in gnu89. */
/* { dg-do preprocess } */
/* { dg-options "-std=gnu89 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :)
CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */
/* Test :: token in gnu99. */
/* { dg-do preprocess } */
/* { dg-options "-std=gnu99 -pedantic-errors" } */
#define CONCAT(x, y) x ## y
CONCAT (:, :)
CONCAT (::, >) /* { dg-error "does not give a valid preprocessing token" } */
2019-10-02 Joseph Myers <joseph@codesourcery.com>
* include/cpplib.h (struct cpp_options): Add member scope.
* init.c (struct lang_flags, lang_defaults): Likewise.
(cpp_set_lang): Set scope member of pfile.
* lex.c (_cpp_lex_direct): Test CPP_OPTION (pfile, scope) not
CPP_OPTION (pfile, cplusplus) for creating CPP_SCOPE tokens.
2019-09-26 Eric Botcazou <ebotcazou@adacore.com> 2019-09-26 Eric Botcazou <ebotcazou@adacore.com>
* charset.c (UCS_LIMIT): New macro. * charset.c (UCS_LIMIT): New macro.
......
...@@ -483,6 +483,9 @@ struct cpp_options ...@@ -483,6 +483,9 @@ struct cpp_options
/* Nonzero for C++2a __VA_OPT__ feature. */ /* Nonzero for C++2a __VA_OPT__ feature. */
unsigned char va_opt; unsigned char va_opt;
/* Nonzero for the '::' token. */
unsigned char scope;
/* Holds the name of the target (execution) character set. */ /* Holds the name of the target (execution) character set. */
const char *narrow_charset; const char *narrow_charset;
......
...@@ -92,32 +92,33 @@ struct lang_flags ...@@ -92,32 +92,33 @@ struct lang_flags
char trigraphs; char trigraphs;
char utf8_char_literals; char utf8_char_literals;
char va_opt; char va_opt;
char scope;
}; };
static const struct lang_flags lang_defaults[] = static const struct lang_flags lang_defaults[] =
{ /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt */ { /* c99 c++ xnum xid c11 std digr ulit rlit udlit bincst digsep trig u8chlit vaopt scope*/
/* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
/* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
/* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
/* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
/* GNUC2X */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, /* GNUC2X */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 },
/* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* STDC89 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
/* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, /* STDC94 */ { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
/* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, /* STDC99 */ { 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
/* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 }, /* STDC11 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 },
/* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 }, /* STDC17 */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 },
/* STDC2X */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0 }, /* STDC2X */ { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1 },
/* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, /* GNUCXX */ { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
/* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1 },
/* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1 }, /* GNUCXX11 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1 },
/* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0 }, /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1 },
/* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1 }, /* GNUCXX14 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1 },
/* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1 },
/* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, /* GNUCXX17 */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 },
/* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0 }, /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1 },
/* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, /* GNUCXX2A */ { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 },
/* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, /* CXX2A */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 },
/* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}; };
/* Sets internal flags correctly for a given language. */ /* Sets internal flags correctly for a given language. */
...@@ -143,6 +144,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang) ...@@ -143,6 +144,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
CPP_OPTION (pfile, trigraphs) = l->trigraphs; CPP_OPTION (pfile, trigraphs) = l->trigraphs;
CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals; CPP_OPTION (pfile, utf8_char_literals) = l->utf8_char_literals;
CPP_OPTION (pfile, va_opt) = l->va_opt; CPP_OPTION (pfile, va_opt) = l->va_opt;
CPP_OPTION (pfile, scope) = l->scope;
} }
/* Initialize library global state. */ /* Initialize library global state. */
......
...@@ -3104,7 +3104,7 @@ _cpp_lex_direct (cpp_reader *pfile) ...@@ -3104,7 +3104,7 @@ _cpp_lex_direct (cpp_reader *pfile)
case ':': case ':':
result->type = CPP_COLON; result->type = CPP_COLON;
if (*buffer->cur == ':' && CPP_OPTION (pfile, cplusplus)) if (*buffer->cur == ':' && CPP_OPTION (pfile, scope))
buffer->cur++, result->type = CPP_SCOPE; buffer->cur++, result->type = CPP_SCOPE;
else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs)) else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs))
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment