aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2012-05-16 10:51:15 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2012-05-16 12:51:15 +0200
commit0b2c4be5fdff70f1babd503c9f6dbabd664c44c7 (patch)
tree866b6e9e6346cbd21ad2a4974753e1735d1f01b6 /gcc/cp/parser.c
parent40295cc722ce5ea0b7ba7b3cb91f6accce0db518 (diff)
downloadgcc-0b2c4be5fdff70f1babd503c9f6dbabd664c44c7.zip
gcc-0b2c4be5fdff70f1babd503c9f6dbabd664c44c7.tar.gz
gcc-0b2c4be5fdff70f1babd503c9f6dbabd664c44c7.tar.bz2
PR preprocessor/7263 - Avoid pedantic warnings on system headers macro tokens
Now that we track token locations accross macro expansions, it would be cool to be able to fix PR preprocessor/7263 for real. That is, consider this example where we have a system header named header.h like this: #define _Complex __complex__ #define _Complex_I 1.0iF and then a normal C file like this: #include "header.h" static _Complex float c = _Complex_I; If we compile the file with -pedantic, the usages of _Complex or _Complex_I should not trigger any warning, even though __complex__ and the complex literal are extensions to the standard C. They shouldn't trigger any warning because _Complex and _Complex_I are defined in a system header (and expanded in normal user code). To be able to handle this, we must address two separate concerns. First, warnings about non-standard usage of numerical literals are emitted directly from within libcpp. So we must teach libcpp's parser for numerical literals to use virtual locations, instead of the spelling location it uses today. Once we have that, as the diagnostics machinery already knows how to avoid emitting errors happening on tokens that come from system headers, we win. Second, there is the issue of tracking locations for declaration specifiers, like the "_Complex" in the declaration: static _Complex float c; For that, we need to arrange for each possible declaration specifier to have its own location, because otherwise, we'd warn on e.g, on: _Complex float c; but not on: static _Complex float c; So this patch addresses the two concerns above. It's actually a follow-up on an earlier patch[1] I wrote as part of my initial work on virtual locations. We then agreed[2] that the second concern was important to address before the patch could get a chance to go in. [1]: http://gcc.gnu.org/ml/gcc-patches/2011-09/msg00957.html [2]: http://gcc.gnu.org/ml/gcc-patches/2011-10/msg00264.html Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk. libcpp/ PR preprocessor/7263 * include/cpplib.h (cpp_classify_number): Take a location parameter. * expr.c (SYNTAX_ERROR_AT, SYNTAX_ERROR2_AT): New diagnostic macros that take a location parameter. (cpp_classify_number): Take a (virtual) location parameter. Use it for diagnostics. Adjust comments. (eval_token): Take a location parameter. Pass it to cpp_classify_number and to diagnostic routines. (_cpp_parse_expr): Use virtual locations of tokens when parsing expressions. Pass a virtual location to eval_token and to diagnostic routines. gcc/c-family/ PR preprocessor/7263 * c-lex.c (c_lex_with_flags): Pass a virtual location to the call to cpp_classify_number. For diagnostics, use the precise location instead of the global input_location. gcc/ PR preprocessor/7263 * c-tree.h (enum c_declspec_word): Declare new enum. (struct c_declspecs::locations): New member. (declspecs_add_qual, declspecs_add_scspec) (declspecs_add_addrspace, declspecs_add_alignas): Take a new location parameter. * c-decl.c (build_null_declspecs): Initialize the new struct c_declspecs::locations member. (declspecs_add_addrspace): Take a location parameter for the address space. Store it onto declaration specifiers. (declspecs_add_qual): Likewise, take a location parameter for the qualifier. (declspecs_add_type): Likewise, take a location parameter for the type specifier. (declspecs_add_scspec): Likewise, take a location parameter for the storage class specifier. (declspecs_add_attrs): Likewise, take a location parameter for the first attribute. (declspecs_add_alignas): Likewise, take a location parameter for the alignas token. (finish_declspecs): For diagnostics, use the location of the relevant declspec, instead of the global input_location. * c-parser.c (c_parser_parameter_declaration): Pass the precise virtual location of the declspec to the declspecs-setters. (c_parser_declspecs): Likewise. Avoid calling c_parser_peek_token repeatedly. gcc/cp/ PR preprocessor/7263 * cp-tree.h (enum cp_decl_spec): Add new enumerators to cover all the possible declarator specifiers so far. (struct cp_decl_specifier_seq::locations): Declare new member. (cp_decl_specifier_seq::{specs, type_location}): Remove. (decl_spec_seq_has_spec_p): Declare new function. * parser.c (cp_parser_check_decl_spec): Remove. (set_and_check_decl_spec_loc): Define new static function. (decl_spec_seq_has_spec_p): Define new public function. (cp_parser_decl_specifier_seq, cp_parser_function_specifier_opt) (cp_parser_type_specifier, cp_parser_simple_type_specifier) (cp_parser_set_storage_class, cp_parser_set_decl_spec_type) (cp_parser_alias_declaration): Set the locations for each declspec, using set_and_check_decl_spec_loc. (cp_parser_explicit_instantiation, cp_parser_init_declarator) (cp_parser_member_declaration, cp_parser_init_declarator): Use the new declspec location for specifiers. Use the new decl_spec_seq_has_spec_p. (cp_parser_type_specifier_seq): Use the new set_and_check_decl_spec_loc. Stop using cp_parser_check_decl_spec. Use the new decl_spec_seq_has_spec_p. (, cp_parser_init_declarator): Use the new set_and_check_decl_spec_loc. (cp_parser_single_declaration, cp_parser_friend_p) (cp_parser_objc_class_ivars, cp_parser_objc_struct_declaration): Use the new decl_spec_seq_has_spec_p. * decl.c (check_tag_decl): Use new decl_spec_seq_has_spec_p. Use the more precise ds_redefined_builtin_type_spec location for diagnostics about re-declaring C++ built-in types. (start_decl, grokvardecl, grokdeclarator): Use the new decl_spec_seq_has_spec_p. gcc/testsuite/ PR preprocessor/7263 * gcc.dg/binary-constants-2.c: Run without tracking locations accross macro expansion. * gcc.dg/binary-constants-3.c: Likewise. * gcc.dg/cpp/sysmac2.c: Likewise. * testsuite/gcc.dg/nofixed-point-2.c: Adjust for more precise location. * gcc.dg/cpp/syshdr3.c: New test. * gcc.dg/cpp/syshdr3.h: New header for the new test above. * gcc.dg/system-binary-constants-1.c: New test. * gcc.dg/system-binary-constants-1.h: New header for the new test above. * g++.dg/cpp/syshdr3.C: New test. * g++.dg/cpp/syshdr3.h: New header the new test above. * g++.dg/system-binary-constants-1.C: New test. * g++.dg/system-binary-constants-1.h: New header the new test above. From-SVN: r187587
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c261
1 files changed, 156 insertions, 105 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index dc64fa1..2dc8f56 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2223,6 +2223,9 @@ static void cp_parser_set_storage_class
(cp_parser *, cp_decl_specifier_seq *, enum rid, location_t);
static void cp_parser_set_decl_spec_type
(cp_decl_specifier_seq *, tree, location_t, bool);
+static void set_and_check_decl_spec_loc
+ (cp_decl_specifier_seq *decl_specs,
+ cp_decl_spec ds, source_location location);
static bool cp_parser_friend_p
(const cp_decl_specifier_seq *);
static void cp_parser_required_error
@@ -2494,53 +2497,6 @@ cp_parser_simulate_error (cp_parser* parser)
return false;
}
-/* Check for repeated decl-specifiers. */
-
-static void
-cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs,
- location_t location)
-{
- int ds;
-
- for (ds = ds_first; ds != ds_last; ++ds)
- {
- unsigned count = decl_specs->specs[ds];
- if (count < 2)
- continue;
- /* The "long" specifier is a special case because of "long long". */
- if (ds == ds_long)
- {
- if (count > 2)
- error_at (location, "%<long long long%> is too long for GCC");
- else
- pedwarn_cxx98 (location, OPT_Wlong_long,
- "ISO C++ 1998 does not support %<long long%>");
- }
- else if (count > 1)
- {
- static const char *const decl_spec_names[] = {
- "signed",
- "unsigned",
- "short",
- "long",
- "const",
- "volatile",
- "restrict",
- "inline",
- "virtual",
- "explicit",
- "friend",
- "typedef",
- "using",
- "constexpr",
- "__complex",
- "__thread"
- };
- error_at (location, "duplicate %qs", decl_spec_names[ds]);
- }
- }
-}
-
/* This function is called when a type is defined. If type
definitions are forbidden at this point, an error message is
issued. */
@@ -10555,6 +10511,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
{
bool constructor_possible_p = !parser->in_declarator_p;
cp_token *start_token = NULL;
+ cp_decl_spec ds;
/* Clear DECL_SPECS. */
clear_decl_specs (decl_specs);
@@ -10568,6 +10525,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
bool constructor_p;
bool found_decl_spec;
cp_token *token;
+ ds = ds_last;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
@@ -10583,6 +10541,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
decl_specs->attributes
= chainon (decl_specs->attributes,
cp_parser_attributes_opt (parser));
+ if (decl_specs->locations[ds_attribute] == 0)
+ decl_specs->locations[ds_attribute] = token->location;
continue;
}
/* Assume we will find a decl-specifier keyword. */
@@ -10602,14 +10562,14 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
}
else
{
- ++decl_specs->specs[(int) ds_friend];
+ ds = ds_friend;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
break;
case RID_CONSTEXPR:
- ++decl_specs->specs[(int) ds_constexpr];
+ ds = ds_constexpr;
cp_lexer_consume_token (parser->lexer);
break;
@@ -10626,7 +10586,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
/* decl-specifier:
typedef */
case RID_TYPEDEF:
- ++decl_specs->specs[(int) ds_typedef];
+ ds = ds_typedef;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
/* A constructor declarator cannot appear in a typedef. */
@@ -10679,8 +10639,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
break;
case RID_THREAD:
/* Consume the token. */
+ ds = ds_thread;
cp_lexer_consume_token (parser->lexer);
- ++decl_specs->specs[(int) ds_thread];
break;
default:
@@ -10694,13 +10654,16 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
&& token->keyword != RID_CONSTEXPR)
error ("decl-specifier invalid in condition");
+ if (ds != ds_last)
+ set_and_check_decl_spec_loc (decl_specs, ds, token->location);
+
/* Constructors are a special case. The `S' in `S()' is not a
decl-specifier; it is the beginning of the declarator. */
constructor_p
= (!found_decl_spec
&& constructor_possible_p
&& (cp_parser_constructor_declarator_p
- (parser, decl_specs->specs[(int) ds_friend] != 0)));
+ (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend))));
/* If we don't have a DECL_SPEC yet, then we must be looking at
a type-specifier. */
@@ -10777,12 +10740,10 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
flags |= CP_PARSER_FLAGS_OPTIONAL;
}
- cp_parser_check_decl_spec (decl_specs, start_token->location);
-
/* Don't allow a friend specifier with a class definition. */
- if (decl_specs->specs[(int) ds_friend] != 0
+ if (decl_spec_seq_has_spec_p (decl_specs, ds_friend)
&& (*declares_class_or_enum & 2))
- error_at (start_token->location,
+ error_at (decl_specs->locations[ds_friend],
"class definition may not be declared a friend");
}
@@ -10843,8 +10804,7 @@ cp_parser_function_specifier_opt (cp_parser* parser,
switch (token->keyword)
{
case RID_INLINE:
- if (decl_specs)
- ++decl_specs->specs[(int) ds_inline];
+ set_and_check_decl_spec_loc (decl_specs, ds_inline, token->location);
break;
case RID_VIRTUAL:
@@ -10853,13 +10813,11 @@ cp_parser_function_specifier_opt (cp_parser* parser,
A member function template shall not be virtual. */
if (PROCESSING_REAL_TEMPLATE_DECL_P ())
error_at (token->location, "templates may not be %<virtual%>");
- else if (decl_specs)
- ++decl_specs->specs[(int) ds_virtual];
+ set_and_check_decl_spec_loc (decl_specs, ds_virtual, token->location);
break;
case RID_EXPLICIT:
- if (decl_specs)
- ++decl_specs->specs[(int) ds_explicit];
+ set_and_check_decl_spec_loc (decl_specs, ds_explicit, token->location);
break;
default:
@@ -13170,14 +13128,16 @@ cp_parser_explicit_instantiation (cp_parser* parser)
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers.type,
- decl_specifiers.type_location);
+ decl_specifiers.locations[ds_type_spec]);
if (declarator != cp_error_declarator)
{
- if (decl_specifiers.specs[(int)ds_inline])
- permerror (input_location, "explicit instantiation shall not use"
+ if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_inline))
+ permerror (decl_specifiers.locations[ds_inline],
+ "explicit instantiation shall not use"
" %<inline%> specifier");
- if (decl_specifiers.specs[(int)ds_constexpr])
- permerror (input_location, "explicit instantiation shall not use"
+ if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_constexpr))
+ permerror (decl_specifiers.locations[ds_constexpr],
+ "explicit instantiation shall not use"
" %<constexpr%> specifier");
decl = grokdeclarator (declarator, &decl_specifiers,
@@ -13399,7 +13359,7 @@ cp_parser_type_specifier (cp_parser* parser,
type_spec
= (cp_parser_elaborated_type_specifier
(parser,
- decl_specs && decl_specs->specs[(int) ds_friend],
+ decl_spec_seq_has_spec_p (decl_specs, ds_friend),
is_declaration));
if (decl_specs)
cp_parser_set_decl_spec_type (decl_specs,
@@ -13440,7 +13400,7 @@ cp_parser_type_specifier (cp_parser* parser,
{
if (decl_specs)
{
- ++decl_specs->specs[(int)ds];
+ set_and_check_decl_spec_loc (decl_specs, ds, token->location);
decl_specs->any_specifiers_p = true;
}
return cp_lexer_consume_token (parser->lexer)->u.value;
@@ -13531,8 +13491,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
type = boolean_type_node;
break;
case RID_SHORT:
- if (decl_specs)
- ++decl_specs->specs[(int) ds_short];
+ set_and_check_decl_spec_loc (decl_specs, ds_short, token->location);
type = short_integer_type_node;
break;
case RID_INT:
@@ -13549,17 +13508,15 @@ cp_parser_simple_type_specifier (cp_parser* parser,
break;
case RID_LONG:
if (decl_specs)
- ++decl_specs->specs[(int) ds_long];
+ set_and_check_decl_spec_loc (decl_specs, ds_long, token->location);
type = long_integer_type_node;
break;
case RID_SIGNED:
- if (decl_specs)
- ++decl_specs->specs[(int) ds_signed];
+ set_and_check_decl_spec_loc (decl_specs, ds_signed, token->location);
type = integer_type_node;
break;
case RID_UNSIGNED:
- if (decl_specs)
- ++decl_specs->specs[(int) ds_unsigned];
+ set_and_check_decl_spec_loc (decl_specs, ds_unsigned, token->location);
type = unsigned_type_node;
break;
case RID_FLOAT:
@@ -15070,19 +15027,21 @@ static tree
cp_parser_alias_declaration (cp_parser* parser)
{
tree id, type, decl, pushed_scope = NULL_TREE, attributes;
- location_t id_location;
+ location_t id_location, using_location, attrs_location = 0;
cp_declarator *declarator;
cp_decl_specifier_seq decl_specs;
bool member_p;
const char *saved_message = NULL;
/* Look for the `using' keyword. */
+ using_location = cp_lexer_peek_token (parser->lexer)->location;
cp_parser_require_keyword (parser, RID_USING, RT_USING);
id_location = cp_lexer_peek_token (parser->lexer)->location;
id = cp_parser_identifier (parser);
if (id == error_mark_node)
return error_mark_node;
+ attrs_location = cp_lexer_peek_token (parser->lexer)->location;
attributes = cp_parser_attributes_opt (parser);
if (attributes == error_mark_node)
return error_mark_node;
@@ -15131,9 +15090,19 @@ cp_parser_alias_declaration (cp_parser* parser)
clear_decl_specs (&decl_specs);
decl_specs.type = type;
- decl_specs.attributes = attributes;
- ++decl_specs.specs[(int) ds_typedef];
- ++decl_specs.specs[(int) ds_alias];
+ if (attributes != NULL_TREE)
+ {
+ decl_specs.attributes = attributes;
+ set_and_check_decl_spec_loc (&decl_specs,
+ ds_attribute,
+ attrs_location);
+ }
+ set_and_check_decl_spec_loc (&decl_specs,
+ ds_typedef,
+ using_location);
+ set_and_check_decl_spec_loc (&decl_specs,
+ ds_alias,
+ using_location);
declarator = make_id_declarator (NULL_TREE, id, sfk_none);
declarator->id_loc = id_location;
@@ -15515,7 +15484,7 @@ cp_parser_init_declarator (cp_parser* parser,
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers->type,
- decl_specifiers->type_location);
+ decl_specifiers->locations[ds_type_spec]);
/* Figure out what scope the entity declared by the DECLARATOR is
located in. `grokdeclarator' sometimes changes the scope, so
@@ -16936,8 +16905,6 @@ cp_parser_type_specifier_seq (cp_parser* parser,
if (is_declaration && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
}
-
- cp_parser_check_decl_spec (type_specifier_seq, start_token->location);
}
/* Parse a parameter-declaration-clause.
@@ -19042,7 +19009,7 @@ cp_parser_member_declaration (cp_parser* parser)
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type
(declarator, decl_specifiers.type,
- decl_specifiers.type_location);
+ decl_specifiers.locations[ds_type_spec]);
/* Look for an asm-specification. */
asm_specification = cp_parser_asm_specification_opt (parser);
@@ -21301,7 +21268,7 @@ cp_parser_single_declaration (cp_parser* parser,
*friend_p = cp_parser_friend_p (&decl_specifiers);
/* There are no template typedefs. */
- if (decl_specifiers.specs[(int) ds_typedef])
+ if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
{
error_at (decl_spec_token_start->location,
"template declaration of %<typedef%>");
@@ -22049,10 +22016,11 @@ cp_parser_set_storage_class (cp_parser *parser,
}
if ((keyword == RID_EXTERN || keyword == RID_STATIC)
- && decl_specs->specs[(int) ds_thread])
+ && decl_spec_seq_has_spec_p (decl_specs, ds_thread))
{
- error_at (location, "%<__thread%> before %qD", ridpointers[keyword]);
- decl_specs->specs[(int) ds_thread] = 0;
+ error_at (decl_specs->locations[ds_thread],
+ "%<__thread%> before %qD", ridpointers[keyword]);
+ decl_specs->locations[ds_thread] = 0;
}
switch (keyword)
@@ -22076,12 +22044,13 @@ cp_parser_set_storage_class (cp_parser *parser,
gcc_unreachable ();
}
decl_specs->storage_class = storage_class;
+ set_and_check_decl_spec_loc (decl_specs, ds_storage_class, location);
/* A storage class specifier cannot be applied alongside a typedef
specifier. If there is a typedef specifier present then set
conflicting_specifiers_p which will trigger an error later
on in grokdeclarator. */
- if (decl_specs->specs[(int)ds_typedef])
+ if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef))
decl_specs->conflicting_specifiers_p = true;
}
@@ -22101,24 +22070,27 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
this is what happened. In system headers, we ignore these
declarations so that G++ can work with system headers that are not
C++-safe. */
- if (decl_specs->specs[(int) ds_typedef]
+ if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)
&& !type_definition_p
&& (type_spec == boolean_type_node
|| type_spec == char16_type_node
|| type_spec == char32_type_node
|| type_spec == wchar_type_node)
&& (decl_specs->type
- || decl_specs->specs[(int) ds_long]
- || decl_specs->specs[(int) ds_short]
- || decl_specs->specs[(int) ds_unsigned]
- || decl_specs->specs[(int) ds_signed]))
+ || decl_spec_seq_has_spec_p (decl_specs, ds_long)
+ || decl_spec_seq_has_spec_p (decl_specs, ds_short)
+ || decl_spec_seq_has_spec_p (decl_specs, ds_unsigned)
+ || decl_spec_seq_has_spec_p (decl_specs, ds_signed)))
{
decl_specs->redefined_builtin_type = type_spec;
+ set_and_check_decl_spec_loc (decl_specs,
+ ds_redefined_builtin_type_spec,
+ location);
if (!decl_specs->type)
{
decl_specs->type = type_spec;
decl_specs->type_definition_p = false;
- decl_specs->type_location = location;
+ set_and_check_decl_spec_loc (decl_specs,ds_type_spec, location);
}
}
else if (decl_specs->type)
@@ -22128,17 +22100,96 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
decl_specs->type = type_spec;
decl_specs->type_definition_p = type_definition_p;
decl_specs->redefined_builtin_type = NULL_TREE;
- decl_specs->type_location = location;
+ set_and_check_decl_spec_loc (decl_specs, ds_type_spec, location);
+ }
+}
+
+/* Set the location for a declarator specifier and check if it is
+ duplicated.
+
+ DECL_SPECS is the sequence of declarator specifiers onto which to
+ set the location.
+
+ DS is the single declarator specifier to set which location is to
+ be set onto the existing sequence of declarators.
+
+ LOCATION is the location for the declarator specifier to
+ consider. */
+
+static void
+set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
+ cp_decl_spec ds, source_location location)
+{
+ gcc_assert (ds < ds_last);
+
+ if (decl_specs == NULL)
+ return;
+
+ if (decl_specs->locations[ds] == 0)
+ decl_specs->locations[ds] = location;
+ else
+ {
+ if (ds == ds_long)
+ {
+ if (decl_specs->locations[ds_long_long] != 0)
+ error_at (location,
+ "%<long long long%> is too long for GCC");
+ else
+ {
+ decl_specs->locations[ds_long_long] = location;
+ pedwarn_cxx98 (location,
+ OPT_Wlong_long,
+ "ISO C++ 1998 does not support %<long long%>");
+ }
+ }
+ else
+ {
+ static const char *const decl_spec_names[] = {
+ "signed",
+ "unsigned",
+ "short",
+ "long",
+ "const",
+ "volatile",
+ "restrict",
+ "inline",
+ "virtual",
+ "explicit",
+ "friend",
+ "typedef",
+ "using",
+ "constexpr",
+ "__complex",
+ "__thread"
+ };
+ error_at (location,
+ "duplicate %qs", decl_spec_names[ds]);
+ }
}
}
+/* Return true iff the declarator specifier DS is present in the
+ sequence of declarator specifiers DECL_SPECS. */
+
+bool
+decl_spec_seq_has_spec_p (const cp_decl_specifier_seq * decl_specs,
+ cp_decl_spec ds)
+{
+ gcc_assert (ds < ds_last);
+
+ if (decl_specs == NULL)
+ return false;
+
+ return decl_specs->locations[ds] != 0;
+}
+
/* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */
static bool
cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers)
{
- return decl_specifiers->specs[(int) ds_friend] != 0;
+ return decl_spec_seq_has_spec_p (decl_specifiers, ds_friend);
}
/* Issue an error message indicating that TOKEN_DESC was expected.
@@ -23951,17 +24002,17 @@ cp_parser_objc_class_ivars (cp_parser* parser)
}
/* __thread. */
- if (declspecs.specs[(int) ds_thread])
+ if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
{
cp_parser_error (parser, "invalid type for instance variable");
- declspecs.specs[(int) ds_thread] = 0;
+ declspecs.locations[ds_thread] = 0;
}
/* typedef. */
- if (declspecs.specs[(int) ds_typedef])
+ if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef))
{
cp_parser_error (parser, "invalid type for instance variable");
- declspecs.specs[(int) ds_typedef] = 0;
+ declspecs.locations[ds_thread] = 0;
}
prefix_attributes = declspecs.attributes;
@@ -24530,17 +24581,17 @@ cp_parser_objc_struct_declaration (cp_parser *parser)
}
/* __thread. */
- if (declspecs.specs[(int) ds_thread])
+ if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
{
cp_parser_error (parser, "invalid type for property");
- declspecs.specs[(int) ds_thread] = 0;
+ declspecs.locations[ds_thread] = 0;
}
/* typedef. */
- if (declspecs.specs[(int) ds_typedef])
+ if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef))
{
cp_parser_error (parser, "invalid type for property");
- declspecs.specs[(int) ds_typedef] = 0;
+ declspecs.locations[ds_typedef] = 0;
}
prefix_attributes = declspecs.attributes;