1 | /* Parser for C and Objective-C. |
2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
3 | |
4 | Parser actions based on the old Bison parser; structure somewhat |
5 | influenced by and fragments based on the C++ parser. |
6 | |
7 | This file is part of GCC. |
8 | |
9 | GCC is free software; you can redistribute it and/or modify it under |
10 | the terms of the GNU General Public License as published by the Free |
11 | Software Foundation; either version 3, or (at your option) any later |
12 | version. |
13 | |
14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
17 | for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with GCC; see the file COPYING3. If not see |
21 | <http://www.gnu.org/licenses/>. */ |
22 | |
23 | /* TODO: |
24 | |
25 | Make sure all relevant comments, and all relevant code from all |
26 | actions, brought over from old parser. Verify exact correspondence |
27 | of syntax accepted. |
28 | |
29 | Add testcases covering every input symbol in every state in old and |
30 | new parsers. |
31 | |
32 | Include full syntax for GNU C, including erroneous cases accepted |
33 | with error messages, in syntax productions in comments. |
34 | |
35 | Make more diagnostics in the front end generally take an explicit |
36 | location rather than implicitly using input_location. */ |
37 | |
38 | #include "config.h" |
39 | #define INCLUDE_MEMORY |
40 | #include "system.h" |
41 | #include "coretypes.h" |
42 | #include "target.h" |
43 | #include "function.h" |
44 | #include "c-tree.h" |
45 | #include "timevar.h" |
46 | #include "stringpool.h" |
47 | #include "cgraph.h" |
48 | #include "attribs.h" |
49 | #include "stor-layout.h" |
50 | #include "varasm.h" |
51 | #include "trans-mem.h" |
52 | #include "c-family/c-pragma.h" |
53 | #include "c-lang.h" |
54 | #include "c-family/c-objc.h" |
55 | #include "plugin.h" |
56 | #include "omp-general.h" |
57 | #include "omp-offload.h" |
58 | #include "builtins.h" |
59 | #include "gomp-constants.h" |
60 | #include "c-family/c-indentation.h" |
61 | #include "gimple-expr.h" |
62 | #include "context.h" |
63 | #include "gcc-rich-location.h" |
64 | #include "c-parser.h" |
65 | #include "gimple-parser.h" |
66 | #include "read-rtl-function.h" |
67 | #include "run-rtl-passes.h" |
68 | #include "intl.h" |
69 | #include "c-family/name-hint.h" |
70 | #include "tree-iterator.h" |
71 | #include "tree-pretty-print.h" |
72 | #include "memmodel.h" |
73 | #include "c-family/known-headers.h" |
74 | #include "bitmap.h" |
75 | #include "analyzer/analyzer-language.h" |
76 | #include "toplev.h" |
77 | |
78 | /* We need to walk over decls with incomplete struct/union/enum types |
79 | after parsing the whole translation unit. |
80 | In finish_decl(), if the decl is static, has incomplete |
81 | struct/union/enum type, it is appended to incomplete_record_decls. |
82 | In c_parser_translation_unit(), we iterate over incomplete_record_decls |
83 | and report error if any of the decls are still incomplete. */ |
84 | |
85 | vec<tree> incomplete_record_decls; |
86 | |
87 | void |
88 | set_c_expr_source_range (c_expr *expr, |
89 | location_t start, location_t finish) |
90 | { |
91 | expr->src_range.m_start = start; |
92 | expr->src_range.m_finish = finish; |
93 | if (expr->value) |
94 | set_source_range (expr: expr->value, start, finish); |
95 | } |
96 | |
97 | void |
98 | set_c_expr_source_range (c_expr *expr, |
99 | source_range src_range) |
100 | { |
101 | expr->src_range = src_range; |
102 | if (expr->value) |
103 | set_source_range (expr: expr->value, src_range); |
104 | } |
105 | |
106 | |
107 | /* Initialization routine for this file. */ |
108 | |
109 | void |
110 | c_parse_init (void) |
111 | { |
112 | /* The only initialization required is of the reserved word |
113 | identifiers. */ |
114 | unsigned int i; |
115 | tree id; |
116 | int mask = 0; |
117 | |
118 | /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in |
119 | the c_token structure. */ |
120 | gcc_assert (RID_MAX <= 255); |
121 | |
122 | mask |= D_CXXONLY; |
123 | if (!flag_isoc99) |
124 | mask |= D_C99; |
125 | if (!flag_isoc23) |
126 | mask |= D_C23; |
127 | if (flag_no_asm) |
128 | { |
129 | mask |= D_ASM | D_EXT; |
130 | if (!flag_isoc99) |
131 | mask |= D_EXT89; |
132 | if (!flag_isoc23) |
133 | mask |= D_EXT11; |
134 | } |
135 | if (!c_dialect_objc ()) |
136 | mask |= D_OBJC | D_CXX_OBJC; |
137 | |
138 | ridpointers = ggc_cleared_vec_alloc<tree> (c: (int) RID_MAX); |
139 | for (i = 0; i < num_c_common_reswords; i++) |
140 | { |
141 | /* If a keyword is disabled, do not enter it into the table |
142 | and so create a canonical spelling that isn't a keyword. */ |
143 | if (c_common_reswords[i].disable & mask) |
144 | { |
145 | if (warn_cxx_compat |
146 | && (c_common_reswords[i].disable & D_CXXWARN)) |
147 | { |
148 | id = get_identifier (c_common_reswords[i].word); |
149 | C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN); |
150 | C_IS_RESERVED_WORD (id) = 1; |
151 | } |
152 | continue; |
153 | } |
154 | |
155 | id = get_identifier (c_common_reswords[i].word); |
156 | C_SET_RID_CODE (id, c_common_reswords[i].rid); |
157 | C_IS_RESERVED_WORD (id) = 1; |
158 | ridpointers [(int) c_common_reswords[i].rid] = id; |
159 | } |
160 | |
161 | for (i = 0; i < NUM_INT_N_ENTS; i++) |
162 | { |
163 | /* We always create the symbols but they aren't always supported. */ |
164 | char name[50]; |
165 | sprintf (s: name, format: "__int%d" , int_n_data[i].bitsize); |
166 | id = get_identifier (name); |
167 | C_SET_RID_CODE (id, RID_FIRST_INT_N + i); |
168 | C_IS_RESERVED_WORD (id) = 1; |
169 | |
170 | sprintf (s: name, format: "__int%d__" , int_n_data[i].bitsize); |
171 | id = get_identifier (name); |
172 | C_SET_RID_CODE (id, RID_FIRST_INT_N + i); |
173 | C_IS_RESERVED_WORD (id) = 1; |
174 | } |
175 | |
176 | if (flag_openmp) |
177 | { |
178 | id = get_identifier ("omp_all_memory" ); |
179 | C_SET_RID_CODE (id, RID_OMP_ALL_MEMORY); |
180 | C_IS_RESERVED_WORD (id) = 1; |
181 | ridpointers [RID_OMP_ALL_MEMORY] = id; |
182 | } |
183 | } |
184 | |
185 | /* A parser structure recording information about the state and |
186 | context of parsing. Includes lexer information with up to two |
187 | tokens of look-ahead; more are not needed for C. */ |
188 | struct GTY(()) c_parser { |
189 | /* The look-ahead tokens. */ |
190 | c_token * GTY((skip)) tokens; |
191 | /* Buffer for look-ahead tokens. */ |
192 | c_token tokens_buf[4]; |
193 | /* How many look-ahead tokens are available (0 - 4, or |
194 | more if parsing from pre-lexed tokens). */ |
195 | unsigned int tokens_avail; |
196 | /* Raw look-ahead tokens, used only for checking in Objective-C |
197 | whether '[[' starts attributes. */ |
198 | vec<c_token, va_gc> *raw_tokens; |
199 | /* The number of raw look-ahead tokens that have since been fully |
200 | lexed. */ |
201 | unsigned int raw_tokens_used; |
202 | /* True if a syntax error is being recovered from; false otherwise. |
203 | c_parser_error sets this flag. It should clear this flag when |
204 | enough tokens have been consumed to recover from the error. */ |
205 | BOOL_BITFIELD error : 1; |
206 | /* True if we're processing a pragma, and shouldn't automatically |
207 | consume CPP_PRAGMA_EOL. */ |
208 | BOOL_BITFIELD in_pragma : 1; |
209 | /* True if we're parsing the outermost block of an if statement. */ |
210 | BOOL_BITFIELD in_if_block : 1; |
211 | /* True if we want to lex a translated, joined string (for an |
212 | initial #pragma pch_preprocess). Otherwise the parser is |
213 | responsible for concatenating strings and translating to the |
214 | execution character set as needed. */ |
215 | BOOL_BITFIELD lex_joined_string : 1; |
216 | /* True if, when the parser is concatenating string literals, it |
217 | should translate them to the execution character set (false |
218 | inside attributes). */ |
219 | BOOL_BITFIELD translate_strings_p : 1; |
220 | |
221 | /* Objective-C specific parser/lexer information. */ |
222 | |
223 | /* True if we are in a context where the Objective-C "PQ" keywords |
224 | are considered keywords. */ |
225 | BOOL_BITFIELD objc_pq_context : 1; |
226 | /* True if we are parsing a (potential) Objective-C foreach |
227 | statement. This is set to true after we parsed 'for (' and while |
228 | we wait for 'in' or ';' to decide if it's a standard C for loop or an |
229 | Objective-C foreach loop. */ |
230 | BOOL_BITFIELD objc_could_be_foreach_context : 1; |
231 | /* The following flag is needed to contextualize Objective-C lexical |
232 | analysis. In some cases (e.g., 'int NSObject;'), it is |
233 | undesirable to bind an identifier to an Objective-C class, even |
234 | if a class with that name exists. */ |
235 | BOOL_BITFIELD objc_need_raw_identifier : 1; |
236 | /* Nonzero if we're processing a __transaction statement. The value |
237 | is 1 | TM_STMT_ATTR_*. */ |
238 | unsigned int in_transaction : 4; |
239 | /* True if we are in a context where the Objective-C "Property attribute" |
240 | keywords are valid. */ |
241 | BOOL_BITFIELD objc_property_attr_context : 1; |
242 | |
243 | /* Whether we have just seen/constructed a string-literal. Set when |
244 | returning a string-literal from c_parser_string_literal. Reset |
245 | in consume_token. Useful when we get a parse error and see an |
246 | unknown token, which could have been a string-literal constant |
247 | macro. */ |
248 | BOOL_BITFIELD seen_string_literal : 1; |
249 | |
250 | /* TRUE if omp::directive, omp::decl or omp::sequence attributes may not |
251 | appear. */ |
252 | BOOL_BITFIELD omp_attrs_forbidden_p : 1; |
253 | |
254 | /* Location of the last consumed token. */ |
255 | location_t last_token_location; |
256 | |
257 | /* Holds state for parsing collapsed OMP_FOR loops. Managed by |
258 | c_parser_omp_for_loop. */ |
259 | struct omp_for_parse_data * GTY((skip)) omp_for_parse_state; |
260 | |
261 | /* If we're in the context of OpenMP directives written as C23 |
262 | attributes turned into pragma, vector of tokens created from that, |
263 | otherwise NULL. */ |
264 | vec<c_token, va_gc> *in_omp_attribute_pragma; |
265 | |
266 | /* Set for omp::decl attribute parsing to the decl to which it |
267 | appertains. */ |
268 | tree in_omp_decl_attribute; |
269 | }; |
270 | |
271 | /* Return a pointer to the Nth token in PARSERs tokens_buf. */ |
272 | |
273 | c_token * |
274 | c_parser_tokens_buf (c_parser *parser, unsigned n) |
275 | { |
276 | return &parser->tokens_buf[n]; |
277 | } |
278 | |
279 | /* Return the error state of PARSER. */ |
280 | |
281 | bool |
282 | c_parser_error (c_parser *parser) |
283 | { |
284 | return parser->error; |
285 | } |
286 | |
287 | /* Set the error state of PARSER to ERR. */ |
288 | |
289 | void |
290 | c_parser_set_error (c_parser *parser, bool err) |
291 | { |
292 | parser->error = err; |
293 | } |
294 | |
295 | |
296 | /* The actual parser and external interface. ??? Does this need to be |
297 | garbage-collected? */ |
298 | |
299 | static GTY (()) c_parser *the_parser; |
300 | |
301 | /* Read in and lex a single token, storing it in *TOKEN. If RAW, |
302 | context-sensitive postprocessing of the token is not done. */ |
303 | |
304 | static void |
305 | c_lex_one_token (c_parser *parser, c_token *token, bool raw = false) |
306 | { |
307 | timevar_push (tv: TV_LEX); |
308 | |
309 | if (raw || vec_safe_length (v: parser->raw_tokens) == 0) |
310 | { |
311 | token->type = c_lex_with_flags (&token->value, &token->location, |
312 | &token->flags, |
313 | (parser->lex_joined_string |
314 | ? 0 : C_LEX_STRING_NO_JOIN)); |
315 | token->id_kind = C_ID_NONE; |
316 | token->keyword = RID_MAX; |
317 | token->pragma_kind = PRAGMA_NONE; |
318 | } |
319 | else |
320 | { |
321 | /* Use a token previously lexed as a raw look-ahead token, and |
322 | complete the processing on it. */ |
323 | *token = (*parser->raw_tokens)[parser->raw_tokens_used]; |
324 | ++parser->raw_tokens_used; |
325 | if (parser->raw_tokens_used == vec_safe_length (v: parser->raw_tokens)) |
326 | { |
327 | vec_free (v&: parser->raw_tokens); |
328 | parser->raw_tokens_used = 0; |
329 | } |
330 | } |
331 | |
332 | if (raw) |
333 | goto out; |
334 | |
335 | switch (token->type) |
336 | { |
337 | case CPP_NAME: |
338 | { |
339 | tree decl; |
340 | |
341 | bool objc_force_identifier = parser->objc_need_raw_identifier; |
342 | if (c_dialect_objc ()) |
343 | parser->objc_need_raw_identifier = false; |
344 | |
345 | if (C_IS_RESERVED_WORD (token->value)) |
346 | { |
347 | enum rid rid_code = C_RID_CODE (token->value); |
348 | |
349 | if (rid_code == RID_CXX_COMPAT_WARN) |
350 | { |
351 | warning_at (token->location, |
352 | OPT_Wc___compat, |
353 | "identifier %qE conflicts with C++ keyword" , |
354 | token->value); |
355 | } |
356 | else if (rid_code >= RID_FIRST_ADDR_SPACE |
357 | && rid_code <= RID_LAST_ADDR_SPACE) |
358 | { |
359 | addr_space_t as; |
360 | as = (addr_space_t) (rid_code - RID_FIRST_ADDR_SPACE); |
361 | targetm.addr_space.diagnose_usage (as, token->location); |
362 | token->id_kind = C_ID_ADDRSPACE; |
363 | token->keyword = rid_code; |
364 | break; |
365 | } |
366 | else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code)) |
367 | { |
368 | /* We found an Objective-C "pq" keyword (in, out, |
369 | inout, bycopy, byref, oneway). They need special |
370 | care because the interpretation depends on the |
371 | context. */ |
372 | if (parser->objc_pq_context) |
373 | { |
374 | token->type = CPP_KEYWORD; |
375 | token->keyword = rid_code; |
376 | break; |
377 | } |
378 | else if (parser->objc_could_be_foreach_context |
379 | && rid_code == RID_IN) |
380 | { |
381 | /* We are in Objective-C, inside a (potential) |
382 | foreach context (which means after having |
383 | parsed 'for (', but before having parsed ';'), |
384 | and we found 'in'. We consider it the keyword |
385 | which terminates the declaration at the |
386 | beginning of a foreach-statement. Note that |
387 | this means you can't use 'in' for anything else |
388 | in that context; in particular, in Objective-C |
389 | you can't use 'in' as the name of the running |
390 | variable in a C for loop. We could potentially |
391 | try to add code here to disambiguate, but it |
392 | seems a reasonable limitation. */ |
393 | token->type = CPP_KEYWORD; |
394 | token->keyword = rid_code; |
395 | break; |
396 | } |
397 | /* Else, "pq" keywords outside of the "pq" context are |
398 | not keywords, and we fall through to the code for |
399 | normal tokens. */ |
400 | } |
401 | else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code)) |
402 | { |
403 | /* We found an Objective-C "property attribute" |
404 | keyword (getter, setter, readonly, etc). These are |
405 | only valid in the property context. */ |
406 | if (parser->objc_property_attr_context) |
407 | { |
408 | token->type = CPP_KEYWORD; |
409 | token->keyword = rid_code; |
410 | break; |
411 | } |
412 | /* Else they are not special keywords. |
413 | */ |
414 | } |
415 | else if (c_dialect_objc () |
416 | && (OBJC_IS_AT_KEYWORD (rid_code) |
417 | || OBJC_IS_CXX_KEYWORD (rid_code))) |
418 | { |
419 | /* We found one of the Objective-C "@" keywords (defs, |
420 | selector, synchronized, etc) or one of the |
421 | Objective-C "cxx" keywords (class, private, |
422 | protected, public, try, catch, throw) without a |
423 | preceding '@' sign. Do nothing and fall through to |
424 | the code for normal tokens (in C++ we would still |
425 | consider the CXX ones keywords, but not in C). */ |
426 | ; |
427 | } |
428 | else |
429 | { |
430 | token->type = CPP_KEYWORD; |
431 | token->keyword = rid_code; |
432 | break; |
433 | } |
434 | } |
435 | |
436 | decl = lookup_name (token->value); |
437 | if (decl) |
438 | { |
439 | if (TREE_CODE (decl) == TYPE_DECL) |
440 | { |
441 | token->id_kind = C_ID_TYPENAME; |
442 | break; |
443 | } |
444 | } |
445 | else if (c_dialect_objc ()) |
446 | { |
447 | tree objc_interface_decl = objc_is_class_name (token->value); |
448 | /* Objective-C class names are in the same namespace as |
449 | variables and typedefs, and hence are shadowed by local |
450 | declarations. */ |
451 | if (objc_interface_decl |
452 | && (!objc_force_identifier || global_bindings_p ())) |
453 | { |
454 | token->value = objc_interface_decl; |
455 | token->id_kind = C_ID_CLASSNAME; |
456 | break; |
457 | } |
458 | } |
459 | token->id_kind = C_ID_ID; |
460 | } |
461 | break; |
462 | case CPP_AT_NAME: |
463 | /* This only happens in Objective-C; it must be a keyword. */ |
464 | token->type = CPP_KEYWORD; |
465 | switch (C_RID_CODE (token->value)) |
466 | { |
467 | /* Replace 'class' with '@class', 'private' with '@private', |
468 | etc. This prevents confusion with the C++ keyword |
469 | 'class', and makes the tokens consistent with other |
470 | Objective-C 'AT' keywords. For example '@class' is |
471 | reported as RID_AT_CLASS which is consistent with |
472 | '@synchronized', which is reported as |
473 | RID_AT_SYNCHRONIZED. |
474 | */ |
475 | case RID_CLASS: token->keyword = RID_AT_CLASS; break; |
476 | case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break; |
477 | case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break; |
478 | case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break; |
479 | case RID_THROW: token->keyword = RID_AT_THROW; break; |
480 | case RID_TRY: token->keyword = RID_AT_TRY; break; |
481 | case RID_CATCH: token->keyword = RID_AT_CATCH; break; |
482 | case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break; |
483 | default: token->keyword = C_RID_CODE (token->value); |
484 | } |
485 | break; |
486 | case CPP_COLON: |
487 | case CPP_COMMA: |
488 | case CPP_CLOSE_PAREN: |
489 | case CPP_SEMICOLON: |
490 | /* These tokens may affect the interpretation of any identifiers |
491 | following, if doing Objective-C. */ |
492 | if (c_dialect_objc ()) |
493 | parser->objc_need_raw_identifier = false; |
494 | break; |
495 | case CPP_PRAGMA: |
496 | /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */ |
497 | token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value); |
498 | token->value = NULL; |
499 | break; |
500 | default: |
501 | break; |
502 | } |
503 | out: |
504 | timevar_pop (tv: TV_LEX); |
505 | } |
506 | |
507 | /* Return a pointer to the next token from PARSER, reading it in if |
508 | necessary. */ |
509 | |
510 | c_token * |
511 | c_parser_peek_token (c_parser *parser) |
512 | { |
513 | if (parser->tokens_avail == 0) |
514 | { |
515 | c_lex_one_token (parser, token: &parser->tokens[0]); |
516 | parser->tokens_avail = 1; |
517 | } |
518 | return &parser->tokens[0]; |
519 | } |
520 | |
521 | /* Return a pointer to the next-but-one token from PARSER, reading it |
522 | in if necessary. The next token is already read in. */ |
523 | |
524 | c_token * |
525 | c_parser_peek_2nd_token (c_parser *parser) |
526 | { |
527 | if (parser->tokens_avail >= 2) |
528 | return &parser->tokens[1]; |
529 | gcc_assert (parser->tokens_avail == 1); |
530 | gcc_assert (parser->tokens[0].type != CPP_EOF); |
531 | gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL); |
532 | c_lex_one_token (parser, token: &parser->tokens[1]); |
533 | parser->tokens_avail = 2; |
534 | return &parser->tokens[1]; |
535 | } |
536 | |
537 | /* Return a pointer to the Nth token from PARSER, reading it |
538 | in if necessary. The N-1th token is already read in. */ |
539 | |
540 | c_token * |
541 | c_parser_peek_nth_token (c_parser *parser, unsigned int n) |
542 | { |
543 | /* N is 1-based, not zero-based. */ |
544 | gcc_assert (n > 0); |
545 | |
546 | if (parser->tokens_avail >= n) |
547 | return &parser->tokens[n - 1]; |
548 | gcc_assert (parser->tokens_avail == n - 1); |
549 | c_lex_one_token (parser, token: &parser->tokens[n - 1]); |
550 | parser->tokens_avail = n; |
551 | return &parser->tokens[n - 1]; |
552 | } |
553 | |
554 | /* Return a pointer to the Nth token from PARSER, reading it in as a |
555 | raw look-ahead token if necessary. The N-1th token is already read |
556 | in. Raw look-ahead tokens remain available for when the non-raw |
557 | functions above are called. */ |
558 | |
559 | c_token * |
560 | c_parser_peek_nth_token_raw (c_parser *parser, unsigned int n) |
561 | { |
562 | /* N is 1-based, not zero-based. */ |
563 | gcc_assert (n > 0); |
564 | |
565 | if (parser->tokens_avail >= n) |
566 | return &parser->tokens[n - 1]; |
567 | unsigned int raw_len = vec_safe_length (v: parser->raw_tokens); |
568 | unsigned int raw_avail |
569 | = parser->tokens_avail + raw_len - parser->raw_tokens_used; |
570 | gcc_assert (raw_avail >= n - 1); |
571 | if (raw_avail >= n) |
572 | return &(*parser->raw_tokens)[parser->raw_tokens_used |
573 | + n - 1 - parser->tokens_avail]; |
574 | vec_safe_reserve (v&: parser->raw_tokens, nelems: 1); |
575 | parser->raw_tokens->quick_grow (len: raw_len + 1); |
576 | c_lex_one_token (parser, token: &(*parser->raw_tokens)[raw_len], raw: true); |
577 | return &(*parser->raw_tokens)[raw_len]; |
578 | } |
579 | |
580 | bool |
581 | c_keyword_starts_typename (enum rid keyword) |
582 | { |
583 | switch (keyword) |
584 | { |
585 | case RID_UNSIGNED: |
586 | case RID_LONG: |
587 | case RID_SHORT: |
588 | case RID_SIGNED: |
589 | case RID_COMPLEX: |
590 | case RID_INT: |
591 | case RID_CHAR: |
592 | case RID_FLOAT: |
593 | case RID_DOUBLE: |
594 | case RID_VOID: |
595 | case RID_DFLOAT32: |
596 | case RID_DFLOAT64: |
597 | case RID_DFLOAT128: |
598 | CASE_RID_FLOATN_NX: |
599 | case RID_BOOL: |
600 | case RID_BITINT: |
601 | case RID_ENUM: |
602 | case RID_STRUCT: |
603 | case RID_UNION: |
604 | case RID_TYPEOF: |
605 | case RID_TYPEOF_UNQUAL: |
606 | case RID_CONST: |
607 | case RID_ATOMIC: |
608 | case RID_VOLATILE: |
609 | case RID_RESTRICT: |
610 | case RID_ATTRIBUTE: |
611 | case RID_FRACT: |
612 | case RID_ACCUM: |
613 | case RID_SAT: |
614 | case RID_AUTO_TYPE: |
615 | case RID_ALIGNAS: |
616 | return true; |
617 | default: |
618 | if (keyword >= RID_FIRST_INT_N |
619 | && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS |
620 | && int_n_enabled_p[keyword - RID_FIRST_INT_N]) |
621 | return true; |
622 | return false; |
623 | } |
624 | } |
625 | |
626 | /* Return true if TOKEN can start a type name, |
627 | false otherwise. */ |
628 | bool |
629 | c_token_starts_typename (c_token *token) |
630 | { |
631 | switch (token->type) |
632 | { |
633 | case CPP_NAME: |
634 | switch (token->id_kind) |
635 | { |
636 | case C_ID_ID: |
637 | return false; |
638 | case C_ID_ADDRSPACE: |
639 | return true; |
640 | case C_ID_TYPENAME: |
641 | return true; |
642 | case C_ID_CLASSNAME: |
643 | gcc_assert (c_dialect_objc ()); |
644 | return true; |
645 | default: |
646 | gcc_unreachable (); |
647 | } |
648 | case CPP_KEYWORD: |
649 | return c_keyword_starts_typename (keyword: token->keyword); |
650 | case CPP_LESS: |
651 | if (c_dialect_objc ()) |
652 | return true; |
653 | return false; |
654 | default: |
655 | return false; |
656 | } |
657 | } |
658 | |
659 | /* Return true if the next token from PARSER can start a type name, |
660 | false otherwise. LA specifies how to do lookahead in order to |
661 | detect unknown type names. If unsure, pick CLA_PREFER_ID. */ |
662 | |
663 | static inline bool |
664 | c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) |
665 | { |
666 | c_token *token = c_parser_peek_token (parser); |
667 | if (c_token_starts_typename (token)) |
668 | return true; |
669 | |
670 | /* Try a bit harder to detect an unknown typename. */ |
671 | if (la != cla_prefer_id |
672 | && token->type == CPP_NAME |
673 | && token->id_kind == C_ID_ID |
674 | |
675 | /* Do not try too hard when we could have "object in array". */ |
676 | && !parser->objc_could_be_foreach_context |
677 | |
678 | && (la == cla_prefer_type |
679 | || c_parser_peek_2nd_token (parser)->type == CPP_NAME |
680 | || c_parser_peek_2nd_token (parser)->type == CPP_MULT) |
681 | |
682 | /* Only unknown identifiers. */ |
683 | && !lookup_name (token->value)) |
684 | return true; |
685 | |
686 | return false; |
687 | } |
688 | |
689 | /* Return true if TOKEN, after an open parenthesis, can start a |
690 | compound literal (either a storage class specifier allowed in that |
691 | context, or a type name), false otherwise. */ |
692 | static bool |
693 | c_token_starts_compound_literal (c_token *token) |
694 | { |
695 | switch (token->type) |
696 | { |
697 | case CPP_KEYWORD: |
698 | switch (token->keyword) |
699 | { |
700 | case RID_CONSTEXPR: |
701 | case RID_REGISTER: |
702 | case RID_STATIC: |
703 | case RID_THREAD: |
704 | return true; |
705 | default: |
706 | break; |
707 | } |
708 | /* Fall through. */ |
709 | default: |
710 | return c_token_starts_typename (token); |
711 | } |
712 | } |
713 | |
714 | /* Return true if TOKEN is a type qualifier, false otherwise. */ |
715 | static bool |
716 | c_token_is_qualifier (c_token *token) |
717 | { |
718 | switch (token->type) |
719 | { |
720 | case CPP_NAME: |
721 | switch (token->id_kind) |
722 | { |
723 | case C_ID_ADDRSPACE: |
724 | return true; |
725 | default: |
726 | return false; |
727 | } |
728 | case CPP_KEYWORD: |
729 | switch (token->keyword) |
730 | { |
731 | case RID_CONST: |
732 | case RID_VOLATILE: |
733 | case RID_RESTRICT: |
734 | case RID_ATTRIBUTE: |
735 | case RID_ATOMIC: |
736 | return true; |
737 | default: |
738 | return false; |
739 | } |
740 | case CPP_LESS: |
741 | return false; |
742 | default: |
743 | gcc_unreachable (); |
744 | } |
745 | } |
746 | |
747 | /* Return true if the next token from PARSER is a type qualifier, |
748 | false otherwise. */ |
749 | static inline bool |
750 | c_parser_next_token_is_qualifier (c_parser *parser) |
751 | { |
752 | c_token *token = c_parser_peek_token (parser); |
753 | return c_token_is_qualifier (token); |
754 | } |
755 | |
756 | /* Return true if TOKEN can start declaration specifiers (not |
757 | including standard attributes), false otherwise. */ |
758 | static bool |
759 | c_token_starts_declspecs (c_token *token) |
760 | { |
761 | switch (token->type) |
762 | { |
763 | case CPP_NAME: |
764 | switch (token->id_kind) |
765 | { |
766 | case C_ID_ID: |
767 | return false; |
768 | case C_ID_ADDRSPACE: |
769 | return true; |
770 | case C_ID_TYPENAME: |
771 | return true; |
772 | case C_ID_CLASSNAME: |
773 | gcc_assert (c_dialect_objc ()); |
774 | return true; |
775 | default: |
776 | gcc_unreachable (); |
777 | } |
778 | case CPP_KEYWORD: |
779 | switch (token->keyword) |
780 | { |
781 | case RID_STATIC: |
782 | case RID_EXTERN: |
783 | case RID_REGISTER: |
784 | case RID_TYPEDEF: |
785 | case RID_INLINE: |
786 | case RID_NORETURN: |
787 | case RID_AUTO: |
788 | case RID_THREAD: |
789 | case RID_UNSIGNED: |
790 | case RID_LONG: |
791 | case RID_SHORT: |
792 | case RID_SIGNED: |
793 | case RID_COMPLEX: |
794 | case RID_INT: |
795 | case RID_CHAR: |
796 | case RID_FLOAT: |
797 | case RID_DOUBLE: |
798 | case RID_VOID: |
799 | case RID_DFLOAT32: |
800 | case RID_DFLOAT64: |
801 | case RID_DFLOAT128: |
802 | CASE_RID_FLOATN_NX: |
803 | case RID_BOOL: |
804 | case RID_BITINT: |
805 | case RID_ENUM: |
806 | case RID_STRUCT: |
807 | case RID_UNION: |
808 | case RID_TYPEOF: |
809 | case RID_TYPEOF_UNQUAL: |
810 | case RID_CONST: |
811 | case RID_VOLATILE: |
812 | case RID_RESTRICT: |
813 | case RID_ATTRIBUTE: |
814 | case RID_FRACT: |
815 | case RID_ACCUM: |
816 | case RID_SAT: |
817 | case RID_ALIGNAS: |
818 | case RID_ATOMIC: |
819 | case RID_AUTO_TYPE: |
820 | case RID_CONSTEXPR: |
821 | return true; |
822 | default: |
823 | if (token->keyword >= RID_FIRST_INT_N |
824 | && token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS |
825 | && int_n_enabled_p[token->keyword - RID_FIRST_INT_N]) |
826 | return true; |
827 | return false; |
828 | } |
829 | case CPP_LESS: |
830 | if (c_dialect_objc ()) |
831 | return true; |
832 | return false; |
833 | default: |
834 | return false; |
835 | } |
836 | } |
837 | |
838 | |
839 | /* Return true if TOKEN can start declaration specifiers (not |
840 | including standard attributes) or a static assertion, false |
841 | otherwise. */ |
842 | static bool |
843 | c_token_starts_declaration (c_token *token) |
844 | { |
845 | if (c_token_starts_declspecs (token) |
846 | || token->keyword == RID_STATIC_ASSERT) |
847 | return true; |
848 | else |
849 | return false; |
850 | } |
851 | |
852 | /* Return true if the next token from PARSER can start declaration |
853 | specifiers (not including standard attributes), false |
854 | otherwise. */ |
855 | bool |
856 | c_parser_next_token_starts_declspecs (c_parser *parser) |
857 | { |
858 | c_token *token = c_parser_peek_token (parser); |
859 | |
860 | /* In Objective-C, a classname normally starts a declspecs unless it |
861 | is immediately followed by a dot. In that case, it is the |
862 | Objective-C 2.0 "dot-syntax" for class objects, ie, calls the |
863 | setter/getter on the class. c_token_starts_declspecs() can't |
864 | differentiate between the two cases because it only checks the |
865 | current token, so we have a special check here. */ |
866 | if (c_dialect_objc () |
867 | && token->type == CPP_NAME |
868 | && token->id_kind == C_ID_CLASSNAME |
869 | && c_parser_peek_2nd_token (parser)->type == CPP_DOT) |
870 | return false; |
871 | |
872 | return c_token_starts_declspecs (token); |
873 | } |
874 | |
875 | /* Return true if the next tokens from PARSER can start declaration |
876 | specifiers (not including standard attributes) or a static |
877 | assertion, false otherwise. */ |
878 | bool |
879 | c_parser_next_tokens_start_declaration (c_parser *parser) |
880 | { |
881 | c_token *token = c_parser_peek_token (parser); |
882 | |
883 | /* Same as above. */ |
884 | if (c_dialect_objc () |
885 | && token->type == CPP_NAME |
886 | && token->id_kind == C_ID_CLASSNAME |
887 | && c_parser_peek_2nd_token (parser)->type == CPP_DOT) |
888 | return false; |
889 | |
890 | /* Labels do not start declarations. */ |
891 | if (token->type == CPP_NAME |
892 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
893 | return false; |
894 | |
895 | if (c_token_starts_declaration (token)) |
896 | return true; |
897 | |
898 | if (c_parser_next_tokens_start_typename (parser, la: cla_nonabstract_decl)) |
899 | return true; |
900 | |
901 | return false; |
902 | } |
903 | |
904 | /* Consume the next token from PARSER. */ |
905 | |
906 | void |
907 | c_parser_consume_token (c_parser *parser) |
908 | { |
909 | gcc_assert (parser->tokens_avail >= 1); |
910 | gcc_assert (parser->tokens[0].type != CPP_EOF); |
911 | gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); |
912 | gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); |
913 | parser->last_token_location = parser->tokens[0].location; |
914 | if (parser->tokens != &parser->tokens_buf[0]) |
915 | parser->tokens++; |
916 | else if (parser->tokens_avail >= 2) |
917 | { |
918 | parser->tokens[0] = parser->tokens[1]; |
919 | if (parser->tokens_avail >= 3) |
920 | { |
921 | parser->tokens[1] = parser->tokens[2]; |
922 | if (parser->tokens_avail >= 4) |
923 | parser->tokens[2] = parser->tokens[3]; |
924 | } |
925 | } |
926 | parser->tokens_avail--; |
927 | parser->seen_string_literal = false; |
928 | } |
929 | |
930 | /* Expect the current token to be a #pragma. Consume it and remember |
931 | that we've begun parsing a pragma. */ |
932 | |
933 | static void |
934 | c_parser_consume_pragma (c_parser *parser) |
935 | { |
936 | gcc_assert (!parser->in_pragma); |
937 | gcc_assert (parser->tokens_avail >= 1); |
938 | gcc_assert (parser->tokens[0].type == CPP_PRAGMA); |
939 | if (parser->tokens != &parser->tokens_buf[0]) |
940 | parser->tokens++; |
941 | else if (parser->tokens_avail >= 2) |
942 | { |
943 | parser->tokens[0] = parser->tokens[1]; |
944 | if (parser->tokens_avail >= 3) |
945 | parser->tokens[1] = parser->tokens[2]; |
946 | } |
947 | parser->tokens_avail--; |
948 | parser->in_pragma = true; |
949 | } |
950 | |
951 | /* Update the global input_location from TOKEN. */ |
952 | static inline void |
953 | c_parser_set_source_position_from_token (c_token *token) |
954 | { |
955 | if (token->type != CPP_EOF) |
956 | { |
957 | input_location = token->location; |
958 | } |
959 | } |
960 | |
961 | /* Helper function for c_parser_error. |
962 | Having peeked a token of kind TOK1_KIND that might signify |
963 | a conflict marker, peek successor tokens to determine |
964 | if we actually do have a conflict marker. |
965 | Specifically, we consider a run of 7 '<', '=' or '>' characters |
966 | at the start of a line as a conflict marker. |
967 | These come through the lexer as three pairs and a single, |
968 | e.g. three CPP_LSHIFT ("<<") and a CPP_LESS ('<'). |
969 | If it returns true, *OUT_LOC is written to with the location/range |
970 | of the marker. */ |
971 | |
972 | static bool |
973 | c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind, |
974 | location_t *out_loc) |
975 | { |
976 | c_token *token2 = c_parser_peek_2nd_token (parser); |
977 | if (token2->type != tok1_kind) |
978 | return false; |
979 | c_token *token3 = c_parser_peek_nth_token (parser, n: 3); |
980 | if (token3->type != tok1_kind) |
981 | return false; |
982 | c_token *token4 = c_parser_peek_nth_token (parser, n: 4); |
983 | if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind)) |
984 | return false; |
985 | |
986 | /* It must be at the start of the line. */ |
987 | location_t start_loc = c_parser_peek_token (parser)->location; |
988 | if (LOCATION_COLUMN (start_loc) != 1) |
989 | return false; |
990 | |
991 | /* We have a conflict marker. Construct a location of the form: |
992 | <<<<<<< |
993 | ^~~~~~~ |
994 | with start == caret, finishing at the end of the marker. */ |
995 | location_t finish_loc = get_finish (loc: token4->location); |
996 | *out_loc = make_location (caret: start_loc, start: start_loc, finish: finish_loc); |
997 | |
998 | return true; |
999 | } |
1000 | |
1001 | /* Issue a diagnostic of the form |
1002 | FILE:LINE: MESSAGE before TOKEN |
1003 | where TOKEN is the next token in the input stream of PARSER. |
1004 | MESSAGE (specified by the caller) is usually of the form "expected |
1005 | OTHER-TOKEN". |
1006 | |
1007 | Use RICHLOC as the location of the diagnostic. |
1008 | |
1009 | Do not issue a diagnostic if still recovering from an error. |
1010 | |
1011 | Return true iff an error was actually emitted. |
1012 | |
1013 | ??? This is taken from the C++ parser, but building up messages in |
1014 | this way is not i18n-friendly and some other approach should be |
1015 | used. */ |
1016 | |
1017 | static bool |
1018 | c_parser_error_richloc (c_parser *parser, const char *gmsgid, |
1019 | rich_location *richloc) |
1020 | { |
1021 | c_token *token = c_parser_peek_token (parser); |
1022 | if (parser->error) |
1023 | return false; |
1024 | parser->error = true; |
1025 | if (!gmsgid) |
1026 | return false; |
1027 | |
1028 | /* If this is actually a conflict marker, report it as such. */ |
1029 | if (token->type == CPP_LSHIFT |
1030 | || token->type == CPP_RSHIFT |
1031 | || token->type == CPP_EQ_EQ) |
1032 | { |
1033 | location_t loc; |
1034 | if (c_parser_peek_conflict_marker (parser, tok1_kind: token->type, out_loc: &loc)) |
1035 | { |
1036 | error_at (loc, "version control conflict marker in file" ); |
1037 | return true; |
1038 | } |
1039 | } |
1040 | |
1041 | /* If we were parsing a string-literal and there is an unknown name |
1042 | token right after, then check to see if that could also have been |
1043 | a literal string by checking the name against a list of known |
1044 | standard string literal constants defined in header files. If |
1045 | there is one, then add that as an hint to the error message. */ |
1046 | auto_diagnostic_group d; |
1047 | name_hint h; |
1048 | if (parser->seen_string_literal && token->type == CPP_NAME) |
1049 | { |
1050 | tree name = token->value; |
1051 | const char *token_name = IDENTIFIER_POINTER (name); |
1052 | const char * |
1053 | = get_c_stdlib_header_for_string_macro_name (n: token_name); |
1054 | if (header_hint != NULL) |
1055 | h = name_hint (NULL, new suggest_missing_header (token->location, |
1056 | token_name, |
1057 | header_hint)); |
1058 | } |
1059 | |
1060 | c_parse_error (gmsgid, |
1061 | /* Because c_parse_error does not understand |
1062 | CPP_KEYWORD, keywords are treated like |
1063 | identifiers. */ |
1064 | (token->type == CPP_KEYWORD ? CPP_NAME : token->type), |
1065 | /* ??? The C parser does not save the cpp flags of a |
1066 | token, we need to pass 0 here and we will not get |
1067 | the source spelling of some tokens but rather the |
1068 | canonical spelling. */ |
1069 | token->value, /*flags=*/0, richloc); |
1070 | return true; |
1071 | } |
1072 | |
1073 | /* As c_parser_error_richloc, but issue the message at the |
1074 | location of PARSER's next token, or at input_location |
1075 | if the next token is EOF. */ |
1076 | |
1077 | bool |
1078 | c_parser_error (c_parser *parser, const char *gmsgid) |
1079 | { |
1080 | c_token *token = c_parser_peek_token (parser); |
1081 | c_parser_set_source_position_from_token (token); |
1082 | rich_location richloc (line_table, input_location); |
1083 | return c_parser_error_richloc (parser, gmsgid, richloc: &richloc); |
1084 | } |
1085 | |
1086 | /* Some tokens naturally come in pairs e.g.'(' and ')'. |
1087 | This class is for tracking such a matching pair of symbols. |
1088 | In particular, it tracks the location of the first token, |
1089 | so that if the second token is missing, we can highlight the |
1090 | location of the first token when notifying the user about the |
1091 | problem. */ |
1092 | |
1093 | template <typename traits_t> |
1094 | class token_pair |
1095 | { |
1096 | public: |
1097 | /* token_pair's ctor. */ |
1098 | token_pair () : m_open_loc (UNKNOWN_LOCATION) {} |
1099 | |
1100 | /* If the next token is the opening symbol for this pair, consume it and |
1101 | return true. |
1102 | Otherwise, issue an error and return false. |
1103 | In either case, record the location of the opening token. */ |
1104 | |
1105 | bool require_open (c_parser *parser) |
1106 | { |
1107 | c_token *token = c_parser_peek_token (parser); |
1108 | if (token) |
1109 | m_open_loc = token->location; |
1110 | |
1111 | return c_parser_require (parser, traits_t::open_token_type, |
1112 | traits_t::open_gmsgid); |
1113 | } |
1114 | |
1115 | /* Consume the next token from PARSER, recording its location as |
1116 | that of the opening token within the pair. */ |
1117 | |
1118 | void consume_open (c_parser *parser) |
1119 | { |
1120 | c_token *token = c_parser_peek_token (parser); |
1121 | gcc_assert (token->type == traits_t::open_token_type); |
1122 | m_open_loc = token->location; |
1123 | c_parser_consume_token (parser); |
1124 | } |
1125 | |
1126 | /* If the next token is the closing symbol for this pair, consume it |
1127 | and return true. |
1128 | Otherwise, issue an error, highlighting the location of the |
1129 | corresponding opening token, and return false. */ |
1130 | |
1131 | bool require_close (c_parser *parser) const |
1132 | { |
1133 | return c_parser_require (parser, traits_t::close_token_type, |
1134 | traits_t::close_gmsgid, m_open_loc); |
1135 | } |
1136 | |
1137 | /* Like token_pair::require_close, except that tokens will be skipped |
1138 | until the desired token is found. An error message is still produced |
1139 | if the next token is not as expected. */ |
1140 | |
1141 | void skip_until_found_close (c_parser *parser) const |
1142 | { |
1143 | c_parser_skip_until_found (parser, traits_t::close_token_type, |
1144 | traits_t::close_gmsgid, m_open_loc); |
1145 | } |
1146 | |
1147 | private: |
1148 | location_t m_open_loc; |
1149 | }; |
1150 | |
1151 | /* Traits for token_pair<T> for tracking matching pairs of parentheses. */ |
1152 | |
1153 | struct matching_paren_traits |
1154 | { |
1155 | static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN; |
1156 | static const char * const open_gmsgid; |
1157 | static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN; |
1158 | static const char * const close_gmsgid; |
1159 | }; |
1160 | |
1161 | const char * const matching_paren_traits::open_gmsgid = "expected %<(%>" ; |
1162 | const char * const matching_paren_traits::close_gmsgid = "expected %<)%>" ; |
1163 | |
1164 | /* "matching_parens" is a token_pair<T> class for tracking matching |
1165 | pairs of parentheses. */ |
1166 | |
1167 | typedef token_pair<matching_paren_traits> matching_parens; |
1168 | |
1169 | /* Traits for token_pair<T> for tracking matching pairs of braces. */ |
1170 | |
1171 | struct matching_brace_traits |
1172 | { |
1173 | static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE; |
1174 | static const char * const open_gmsgid; |
1175 | static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE; |
1176 | static const char * const close_gmsgid; |
1177 | }; |
1178 | |
1179 | const char * const matching_brace_traits::open_gmsgid = "expected %<{%>" ; |
1180 | const char * const matching_brace_traits::close_gmsgid = "expected %<}%>" ; |
1181 | |
1182 | /* "matching_braces" is a token_pair<T> class for tracking matching |
1183 | pairs of braces. */ |
1184 | |
1185 | typedef token_pair<matching_brace_traits> matching_braces; |
1186 | |
1187 | /* Get a description of the matching symbol to TYPE e.g. "(" for |
1188 | CPP_CLOSE_PAREN. */ |
1189 | |
1190 | static const char * |
1191 | get_matching_symbol (enum cpp_ttype type) |
1192 | { |
1193 | switch (type) |
1194 | { |
1195 | default: |
1196 | gcc_unreachable (); |
1197 | case CPP_CLOSE_PAREN: |
1198 | return "(" ; |
1199 | case CPP_CLOSE_BRACE: |
1200 | return "{" ; |
1201 | } |
1202 | } |
1203 | |
1204 | /* If the next token is of the indicated TYPE, consume it. Otherwise, |
1205 | issue the error MSGID. If MSGID is NULL then a message has already |
1206 | been produced and no message will be produced this time. Returns |
1207 | true if found, false otherwise. |
1208 | |
1209 | If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it |
1210 | within any error as the location of an "opening" token matching |
1211 | the close token TYPE (e.g. the location of the '(' when TYPE is |
1212 | CPP_CLOSE_PAREN). |
1213 | |
1214 | If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly |
1215 | one type (e.g. "expected %<)%>") and thus it may be reasonable to |
1216 | attempt to generate a fix-it hint for the problem. |
1217 | Otherwise msgid describes multiple token types (e.g. |
1218 | "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to |
1219 | generate a fix-it hint. */ |
1220 | |
1221 | bool |
1222 | c_parser_require (c_parser *parser, |
1223 | enum cpp_ttype type, |
1224 | const char *msgid, |
1225 | location_t matching_location, |
1226 | bool type_is_unique) |
1227 | { |
1228 | if (c_parser_next_token_is (parser, type)) |
1229 | { |
1230 | c_parser_consume_token (parser); |
1231 | return true; |
1232 | } |
1233 | else |
1234 | { |
1235 | location_t next_token_loc = c_parser_peek_token (parser)->location; |
1236 | gcc_rich_location richloc (next_token_loc); |
1237 | |
1238 | /* Potentially supply a fix-it hint, suggesting to add the |
1239 | missing token immediately after the *previous* token. |
1240 | This may move the primary location within richloc. */ |
1241 | if (!parser->error && type_is_unique) |
1242 | maybe_suggest_missing_token_insertion (richloc: &richloc, token_type: type, |
1243 | prev_token_loc: parser->last_token_location); |
1244 | |
1245 | /* If matching_location != UNKNOWN_LOCATION, highlight it. |
1246 | Attempt to consolidate diagnostics by printing it as a |
1247 | secondary range within the main diagnostic. */ |
1248 | bool added_matching_location = false; |
1249 | if (matching_location != UNKNOWN_LOCATION) |
1250 | added_matching_location |
1251 | = richloc.add_location_if_nearby (loc: matching_location); |
1252 | |
1253 | if (c_parser_error_richloc (parser, gmsgid: msgid, richloc: &richloc)) |
1254 | /* If we weren't able to consolidate matching_location, then |
1255 | print it as a secondary diagnostic. */ |
1256 | if (matching_location != UNKNOWN_LOCATION && !added_matching_location) |
1257 | inform (matching_location, "to match this %qs" , |
1258 | get_matching_symbol (type)); |
1259 | |
1260 | return false; |
1261 | } |
1262 | } |
1263 | |
1264 | /* If the next token is the indicated keyword, consume it. Otherwise, |
1265 | issue the error MSGID. Returns true if found, false otherwise. */ |
1266 | |
1267 | static bool |
1268 | c_parser_require_keyword (c_parser *parser, |
1269 | enum rid keyword, |
1270 | const char *msgid) |
1271 | { |
1272 | if (c_parser_next_token_is_keyword (parser, keyword)) |
1273 | { |
1274 | c_parser_consume_token (parser); |
1275 | return true; |
1276 | } |
1277 | else |
1278 | { |
1279 | c_parser_error (parser, gmsgid: msgid); |
1280 | return false; |
1281 | } |
1282 | } |
1283 | |
1284 | /* Like c_parser_require, except that tokens will be skipped until the |
1285 | desired token is found. An error message is still produced if the |
1286 | next token is not as expected. If MSGID is NULL then a message has |
1287 | already been produced and no message will be produced this |
1288 | time. |
1289 | |
1290 | If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it |
1291 | within any error as the location of an "opening" token matching |
1292 | the close token TYPE (e.g. the location of the '(' when TYPE is |
1293 | CPP_CLOSE_PAREN). */ |
1294 | |
1295 | void |
1296 | c_parser_skip_until_found (c_parser *parser, |
1297 | enum cpp_ttype type, |
1298 | const char *msgid, |
1299 | location_t matching_location) |
1300 | { |
1301 | unsigned nesting_depth = 0; |
1302 | |
1303 | if (c_parser_require (parser, type, msgid, matching_location)) |
1304 | { |
1305 | if (UNLIKELY (type == CPP_PRAGMA_EOL) && parser->in_omp_attribute_pragma) |
1306 | { |
1307 | c_token *token = c_parser_peek_token (parser); |
1308 | if (token->type == CPP_EOF) |
1309 | { |
1310 | parser->tokens = &parser->tokens_buf[0]; |
1311 | parser->tokens_avail = token->flags; |
1312 | parser->in_omp_attribute_pragma = NULL; |
1313 | } |
1314 | } |
1315 | return; |
1316 | } |
1317 | |
1318 | /* Skip tokens until the desired token is found. */ |
1319 | while (true) |
1320 | { |
1321 | /* Peek at the next token. */ |
1322 | c_token *token = c_parser_peek_token (parser); |
1323 | /* If we've reached the token we want, consume it and stop. */ |
1324 | if (token->type == type && !nesting_depth) |
1325 | { |
1326 | c_parser_consume_token (parser); |
1327 | if (UNLIKELY (type == CPP_PRAGMA_EOL) |
1328 | && parser->in_omp_attribute_pragma) |
1329 | { |
1330 | c_token *token = c_parser_peek_token (parser); |
1331 | if (token->type == CPP_EOF) |
1332 | { |
1333 | parser->tokens = &parser->tokens_buf[0]; |
1334 | parser->tokens_avail = token->flags; |
1335 | parser->in_omp_attribute_pragma = NULL; |
1336 | } |
1337 | } |
1338 | break; |
1339 | } |
1340 | |
1341 | /* If we've run out of tokens, stop. */ |
1342 | if (token->type == CPP_EOF) |
1343 | return; |
1344 | if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) |
1345 | return; |
1346 | if (token->type == CPP_OPEN_BRACE |
1347 | || token->type == CPP_OPEN_PAREN |
1348 | || token->type == CPP_OPEN_SQUARE) |
1349 | ++nesting_depth; |
1350 | else if (token->type == CPP_CLOSE_BRACE |
1351 | || token->type == CPP_CLOSE_PAREN |
1352 | || token->type == CPP_CLOSE_SQUARE) |
1353 | { |
1354 | if (nesting_depth-- == 0) |
1355 | break; |
1356 | } |
1357 | /* Consume this token. */ |
1358 | c_parser_consume_token (parser); |
1359 | } |
1360 | parser->error = false; |
1361 | } |
1362 | |
1363 | /* Skip tokens until the end of a parameter is found, but do not |
1364 | consume the comma, semicolon or closing delimiter. */ |
1365 | |
1366 | static void |
1367 | c_parser_skip_to_end_of_parameter (c_parser *parser) |
1368 | { |
1369 | unsigned nesting_depth = 0; |
1370 | |
1371 | while (true) |
1372 | { |
1373 | c_token *token = c_parser_peek_token (parser); |
1374 | if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON) |
1375 | && !nesting_depth) |
1376 | break; |
1377 | /* If we've run out of tokens, stop. */ |
1378 | if (token->type == CPP_EOF) |
1379 | return; |
1380 | if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) |
1381 | return; |
1382 | if (token->type == CPP_OPEN_BRACE |
1383 | || token->type == CPP_OPEN_PAREN |
1384 | || token->type == CPP_OPEN_SQUARE) |
1385 | ++nesting_depth; |
1386 | else if (token->type == CPP_CLOSE_BRACE |
1387 | || token->type == CPP_CLOSE_PAREN |
1388 | || token->type == CPP_CLOSE_SQUARE) |
1389 | { |
1390 | if (nesting_depth-- == 0) |
1391 | break; |
1392 | } |
1393 | /* Consume this token. */ |
1394 | c_parser_consume_token (parser); |
1395 | } |
1396 | parser->error = false; |
1397 | } |
1398 | |
1399 | /* Expect to be at the end of the pragma directive and consume an |
1400 | end of line marker. */ |
1401 | |
1402 | static void |
1403 | c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true) |
1404 | { |
1405 | gcc_assert (parser->in_pragma); |
1406 | parser->in_pragma = false; |
1407 | |
1408 | if (error_if_not_eol && c_parser_peek_token (parser)->type != CPP_PRAGMA_EOL) |
1409 | c_parser_error (parser, gmsgid: "expected end of line" ); |
1410 | |
1411 | cpp_ttype token_type; |
1412 | do |
1413 | { |
1414 | c_token *token = c_parser_peek_token (parser); |
1415 | token_type = token->type; |
1416 | if (token_type == CPP_EOF) |
1417 | break; |
1418 | c_parser_consume_token (parser); |
1419 | } |
1420 | while (token_type != CPP_PRAGMA_EOL); |
1421 | |
1422 | if (parser->in_omp_attribute_pragma) |
1423 | { |
1424 | c_token *token = c_parser_peek_token (parser); |
1425 | if (token->type == CPP_EOF) |
1426 | { |
1427 | parser->tokens = &parser->tokens_buf[0]; |
1428 | parser->tokens_avail = token->flags; |
1429 | parser->in_omp_attribute_pragma = NULL; |
1430 | } |
1431 | } |
1432 | |
1433 | parser->error = false; |
1434 | } |
1435 | |
1436 | /* Skip tokens until we have consumed an entire block, or until we |
1437 | have consumed a non-nested ';'. */ |
1438 | |
1439 | static void |
1440 | c_parser_skip_to_end_of_block_or_statement (c_parser *parser) |
1441 | { |
1442 | unsigned nesting_depth = 0; |
1443 | bool save_error = parser->error; |
1444 | |
1445 | while (true) |
1446 | { |
1447 | c_token *token; |
1448 | |
1449 | /* Peek at the next token. */ |
1450 | token = c_parser_peek_token (parser); |
1451 | |
1452 | switch (token->type) |
1453 | { |
1454 | case CPP_EOF: |
1455 | return; |
1456 | |
1457 | case CPP_PRAGMA_EOL: |
1458 | if (parser->in_pragma) |
1459 | return; |
1460 | break; |
1461 | |
1462 | case CPP_SEMICOLON: |
1463 | /* If the next token is a ';', we have reached the |
1464 | end of the statement. */ |
1465 | if (!nesting_depth) |
1466 | { |
1467 | /* Consume the ';'. */ |
1468 | c_parser_consume_token (parser); |
1469 | goto finished; |
1470 | } |
1471 | break; |
1472 | |
1473 | case CPP_CLOSE_BRACE: |
1474 | /* If the next token is a non-nested '}', then we have |
1475 | reached the end of the current block. */ |
1476 | if (nesting_depth == 0 || --nesting_depth == 0) |
1477 | { |
1478 | c_parser_consume_token (parser); |
1479 | goto finished; |
1480 | } |
1481 | break; |
1482 | |
1483 | case CPP_OPEN_BRACE: |
1484 | /* If it the next token is a '{', then we are entering a new |
1485 | block. Consume the entire block. */ |
1486 | ++nesting_depth; |
1487 | break; |
1488 | |
1489 | case CPP_PRAGMA: |
1490 | /* If we see a pragma, consume the whole thing at once. We |
1491 | have some safeguards against consuming pragmas willy-nilly. |
1492 | Normally, we'd expect to be here with parser->error set, |
1493 | which disables these safeguards. But it's possible to get |
1494 | here for secondary error recovery, after parser->error has |
1495 | been cleared. */ |
1496 | c_parser_consume_pragma (parser); |
1497 | c_parser_skip_to_pragma_eol (parser); |
1498 | parser->error = save_error; |
1499 | continue; |
1500 | |
1501 | default: |
1502 | break; |
1503 | } |
1504 | |
1505 | c_parser_consume_token (parser); |
1506 | } |
1507 | |
1508 | finished: |
1509 | parser->error = false; |
1510 | } |
1511 | |
1512 | /* CPP's options (initialized by c-opts.cc). */ |
1513 | extern cpp_options *cpp_opts; |
1514 | |
1515 | /* Save the warning flags which are controlled by __extension__. */ |
1516 | |
1517 | static inline int |
1518 | disable_extension_diagnostics (void) |
1519 | { |
1520 | int ret = (pedantic |
1521 | | (warn_pointer_arith << 1) |
1522 | | (warn_traditional << 2) |
1523 | | (flag_iso << 3) |
1524 | | (warn_long_long << 4) |
1525 | | (warn_cxx_compat << 5) |
1526 | | (warn_overlength_strings << 6) |
1527 | /* warn_c90_c99_compat has three states: -1/0/1, so we must |
1528 | play tricks to properly restore it. */ |
1529 | | ((warn_c90_c99_compat == 1) << 7) |
1530 | | ((warn_c90_c99_compat == -1) << 8) |
1531 | /* Similarly for warn_c99_c11_compat. */ |
1532 | | ((warn_c99_c11_compat == 1) << 9) |
1533 | | ((warn_c99_c11_compat == -1) << 10) |
1534 | /* Similarly for warn_c11_c23_compat. */ |
1535 | | ((warn_c11_c23_compat == 1) << 11) |
1536 | | ((warn_c11_c23_compat == -1) << 12) |
1537 | ); |
1538 | cpp_opts->cpp_pedantic = pedantic = 0; |
1539 | warn_pointer_arith = 0; |
1540 | cpp_opts->cpp_warn_traditional = warn_traditional = 0; |
1541 | flag_iso = 0; |
1542 | cpp_opts->cpp_warn_long_long = warn_long_long = 0; |
1543 | warn_cxx_compat = 0; |
1544 | warn_overlength_strings = 0; |
1545 | warn_c90_c99_compat = 0; |
1546 | warn_c99_c11_compat = 0; |
1547 | warn_c11_c23_compat = 0; |
1548 | return ret; |
1549 | } |
1550 | |
1551 | /* Restore the warning flags which are controlled by __extension__. |
1552 | FLAGS is the return value from disable_extension_diagnostics. */ |
1553 | |
1554 | static inline void |
1555 | restore_extension_diagnostics (int flags) |
1556 | { |
1557 | cpp_opts->cpp_pedantic = pedantic = flags & 1; |
1558 | warn_pointer_arith = (flags >> 1) & 1; |
1559 | cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1; |
1560 | flag_iso = (flags >> 3) & 1; |
1561 | cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1; |
1562 | warn_cxx_compat = (flags >> 5) & 1; |
1563 | warn_overlength_strings = (flags >> 6) & 1; |
1564 | /* See above for why is this needed. */ |
1565 | warn_c90_c99_compat = (flags >> 7) & 1 ? 1 : ((flags >> 8) & 1 ? -1 : 0); |
1566 | warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0); |
1567 | warn_c11_c23_compat = (flags >> 11) & 1 ? 1 : ((flags >> 12) & 1 ? -1 : 0); |
1568 | } |
1569 | |
1570 | /* Helper data structure for parsing #pragma acc routine. */ |
1571 | struct oacc_routine_data { |
1572 | bool error_seen; /* Set if error has been reported. */ |
1573 | bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ |
1574 | tree clauses; |
1575 | location_t loc; |
1576 | }; |
1577 | |
1578 | /* Used for parsing objc foreach statements. */ |
1579 | static tree objc_foreach_break_label, objc_foreach_continue_label; |
1580 | |
1581 | /* Used for parsing OMP for loops. |
1582 | |
1583 | Some notes on flags used for context: |
1584 | parser->omp_for_parse_state is non-null anywhere inside the OMP FOR |
1585 | construct, except for the final-loop-body. |
1586 | The want_nested_loop flag is true if inside a {} sequence where |
1587 | a loop-nest (or another {} sequence containing a loop-nest) is expected, |
1588 | but has not yet been seen. It's false when parsing intervening code |
1589 | statements or their substatements that cannot contain a loop-nest. |
1590 | The in_intervening_code flag is true when parsing any intervening code, |
1591 | including substatements, and whether or not want_nested_loop is true. |
1592 | |
1593 | And, about error handling: |
1594 | The saw_intervening_code flag is set if the loop is not perfectly |
1595 | nested, even in the usual case where this is not an error. |
1596 | perfect_nesting_fail is set if an error has been diagnosed because an |
1597 | imperfectly-nested loop was found where a perfectly-nested one is |
1598 | required (we diagnose this only once). |
1599 | fail is set if any kind of structural error in the loop nest |
1600 | has been found and diagnosed. |
1601 | */ |
1602 | struct omp_for_parse_data { |
1603 | enum tree_code code; |
1604 | tree declv, condv, incrv, initv; |
1605 | tree pre_body; |
1606 | tree bindings; |
1607 | int count; /* Expected nesting depth. */ |
1608 | int depth; /* Current nesting depth. */ |
1609 | location_t for_loc; |
1610 | bool ordered : 1; |
1611 | bool inscan : 1; |
1612 | bool want_nested_loop : 1; |
1613 | bool in_intervening_code : 1; |
1614 | bool saw_intervening_code: 1; |
1615 | bool perfect_nesting_fail : 1; |
1616 | bool fail : 1; |
1617 | }; |
1618 | |
1619 | static bool c_parser_nth_token_starts_std_attributes (c_parser *, |
1620 | unsigned int); |
1621 | static tree c_parser_std_attribute_specifier_sequence (c_parser *); |
1622 | static void c_parser_external_declaration (c_parser *); |
1623 | static void c_parser_asm_definition (c_parser *); |
1624 | static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, |
1625 | bool, bool, tree * = NULL, |
1626 | vec<c_token> * = NULL, |
1627 | bool have_attrs = false, |
1628 | tree attrs = NULL, |
1629 | struct oacc_routine_data * = NULL, |
1630 | bool * = NULL); |
1631 | static bool c_parser_handle_statement_omp_attributes (c_parser *, tree &, |
1632 | bool *); |
1633 | static void c_parser_static_assert_declaration_no_semi (c_parser *); |
1634 | static void c_parser_static_assert_declaration (c_parser *); |
1635 | static struct c_typespec c_parser_enum_specifier (c_parser *); |
1636 | static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); |
1637 | static tree c_parser_struct_declaration (c_parser *, tree *); |
1638 | static struct c_typespec c_parser_typeof_specifier (c_parser *); |
1639 | static tree c_parser_alignas_specifier (c_parser *); |
1640 | static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, |
1641 | c_dtr_syn, bool *); |
1642 | static struct c_declarator *c_parser_direct_declarator_inner (c_parser *, |
1643 | bool, |
1644 | struct c_declarator *); |
1645 | static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree, |
1646 | bool); |
1647 | static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree, |
1648 | tree, bool); |
1649 | static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool); |
1650 | static tree c_parser_simple_asm_expr (c_parser *); |
1651 | static tree c_parser_gnu_attributes (c_parser *); |
1652 | static struct c_expr c_parser_initializer (c_parser *, tree); |
1653 | static struct c_expr c_parser_braced_init (c_parser *, tree, bool, |
1654 | struct obstack *, tree); |
1655 | static void c_parser_initelt (c_parser *, struct obstack *); |
1656 | static void c_parser_initval (c_parser *, struct c_expr *, |
1657 | struct obstack *); |
1658 | static tree c_parser_compound_statement (c_parser *, location_t * = NULL); |
1659 | static location_t c_parser_compound_statement_nostart (c_parser *); |
1660 | static void c_parser_label (c_parser *, tree); |
1661 | static void c_parser_statement (c_parser *, bool *, location_t * = NULL); |
1662 | static void c_parser_statement_after_labels (c_parser *, bool *, |
1663 | vec<tree> * = NULL); |
1664 | static tree c_parser_c99_block_statement (c_parser *, bool *, |
1665 | location_t * = NULL); |
1666 | static void c_parser_if_statement (c_parser *, bool *, vec<tree> *); |
1667 | static void c_parser_switch_statement (c_parser *, bool *); |
1668 | static void c_parser_while_statement (c_parser *, bool, unsigned short, bool, |
1669 | bool *); |
1670 | static void c_parser_do_statement (c_parser *, bool, unsigned short, bool); |
1671 | static void c_parser_for_statement (c_parser *, bool, unsigned short, bool, |
1672 | bool *); |
1673 | static tree c_parser_asm_statement (c_parser *); |
1674 | static tree c_parser_asm_operands (c_parser *); |
1675 | static tree c_parser_asm_goto_operands (c_parser *); |
1676 | static tree c_parser_asm_clobbers (c_parser *); |
1677 | static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *, |
1678 | tree = NULL_TREE); |
1679 | static struct c_expr c_parser_conditional_expression (c_parser *, |
1680 | struct c_expr *, tree); |
1681 | static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, |
1682 | tree); |
1683 | static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); |
1684 | static struct c_expr c_parser_unary_expression (c_parser *); |
1685 | static struct c_expr c_parser_sizeof_expression (c_parser *); |
1686 | static struct c_expr c_parser_alignof_expression (c_parser *); |
1687 | static struct c_expr c_parser_postfix_expression (c_parser *); |
1688 | static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, |
1689 | struct c_declspecs *, |
1690 | struct c_type_name *, |
1691 | location_t); |
1692 | static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, |
1693 | location_t loc, |
1694 | struct c_expr); |
1695 | static tree c_parser_transaction (c_parser *, enum rid); |
1696 | static struct c_expr c_parser_transaction_expression (c_parser *, enum rid); |
1697 | static tree c_parser_transaction_cancel (c_parser *); |
1698 | static struct c_expr c_parser_expression (c_parser *); |
1699 | static struct c_expr c_parser_expression_conv (c_parser *); |
1700 | static vec<tree, va_gc> *c_parser_expr_list (c_parser *, bool, bool, |
1701 | vec<tree, va_gc> **, location_t *, |
1702 | tree *, vec<location_t> *, |
1703 | unsigned int * = NULL); |
1704 | static struct c_expr c_parser_has_attribute_expression (c_parser *); |
1705 | |
1706 | static void c_parser_oacc_declare (c_parser *); |
1707 | static void c_parser_oacc_enter_exit_data (c_parser *, bool); |
1708 | static void c_parser_oacc_update (c_parser *); |
1709 | static void c_parser_omp_construct (c_parser *, bool *); |
1710 | static void c_parser_omp_threadprivate (c_parser *); |
1711 | static void c_parser_omp_barrier (c_parser *); |
1712 | static void c_parser_omp_depobj (c_parser *); |
1713 | static void c_parser_omp_flush (c_parser *); |
1714 | static tree c_parser_omp_loop_nest (c_parser *, bool *); |
1715 | static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, |
1716 | tree, tree *, bool *); |
1717 | static void c_parser_omp_taskwait (c_parser *); |
1718 | static void c_parser_omp_taskyield (c_parser *); |
1719 | static void c_parser_omp_cancel (c_parser *); |
1720 | static void c_parser_omp_nothing (c_parser *); |
1721 | |
1722 | enum pragma_context { pragma_external, pragma_struct, pragma_param, |
1723 | pragma_stmt, pragma_compound }; |
1724 | static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); |
1725 | static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); |
1726 | static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); |
1727 | static void c_parser_omp_begin (c_parser *); |
1728 | static void c_parser_omp_end (c_parser *); |
1729 | static bool c_parser_omp_declare (c_parser *, enum pragma_context); |
1730 | static void c_parser_omp_requires (c_parser *); |
1731 | static bool c_parser_omp_error (c_parser *, enum pragma_context); |
1732 | static void c_parser_omp_assumption_clauses (c_parser *, bool); |
1733 | static void c_parser_omp_allocate (c_parser *); |
1734 | static void c_parser_omp_assumes (c_parser *); |
1735 | static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); |
1736 | static void c_parser_oacc_routine (c_parser *, enum pragma_context); |
1737 | |
1738 | /* These Objective-C parser functions are only ever called when |
1739 | compiling Objective-C. */ |
1740 | static void c_parser_objc_class_definition (c_parser *, tree); |
1741 | static void c_parser_objc_class_instance_variables (c_parser *); |
1742 | static void c_parser_objc_class_declaration (c_parser *); |
1743 | static void c_parser_objc_alias_declaration (c_parser *); |
1744 | static void c_parser_objc_protocol_definition (c_parser *, tree); |
1745 | static bool c_parser_objc_method_type (c_parser *); |
1746 | static void c_parser_objc_method_definition (c_parser *); |
1747 | static void c_parser_objc_methodprotolist (c_parser *); |
1748 | static void c_parser_objc_methodproto (c_parser *); |
1749 | static tree c_parser_objc_method_decl (c_parser *, bool, tree *, tree *); |
1750 | static tree c_parser_objc_type_name (c_parser *); |
1751 | static tree c_parser_objc_protocol_refs (c_parser *); |
1752 | static void c_parser_objc_try_catch_finally_statement (c_parser *); |
1753 | static void c_parser_objc_synchronized_statement (c_parser *); |
1754 | static tree c_parser_objc_selector (c_parser *); |
1755 | static tree c_parser_objc_selector_arg (c_parser *); |
1756 | static tree c_parser_objc_receiver (c_parser *); |
1757 | static tree c_parser_objc_message_args (c_parser *); |
1758 | static tree c_parser_objc_keywordexpr (c_parser *); |
1759 | static void c_parser_objc_at_property_declaration (c_parser *); |
1760 | static void c_parser_objc_at_synthesize_declaration (c_parser *); |
1761 | static void c_parser_objc_at_dynamic_declaration (c_parser *); |
1762 | static bool c_parser_objc_diagnose_bad_element_prefix |
1763 | (c_parser *, struct c_declspecs *); |
1764 | static location_t c_parser_parse_rtl_body (c_parser *, char *); |
1765 | |
1766 | #if ENABLE_ANALYZER |
1767 | |
1768 | namespace ana { |
1769 | |
1770 | /* Concrete implementation of ana::translation_unit for the C frontend. */ |
1771 | |
1772 | class c_translation_unit : public translation_unit |
1773 | { |
1774 | public: |
1775 | /* Implementation of translation_unit::lookup_constant_by_id for use by the |
1776 | analyzer to look up named constants in the user's source code. */ |
1777 | tree lookup_constant_by_id (tree id) const final override |
1778 | { |
1779 | /* Consider decls. */ |
1780 | if (tree decl = lookup_name (id)) |
1781 | if (TREE_CODE (decl) == CONST_DECL) |
1782 | if (tree value = DECL_INITIAL (decl)) |
1783 | if (TREE_CODE (value) == INTEGER_CST) |
1784 | return value; |
1785 | |
1786 | /* Consider macros. */ |
1787 | cpp_hashnode *hashnode = C_CPP_HASHNODE (id); |
1788 | if (cpp_macro_p (node: hashnode)) |
1789 | if (tree value = consider_macro (macro: hashnode->value.macro)) |
1790 | return value; |
1791 | |
1792 | return NULL_TREE; |
1793 | } |
1794 | |
1795 | tree |
1796 | lookup_type_by_id (tree id) const final override |
1797 | { |
1798 | if (tree type_decl = lookup_name (id)) |
1799 | if (TREE_CODE (type_decl) == TYPE_DECL) |
1800 | { |
1801 | tree record_type = TREE_TYPE (type_decl); |
1802 | if (TREE_CODE (record_type) == RECORD_TYPE) |
1803 | return record_type; |
1804 | } |
1805 | |
1806 | return NULL_TREE; |
1807 | } |
1808 | |
1809 | tree |
1810 | lookup_global_var_by_id (tree id) const final override |
1811 | { |
1812 | if (tree var_decl = lookup_name (id)) |
1813 | if (TREE_CODE (var_decl) == VAR_DECL) |
1814 | return var_decl; |
1815 | |
1816 | return NULL_TREE; |
1817 | } |
1818 | |
1819 | private: |
1820 | /* Attempt to get an INTEGER_CST from MACRO. |
1821 | Only handle the simplest cases: where MACRO's definition is a single |
1822 | token containing a number, by lexing the number again. |
1823 | This will handle e.g. |
1824 | #define NAME 42 |
1825 | and other bases but not negative numbers, parentheses or e.g. |
1826 | #define NAME 1 << 7 |
1827 | as doing so would require a parser. */ |
1828 | tree consider_macro (cpp_macro *macro) const |
1829 | { |
1830 | if (macro->paramc > 0) |
1831 | return NULL_TREE; |
1832 | if (macro->kind != cmk_macro) |
1833 | return NULL_TREE; |
1834 | if (macro->count != 1) |
1835 | return NULL_TREE; |
1836 | const cpp_token &tok = macro->exp.tokens[0]; |
1837 | if (tok.type != CPP_NUMBER) |
1838 | return NULL_TREE; |
1839 | |
1840 | cpp_reader *old_parse_in = parse_in; |
1841 | parse_in = cpp_create_reader (CLK_GNUC89, NULL, line_table); |
1842 | |
1843 | pretty_printer pp; |
1844 | pp_string (&pp, (const char *) tok.val.str.text); |
1845 | pp_newline (&pp); |
1846 | cpp_push_buffer (parse_in, |
1847 | (const unsigned char *) pp_formatted_text (&pp), |
1848 | strlen (s: pp_formatted_text (&pp)), |
1849 | 0); |
1850 | |
1851 | tree value; |
1852 | location_t loc; |
1853 | unsigned char cpp_flags; |
1854 | c_lex_with_flags (&value, &loc, &cpp_flags, 0); |
1855 | |
1856 | cpp_destroy (parse_in); |
1857 | parse_in = old_parse_in; |
1858 | |
1859 | if (value && TREE_CODE (value) == INTEGER_CST) |
1860 | return value; |
1861 | |
1862 | return NULL_TREE; |
1863 | } |
1864 | }; |
1865 | |
1866 | } // namespace ana |
1867 | |
1868 | #endif /* #if ENABLE_ANALYZER */ |
1869 | |
1870 | /* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). |
1871 | |
1872 | translation-unit: |
1873 | external-declarations |
1874 | |
1875 | external-declarations: |
1876 | external-declaration |
1877 | external-declarations external-declaration |
1878 | |
1879 | GNU extensions: |
1880 | |
1881 | translation-unit: |
1882 | empty |
1883 | */ |
1884 | |
1885 | static void |
1886 | c_parser_translation_unit (c_parser *parser) |
1887 | { |
1888 | if (c_parser_next_token_is (parser, type: CPP_EOF)) |
1889 | { |
1890 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
1891 | "ISO C forbids an empty translation unit" ); |
1892 | } |
1893 | else |
1894 | { |
1895 | void *obstack_position = obstack_alloc (&parser_obstack, 0); |
1896 | mark_valid_location_for_stdc_pragma (false); |
1897 | do |
1898 | { |
1899 | ggc_collect (); |
1900 | c_parser_external_declaration (parser); |
1901 | obstack_free (&parser_obstack, obstack_position); |
1902 | } |
1903 | while (c_parser_next_token_is_not (parser, type: CPP_EOF)); |
1904 | } |
1905 | |
1906 | unsigned int i; |
1907 | tree decl; |
1908 | FOR_EACH_VEC_ELT (incomplete_record_decls, i, decl) |
1909 | if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node) |
1910 | error ("storage size of %q+D isn%'t known" , decl); |
1911 | |
1912 | if (vec_safe_length (v: current_omp_declare_target_attribute)) |
1913 | { |
1914 | c_omp_declare_target_attr |
1915 | a = current_omp_declare_target_attribute->pop (); |
1916 | if (!errorcount) |
1917 | error ("%qs without corresponding %qs" , |
1918 | a.device_type >= 0 ? "#pragma omp begin declare target" |
1919 | : "#pragma omp declare target" , |
1920 | "#pragma omp end declare target" ); |
1921 | vec_safe_truncate (v: current_omp_declare_target_attribute, size: 0); |
1922 | } |
1923 | if (vec_safe_length (v: current_omp_begin_assumes)) |
1924 | { |
1925 | if (!errorcount) |
1926 | error ("%qs without corresponding %qs" , |
1927 | "#pragma omp begin assumes" , "#pragma omp end assumes" ); |
1928 | vec_safe_truncate (v: current_omp_begin_assumes, size: 0); |
1929 | } |
1930 | |
1931 | #if ENABLE_ANALYZER |
1932 | if (flag_analyzer) |
1933 | { |
1934 | ana::c_translation_unit tu; |
1935 | ana::on_finish_translation_unit (tu); |
1936 | } |
1937 | #endif |
1938 | } |
1939 | |
1940 | /* Parse an external declaration (C90 6.7, C99 6.9, C11 6.9). |
1941 | |
1942 | external-declaration: |
1943 | function-definition |
1944 | declaration |
1945 | |
1946 | GNU extensions: |
1947 | |
1948 | external-declaration: |
1949 | asm-definition |
1950 | ; |
1951 | __extension__ external-declaration |
1952 | |
1953 | Objective-C: |
1954 | |
1955 | external-declaration: |
1956 | objc-class-definition |
1957 | objc-class-declaration |
1958 | objc-alias-declaration |
1959 | objc-protocol-definition |
1960 | objc-method-definition |
1961 | @end |
1962 | */ |
1963 | |
1964 | static void |
1965 | c_parser_external_declaration (c_parser *parser) |
1966 | { |
1967 | int ext; |
1968 | switch (c_parser_peek_token (parser)->type) |
1969 | { |
1970 | case CPP_KEYWORD: |
1971 | switch (c_parser_peek_token (parser)->keyword) |
1972 | { |
1973 | case RID_EXTENSION: |
1974 | ext = disable_extension_diagnostics (); |
1975 | c_parser_consume_token (parser); |
1976 | c_parser_external_declaration (parser); |
1977 | restore_extension_diagnostics (flags: ext); |
1978 | break; |
1979 | case RID_ASM: |
1980 | c_parser_asm_definition (parser); |
1981 | break; |
1982 | case RID_AT_INTERFACE: |
1983 | case RID_AT_IMPLEMENTATION: |
1984 | gcc_assert (c_dialect_objc ()); |
1985 | c_parser_objc_class_definition (parser, NULL_TREE); |
1986 | break; |
1987 | case RID_AT_CLASS: |
1988 | gcc_assert (c_dialect_objc ()); |
1989 | c_parser_objc_class_declaration (parser); |
1990 | break; |
1991 | case RID_AT_ALIAS: |
1992 | gcc_assert (c_dialect_objc ()); |
1993 | c_parser_objc_alias_declaration (parser); |
1994 | break; |
1995 | case RID_AT_PROTOCOL: |
1996 | gcc_assert (c_dialect_objc ()); |
1997 | c_parser_objc_protocol_definition (parser, NULL_TREE); |
1998 | break; |
1999 | case RID_AT_PROPERTY: |
2000 | gcc_assert (c_dialect_objc ()); |
2001 | c_parser_objc_at_property_declaration (parser); |
2002 | break; |
2003 | case RID_AT_SYNTHESIZE: |
2004 | gcc_assert (c_dialect_objc ()); |
2005 | c_parser_objc_at_synthesize_declaration (parser); |
2006 | break; |
2007 | case RID_AT_DYNAMIC: |
2008 | gcc_assert (c_dialect_objc ()); |
2009 | c_parser_objc_at_dynamic_declaration (parser); |
2010 | break; |
2011 | case RID_AT_END: |
2012 | gcc_assert (c_dialect_objc ()); |
2013 | c_parser_consume_token (parser); |
2014 | objc_finish_implementation (); |
2015 | break; |
2016 | default: |
2017 | goto decl_or_fndef; |
2018 | } |
2019 | break; |
2020 | case CPP_SEMICOLON: |
2021 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
2022 | "ISO C does not allow extra %<;%> outside of a function" ); |
2023 | c_parser_consume_token (parser); |
2024 | break; |
2025 | case CPP_PRAGMA: |
2026 | mark_valid_location_for_stdc_pragma (true); |
2027 | c_parser_pragma (parser, pragma_external, NULL); |
2028 | mark_valid_location_for_stdc_pragma (false); |
2029 | break; |
2030 | case CPP_PLUS: |
2031 | case CPP_MINUS: |
2032 | if (c_dialect_objc ()) |
2033 | { |
2034 | c_parser_objc_method_definition (parser); |
2035 | break; |
2036 | } |
2037 | /* Else fall through, and yield a syntax error trying to parse |
2038 | as a declaration or function definition. */ |
2039 | /* FALLTHRU */ |
2040 | default: |
2041 | decl_or_fndef: |
2042 | /* A declaration or a function definition (or, in Objective-C, |
2043 | an @interface or @protocol with prefix attributes). We can |
2044 | only tell which after parsing the declaration specifiers, if |
2045 | any, and the first declarator. */ |
2046 | c_parser_declaration_or_fndef (parser, true, true, true, false, true); |
2047 | break; |
2048 | } |
2049 | } |
2050 | |
2051 | static void c_parser_handle_directive_omp_attributes (tree &, vec<c_token> *&, |
2052 | vec<c_token> *); |
2053 | static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> *); |
2054 | static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool); |
2055 | |
2056 | /* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */ |
2057 | |
2058 | static void |
2059 | add_debug_begin_stmt (location_t loc) |
2060 | { |
2061 | /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */ |
2062 | if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ()) |
2063 | return; |
2064 | |
2065 | tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); |
2066 | SET_EXPR_LOCATION (stmt, loc); |
2067 | add_stmt (stmt); |
2068 | } |
2069 | |
2070 | /* Helper function for c_parser_declaration_or_fndef and |
2071 | Handle assume attribute(s). */ |
2072 | |
2073 | static tree |
2074 | handle_assume_attribute (location_t here, tree attrs, bool nested) |
2075 | { |
2076 | if (nested) |
2077 | for (tree attr = lookup_attribute (attr_ns: "gnu" , attr_name: "assume" , list: attrs); attr; |
2078 | attr = lookup_attribute (attr_ns: "gnu" , attr_name: "assume" , TREE_CHAIN (attr))) |
2079 | { |
2080 | tree args = TREE_VALUE (attr); |
2081 | int nargs = list_length (args); |
2082 | if (nargs != 1) |
2083 | { |
2084 | error_at (here, "wrong number of arguments specified " |
2085 | "for %qE attribute" , |
2086 | get_attribute_name (attr)); |
2087 | inform (here, "expected %i, found %i" , 1, nargs); |
2088 | } |
2089 | else |
2090 | { |
2091 | tree arg = TREE_VALUE (args); |
2092 | arg = c_objc_common_truthvalue_conversion (here, arg); |
2093 | arg = c_fully_fold (arg, false, NULL); |
2094 | if (arg != error_mark_node) |
2095 | { |
2096 | tree fn = build_call_expr_internal_loc (here, IFN_ASSUME, |
2097 | void_type_node, 1, |
2098 | arg); |
2099 | add_stmt (fn); |
2100 | } |
2101 | } |
2102 | } |
2103 | else |
2104 | pedwarn (here, OPT_Wattributes, |
2105 | "%<assume%> attribute at top level" ); |
2106 | |
2107 | return remove_attribute ("gnu" , "assume" , attrs); |
2108 | } |
2109 | |
2110 | /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 |
2111 | 6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition |
2112 | is accepted; otherwise (old-style parameter declarations) only other |
2113 | declarations are accepted. If STATIC_ASSERT_OK is true, a static |
2114 | assertion is accepted; otherwise (old-style parameter declarations) |
2115 | it is not. If NESTED is true, we are inside a function or parsing |
2116 | old-style parameter declarations; any functions encountered are |
2117 | nested functions and declaration specifiers are required; otherwise |
2118 | we are at top level and functions are normal functions and |
2119 | declaration specifiers may be optional. If EMPTY_OK is true, empty |
2120 | declarations are OK (subject to all other constraints); otherwise |
2121 | (old-style parameter declarations) they are diagnosed. If |
2122 | START_ATTR_OK is true, the declaration specifiers may start with |
2123 | attributes (GNU or standard); otherwise they may not. |
2124 | OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed |
2125 | declaration when parsing an Objective-C foreach statement. |
2126 | FALLTHRU_ATTR_P is used to signal whether this function parsed |
2127 | "__attribute__((fallthrough));". ATTRS are any standard attributes |
2128 | parsed in the caller (in contexts where such attributes had to be |
2129 | parsed to determine whether what follows is a declaration or a |
2130 | statement); HAVE_ATTRS says whether there were any such attributes |
2131 | (even empty). |
2132 | |
2133 | declaration: |
2134 | declaration-specifiers init-declarator-list[opt] ; |
2135 | static_assert-declaration |
2136 | |
2137 | function-definition: |
2138 | declaration-specifiers[opt] declarator declaration-list[opt] |
2139 | compound-statement |
2140 | |
2141 | declaration-list: |
2142 | declaration |
2143 | declaration-list declaration |
2144 | |
2145 | init-declarator-list: |
2146 | init-declarator |
2147 | init-declarator-list , init-declarator |
2148 | |
2149 | init-declarator: |
2150 | declarator simple-asm-expr[opt] gnu-attributes[opt] |
2151 | declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer |
2152 | |
2153 | GNU extensions: |
2154 | |
2155 | nested-function-definition: |
2156 | declaration-specifiers declarator declaration-list[opt] |
2157 | compound-statement |
2158 | |
2159 | attribute ; |
2160 | |
2161 | Objective-C: |
2162 | gnu-attributes objc-class-definition |
2163 | gnu-attributes objc-category-definition |
2164 | gnu-attributes objc-protocol-definition |
2165 | |
2166 | The simple-asm-expr and gnu-attributes are GNU extensions. |
2167 | |
2168 | This function does not handle __extension__; that is handled in its |
2169 | callers. ??? Following the old parser, __extension__ may start |
2170 | external declarations, declarations in functions and declarations |
2171 | at the start of "for" loops, but not old-style parameter |
2172 | declarations. |
2173 | |
2174 | C99 requires declaration specifiers in a function definition; the |
2175 | absence is diagnosed through the diagnosis of implicit int. In GNU |
2176 | C we also allow but diagnose declarations without declaration |
2177 | specifiers, but only at top level (elsewhere they conflict with |
2178 | other syntax). |
2179 | |
2180 | In Objective-C, declarations of the looping variable in a foreach |
2181 | statement are exceptionally terminated by 'in' (for example, 'for |
2182 | (NSObject *object in array) { ... }'). |
2183 | |
2184 | OpenMP: |
2185 | |
2186 | declaration: |
2187 | threadprivate-directive |
2188 | |
2189 | GIMPLE: |
2190 | |
2191 | gimple-function-definition: |
2192 | declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator |
2193 | declaration-list[opt] compound-statement |
2194 | |
2195 | rtl-function-definition: |
2196 | declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator |
2197 | declaration-list[opt] compound-statement */ |
2198 | |
2199 | static void |
2200 | c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, |
2201 | bool static_assert_ok, bool empty_ok, |
2202 | bool nested, bool start_attr_ok, |
2203 | tree *objc_foreach_object_declaration |
2204 | /* = NULL */, |
2205 | vec<c_token> *omp_declare_simd_clauses |
2206 | /* = NULL */, |
2207 | bool have_attrs /* = false */, |
2208 | tree attrs /* = NULL_TREE */, |
2209 | struct oacc_routine_data *oacc_routine_data |
2210 | /* = NULL */, |
2211 | bool *fallthru_attr_p /* = NULL */) |
2212 | { |
2213 | struct c_declspecs *specs; |
2214 | tree prefix_attrs; |
2215 | tree all_prefix_attrs; |
2216 | bool diagnosed_no_specs = false; |
2217 | location_t here = c_parser_peek_token (parser)->location; |
2218 | |
2219 | add_debug_begin_stmt (loc: c_parser_peek_token (parser)->location); |
2220 | |
2221 | if (static_assert_ok |
2222 | && c_parser_next_token_is_keyword (parser, keyword: RID_STATIC_ASSERT)) |
2223 | { |
2224 | c_parser_static_assert_declaration (parser); |
2225 | return; |
2226 | } |
2227 | specs = build_null_declspecs (); |
2228 | |
2229 | /* Handle any standard attributes parsed in the caller. */ |
2230 | if (have_attrs) |
2231 | { |
2232 | declspecs_add_attrs (here, specs, attrs); |
2233 | specs->non_std_attrs_seen_p = false; |
2234 | } |
2235 | |
2236 | /* Try to detect an unknown type name when we have "A B" or "A *B". */ |
2237 | if (c_parser_peek_token (parser)->type == CPP_NAME |
2238 | && c_parser_peek_token (parser)->id_kind == C_ID_ID |
2239 | && (c_parser_peek_2nd_token (parser)->type == CPP_NAME |
2240 | || c_parser_peek_2nd_token (parser)->type == CPP_MULT) |
2241 | && (!nested || !lookup_name (c_parser_peek_token (parser)->value))) |
2242 | { |
2243 | tree name = c_parser_peek_token (parser)->value; |
2244 | |
2245 | /* Issue a warning about NAME being an unknown type name, perhaps |
2246 | with some kind of hint. |
2247 | If the user forgot a "struct" etc, suggest inserting |
2248 | it. Otherwise, attempt to look for misspellings. */ |
2249 | gcc_rich_location richloc (here); |
2250 | if (tag_exists_p (RECORD_TYPE, name)) |
2251 | { |
2252 | /* This is not C++ with its implicit typedef. */ |
2253 | richloc.add_fixit_insert_before (new_content: "struct " ); |
2254 | error_at (&richloc, |
2255 | "unknown type name %qE;" |
2256 | " use %<struct%> keyword to refer to the type" , |
2257 | name); |
2258 | } |
2259 | else if (tag_exists_p (UNION_TYPE, name)) |
2260 | { |
2261 | richloc.add_fixit_insert_before (new_content: "union " ); |
2262 | error_at (&richloc, |
2263 | "unknown type name %qE;" |
2264 | " use %<union%> keyword to refer to the type" , |
2265 | name); |
2266 | } |
2267 | else if (tag_exists_p (ENUMERAL_TYPE, name)) |
2268 | { |
2269 | richloc.add_fixit_insert_before (new_content: "enum " ); |
2270 | error_at (&richloc, |
2271 | "unknown type name %qE;" |
2272 | " use %<enum%> keyword to refer to the type" , |
2273 | name); |
2274 | } |
2275 | else |
2276 | { |
2277 | auto_diagnostic_group d; |
2278 | name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME, |
2279 | here); |
2280 | if (const char *suggestion = hint.suggestion ()) |
2281 | { |
2282 | richloc.add_fixit_replace (new_content: suggestion); |
2283 | error_at (&richloc, |
2284 | "unknown type name %qE; did you mean %qs?" , |
2285 | name, suggestion); |
2286 | } |
2287 | else |
2288 | error_at (here, "unknown type name %qE" , name); |
2289 | } |
2290 | |
2291 | /* Parse declspecs normally to get a correct pointer type, but avoid |
2292 | a further "fails to be a type name" error. Refuse nested functions |
2293 | since it is not how the user likely wants us to recover. */ |
2294 | c_parser_peek_token (parser)->type = CPP_KEYWORD; |
2295 | c_parser_peek_token (parser)->keyword = RID_VOID; |
2296 | c_parser_peek_token (parser)->value = error_mark_node; |
2297 | fndef_ok = !nested; |
2298 | } |
2299 | |
2300 | /* When there are standard attributes at the start of the |
2301 | declaration (to apply to the entity being declared), an |
2302 | init-declarator-list or function definition must be present. */ |
2303 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
2304 | have_attrs = true; |
2305 | |
2306 | c_parser_declspecs (parser, specs, true, true, start_attr_ok, |
2307 | true, true, start_attr_ok, true, cla_nonabstract_decl); |
2308 | if (parser->error) |
2309 | { |
2310 | c_parser_skip_to_end_of_block_or_statement (parser); |
2311 | return; |
2312 | } |
2313 | if (nested && !specs->declspecs_seen_p) |
2314 | { |
2315 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
2316 | c_parser_skip_to_end_of_block_or_statement (parser); |
2317 | return; |
2318 | } |
2319 | |
2320 | finish_declspecs (specs); |
2321 | bool gnu_auto_type_p = specs->typespec_word == cts_auto_type; |
2322 | bool std_auto_type_p = specs->c23_auto_p; |
2323 | bool any_auto_type_p = gnu_auto_type_p || std_auto_type_p; |
2324 | gcc_assert (!(gnu_auto_type_p && std_auto_type_p)); |
2325 | const char *auto_type_keyword = gnu_auto_type_p ? "__auto_type" : "auto" ; |
2326 | if (specs->constexpr_p) |
2327 | { |
2328 | /* An underspecified declaration may not declare tags or members |
2329 | or structures or unions; it is undefined behavior to declare |
2330 | the members of an enumeration. Where the structure, union or |
2331 | enumeration type is declared within an initializer, this is |
2332 | diagnosed elsewhere. Diagnose here the case of declaring |
2333 | such a type in the type specifiers of a constexpr |
2334 | declaration. */ |
2335 | switch (specs->typespec_kind) |
2336 | { |
2337 | case ctsk_tagfirstref: |
2338 | case ctsk_tagfirstref_attrs: |
2339 | error_at (here, "%qT declared in underspecified object declaration" , |
2340 | specs->type); |
2341 | break; |
2342 | |
2343 | case ctsk_tagdef: |
2344 | error_at (here, "%qT defined in underspecified object declaration" , |
2345 | specs->type); |
2346 | break; |
2347 | |
2348 | default: |
2349 | break; |
2350 | } |
2351 | } |
2352 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
2353 | { |
2354 | bool handled_assume = false; |
2355 | if (specs->attrs |
2356 | && !nested |
2357 | && specs->typespec_kind == ctsk_none |
2358 | && c_parser_handle_statement_omp_attributes (parser, specs->attrs, |
2359 | NULL)) |
2360 | { |
2361 | if (specs->attrs) |
2362 | c_warn_unused_attributes (specs->attrs); |
2363 | while (parser->in_omp_attribute_pragma) |
2364 | { |
2365 | gcc_assert (c_parser_next_token_is (parser, CPP_PRAGMA)); |
2366 | c_parser_pragma (parser, pragma_external, NULL); |
2367 | } |
2368 | c_parser_consume_token (parser); |
2369 | return; |
2370 | } |
2371 | if (specs->typespec_kind == ctsk_none |
2372 | && lookup_attribute (attr_ns: "gnu" , attr_name: "assume" , list: specs->attrs)) |
2373 | { |
2374 | handled_assume = true; |
2375 | specs->attrs |
2376 | = handle_assume_attribute (here, attrs: specs->attrs, nested); |
2377 | } |
2378 | if (any_auto_type_p) |
2379 | error_at (here, "%qs in empty declaration" , auto_type_keyword); |
2380 | else if (specs->typespec_kind == ctsk_none |
2381 | && attribute_fallthrough_p (specs->attrs)) |
2382 | { |
2383 | if (fallthru_attr_p != NULL) |
2384 | *fallthru_attr_p = true; |
2385 | if (nested) |
2386 | { |
2387 | tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH, |
2388 | void_type_node, 0); |
2389 | add_stmt (fn); |
2390 | } |
2391 | else |
2392 | pedwarn (here, OPT_Wattributes, |
2393 | "%<fallthrough%> attribute at top level" ); |
2394 | } |
2395 | else if (empty_ok |
2396 | && !(have_attrs && specs->non_std_attrs_seen_p) |
2397 | && !handled_assume) |
2398 | shadow_tag (specs); |
2399 | else |
2400 | { |
2401 | shadow_tag_warned (specs, 1); |
2402 | if (!handled_assume) |
2403 | pedwarn (here, 0, "empty declaration" ); |
2404 | } |
2405 | /* We still have to evaluate size expressions. */ |
2406 | if (specs->expr) |
2407 | add_stmt (fold_convert (void_type_node, specs->expr)); |
2408 | c_parser_consume_token (parser); |
2409 | if (oacc_routine_data) |
2410 | c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); |
2411 | return; |
2412 | } |
2413 | |
2414 | /* Provide better error recovery. Note that a type name here is usually |
2415 | better diagnosed as a redeclaration. */ |
2416 | if (empty_ok |
2417 | && specs->typespec_kind == ctsk_tagdef |
2418 | && c_parser_next_token_starts_declspecs (parser) |
2419 | && !c_parser_next_token_is (parser, type: CPP_NAME)) |
2420 | { |
2421 | c_parser_error (parser, gmsgid: "expected %<;%>, identifier or %<(%>" ); |
2422 | parser->error = false; |
2423 | shadow_tag_warned (specs, 1); |
2424 | return; |
2425 | } |
2426 | else if (c_dialect_objc () && !any_auto_type_p) |
2427 | { |
2428 | /* Prefix attributes are an error on method decls. */ |
2429 | switch (c_parser_peek_token (parser)->type) |
2430 | { |
2431 | case CPP_PLUS: |
2432 | case CPP_MINUS: |
2433 | if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) |
2434 | return; |
2435 | if (specs->attrs) |
2436 | { |
2437 | warning_at (c_parser_peek_token (parser)->location, |
2438 | OPT_Wattributes, |
2439 | "prefix attributes are ignored for methods" ); |
2440 | specs->attrs = NULL_TREE; |
2441 | } |
2442 | if (fndef_ok) |
2443 | c_parser_objc_method_definition (parser); |
2444 | else |
2445 | c_parser_objc_methodproto (parser); |
2446 | return; |
2447 | break; |
2448 | default: |
2449 | break; |
2450 | } |
2451 | /* This is where we parse 'attributes @interface ...', |
2452 | 'attributes @implementation ...', 'attributes @protocol ...' |
2453 | (where attributes could be, for example, __attribute__ |
2454 | ((deprecated)). |
2455 | */ |
2456 | switch (c_parser_peek_token (parser)->keyword) |
2457 | { |
2458 | case RID_AT_INTERFACE: |
2459 | { |
2460 | if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) |
2461 | return; |
2462 | c_parser_objc_class_definition (parser, specs->attrs); |
2463 | return; |
2464 | } |
2465 | break; |
2466 | case RID_AT_IMPLEMENTATION: |
2467 | { |
2468 | if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) |
2469 | return; |
2470 | if (specs->attrs) |
2471 | { |
2472 | warning_at (c_parser_peek_token (parser)->location, |
2473 | OPT_Wattributes, |
2474 | "prefix attributes are ignored for implementations" ); |
2475 | specs->attrs = NULL_TREE; |
2476 | } |
2477 | c_parser_objc_class_definition (parser, NULL_TREE); |
2478 | return; |
2479 | } |
2480 | break; |
2481 | case RID_AT_PROTOCOL: |
2482 | { |
2483 | if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) |
2484 | return; |
2485 | c_parser_objc_protocol_definition (parser, specs->attrs); |
2486 | return; |
2487 | } |
2488 | break; |
2489 | case RID_AT_ALIAS: |
2490 | case RID_AT_CLASS: |
2491 | case RID_AT_END: |
2492 | case RID_AT_PROPERTY: |
2493 | if (specs->attrs) |
2494 | { |
2495 | c_parser_error (parser, gmsgid: "unexpected attribute" ); |
2496 | specs->attrs = NULL; |
2497 | } |
2498 | break; |
2499 | default: |
2500 | break; |
2501 | } |
2502 | } |
2503 | else if (attribute_fallthrough_p (specs->attrs)) |
2504 | warning_at (here, OPT_Wattributes, |
2505 | "%<fallthrough%> attribute not followed by %<;%>" ); |
2506 | else if (lookup_attribute (attr_ns: "gnu" , attr_name: "assume" , list: specs->attrs)) |
2507 | warning_at (here, OPT_Wattributes, |
2508 | "%<assume%> attribute not followed by %<;%>" ); |
2509 | |
2510 | auto_vec<c_token> omp_declare_simd_attr_clauses; |
2511 | c_parser_handle_directive_omp_attributes (specs->attrs, |
2512 | omp_declare_simd_clauses, |
2513 | &omp_declare_simd_attr_clauses); |
2514 | pending_xref_error (); |
2515 | prefix_attrs = specs->attrs; |
2516 | all_prefix_attrs = prefix_attrs; |
2517 | specs->attrs = NULL_TREE; |
2518 | while (true) |
2519 | { |
2520 | struct c_declarator *declarator; |
2521 | bool dummy = false; |
2522 | timevar_id_t tv; |
2523 | tree fnbody = NULL_TREE; |
2524 | tree underspec_name = NULL_TREE; |
2525 | auto_vec<c_token> omp_dsimd_idattr_clauses; |
2526 | /* Declaring either one or more declarators (in which case we |
2527 | should diagnose if there were no declaration specifiers) or a |
2528 | function definition (in which case the diagnostic for |
2529 | implicit int suffices). */ |
2530 | declarator = c_parser_declarator (parser, |
2531 | type_seen_p: specs->typespec_kind != ctsk_none, |
2532 | kind: C_DTR_NORMAL, seen_id: &dummy); |
2533 | if (declarator == NULL) |
2534 | { |
2535 | if (omp_declare_simd_clauses) |
2536 | c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, |
2537 | omp_declare_simd_clauses); |
2538 | if (oacc_routine_data) |
2539 | c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); |
2540 | c_parser_skip_to_end_of_block_or_statement (parser); |
2541 | return; |
2542 | } |
2543 | if (flag_openmp || flag_openmp_simd) |
2544 | { |
2545 | struct c_declarator *d = declarator; |
2546 | while (d->kind != cdk_id) |
2547 | d = d->declarator; |
2548 | vec<c_token> *dummy = NULL; |
2549 | c_parser_handle_directive_omp_attributes (d->u.id.attrs, dummy, |
2550 | &omp_dsimd_idattr_clauses); |
2551 | } |
2552 | if (gnu_auto_type_p && declarator->kind != cdk_id) |
2553 | { |
2554 | error_at (here, |
2555 | "%<__auto_type%> requires a plain identifier" |
2556 | " as declarator" ); |
2557 | c_parser_skip_to_end_of_block_or_statement (parser); |
2558 | return; |
2559 | } |
2560 | if (std_auto_type_p) |
2561 | { |
2562 | struct c_declarator *d = declarator; |
2563 | while (d->kind == cdk_attrs) |
2564 | d = d->declarator; |
2565 | if (d->kind != cdk_id) |
2566 | { |
2567 | error_at (here, |
2568 | "%<auto%> requires a plain identifier, possibly with" |
2569 | " attributes, as declarator" ); |
2570 | c_parser_skip_to_end_of_block_or_statement (parser); |
2571 | return; |
2572 | } |
2573 | underspec_name = d->u.id.id; |
2574 | } |
2575 | else if (specs->constexpr_p) |
2576 | { |
2577 | struct c_declarator *d = declarator; |
2578 | while (d->kind != cdk_id) |
2579 | d = d->declarator; |
2580 | underspec_name = d->u.id.id; |
2581 | } |
2582 | if (c_parser_next_token_is (parser, type: CPP_EQ) |
2583 | || c_parser_next_token_is (parser, type: CPP_COMMA) |
2584 | || c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
2585 | || c_parser_next_token_is_keyword (parser, keyword: RID_ASM) |
2586 | || c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE) |
2587 | || c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
2588 | { |
2589 | tree asm_name = NULL_TREE; |
2590 | tree postfix_attrs = NULL_TREE; |
2591 | if (!diagnosed_no_specs && !specs->declspecs_seen_p) |
2592 | { |
2593 | diagnosed_no_specs = true; |
2594 | pedwarn (here, 0, "data definition has no type or storage class" ); |
2595 | } |
2596 | /* Having seen a data definition, there cannot now be a |
2597 | function definition. */ |
2598 | fndef_ok = false; |
2599 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ASM)) |
2600 | asm_name = c_parser_simple_asm_expr (parser); |
2601 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
2602 | { |
2603 | postfix_attrs = c_parser_gnu_attributes (parser); |
2604 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
2605 | { |
2606 | /* This means there is an attribute specifier after |
2607 | the declarator in a function definition. Provide |
2608 | some more information for the user. */ |
2609 | error_at (here, "attributes should be specified before the " |
2610 | "declarator in a function definition" ); |
2611 | c_parser_skip_to_end_of_block_or_statement (parser); |
2612 | return; |
2613 | } |
2614 | } |
2615 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
2616 | { |
2617 | tree d; |
2618 | struct c_expr init; |
2619 | location_t init_loc; |
2620 | c_parser_consume_token (parser); |
2621 | if (any_auto_type_p) |
2622 | { |
2623 | init_loc = c_parser_peek_token (parser)->location; |
2624 | rich_location richloc (line_table, init_loc); |
2625 | unsigned int underspec_state = 0; |
2626 | if (std_auto_type_p) |
2627 | underspec_state = |
2628 | start_underspecified_init (init_loc, underspec_name); |
2629 | start_init (NULL_TREE, asm_name, |
2630 | (global_bindings_p () |
2631 | || specs->storage_class == csc_static |
2632 | || specs->constexpr_p), |
2633 | specs->constexpr_p, &richloc); |
2634 | /* A parameter is initialized, which is invalid. Don't |
2635 | attempt to instrument the initializer. */ |
2636 | int flag_sanitize_save = flag_sanitize; |
2637 | if (nested && !empty_ok) |
2638 | flag_sanitize = 0; |
2639 | init = c_parser_expr_no_commas (parser, NULL); |
2640 | if (std_auto_type_p) |
2641 | finish_underspecified_init (underspec_name, |
2642 | underspec_state); |
2643 | flag_sanitize = flag_sanitize_save; |
2644 | if (gnu_auto_type_p |
2645 | && TREE_CODE (init.value) == COMPONENT_REF |
2646 | && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1))) |
2647 | error_at (here, |
2648 | "%<__auto_type%> used with a bit-field" |
2649 | " initializer" ); |
2650 | init = convert_lvalue_to_rvalue (init_loc, init, true, true, |
2651 | true); |
2652 | tree init_type = TREE_TYPE (init.value); |
2653 | bool vm_type = c_type_variably_modified_p (t: init_type); |
2654 | if (vm_type) |
2655 | init.value = save_expr (init.value); |
2656 | finish_init (); |
2657 | specs->typespec_kind = ctsk_typeof; |
2658 | specs->locations[cdw_typedef] = init_loc; |
2659 | specs->typedef_p = true; |
2660 | specs->type = init_type; |
2661 | if (specs->postfix_attrs) |
2662 | { |
2663 | /* Postfix [[]] attributes are valid with C23 |
2664 | auto, although not with __auto_type, and |
2665 | modify the type given by the initializer. */ |
2666 | specs->postfix_attrs = |
2667 | c_warn_type_attributes (specs->postfix_attrs); |
2668 | decl_attributes (&specs->type, specs->postfix_attrs, 0); |
2669 | specs->postfix_attrs = NULL_TREE; |
2670 | } |
2671 | if (vm_type) |
2672 | { |
2673 | bool maybe_const = true; |
2674 | tree type_expr = c_fully_fold (init.value, false, |
2675 | &maybe_const); |
2676 | specs->expr_const_operands &= maybe_const; |
2677 | if (specs->expr) |
2678 | specs->expr = build2 (COMPOUND_EXPR, |
2679 | TREE_TYPE (type_expr), |
2680 | specs->expr, type_expr); |
2681 | else |
2682 | specs->expr = type_expr; |
2683 | } |
2684 | d = start_decl (declarator, specs, true, |
2685 | chainon (postfix_attrs, all_prefix_attrs)); |
2686 | if (!d) |
2687 | d = error_mark_node; |
2688 | if (omp_declare_simd_clauses) |
2689 | c_finish_omp_declare_simd (parser, d, NULL_TREE, |
2690 | omp_declare_simd_clauses); |
2691 | if (!omp_dsimd_idattr_clauses.is_empty ()) |
2692 | c_finish_omp_declare_simd (parser, d, NULL_TREE, |
2693 | &omp_dsimd_idattr_clauses); |
2694 | } |
2695 | else |
2696 | { |
2697 | /* The declaration of the variable is in effect while |
2698 | its initializer is parsed, except for a constexpr |
2699 | variable. */ |
2700 | init_loc = c_parser_peek_token (parser)->location; |
2701 | rich_location richloc (line_table, init_loc); |
2702 | unsigned int underspec_state = 0; |
2703 | if (specs->constexpr_p) |
2704 | underspec_state = |
2705 | start_underspecified_init (init_loc, underspec_name); |
2706 | d = start_decl (declarator, specs, true, |
2707 | chainon (postfix_attrs, |
2708 | all_prefix_attrs), |
2709 | !specs->constexpr_p); |
2710 | if (!d) |
2711 | d = error_mark_node; |
2712 | if (!specs->constexpr_p && omp_declare_simd_clauses) |
2713 | c_finish_omp_declare_simd (parser, d, NULL_TREE, |
2714 | omp_declare_simd_clauses); |
2715 | if (!specs->constexpr_p |
2716 | && !omp_dsimd_idattr_clauses.is_empty ()) |
2717 | c_finish_omp_declare_simd (parser, d, NULL_TREE, |
2718 | &omp_dsimd_idattr_clauses); |
2719 | start_init (d, asm_name, |
2720 | TREE_STATIC (d) || specs->constexpr_p, |
2721 | specs->constexpr_p, &richloc); |
2722 | /* A parameter is initialized, which is invalid. Don't |
2723 | attempt to instrument the initializer. */ |
2724 | int flag_sanitize_save = flag_sanitize; |
2725 | if (TREE_CODE (d) == PARM_DECL) |
2726 | flag_sanitize = 0; |
2727 | init = c_parser_initializer (parser, d); |
2728 | flag_sanitize = flag_sanitize_save; |
2729 | if (specs->constexpr_p) |
2730 | { |
2731 | finish_underspecified_init (underspec_name, |
2732 | underspec_state); |
2733 | d = pushdecl (d); |
2734 | if (omp_declare_simd_clauses) |
2735 | c_finish_omp_declare_simd (parser, d, NULL_TREE, |
2736 | omp_declare_simd_clauses); |
2737 | if (!specs->constexpr_p |
2738 | && !omp_dsimd_idattr_clauses.is_empty ()) |
2739 | c_finish_omp_declare_simd (parser, d, NULL_TREE, |
2740 | &omp_dsimd_idattr_clauses); |
2741 | } |
2742 | finish_init (); |
2743 | } |
2744 | if (oacc_routine_data) |
2745 | c_finish_oacc_routine (oacc_routine_data, d, false); |
2746 | if (d != error_mark_node) |
2747 | { |
2748 | maybe_warn_string_init (init_loc, TREE_TYPE (d), init); |
2749 | finish_decl (d, init_loc, init.value, |
2750 | init.original_type, asm_name); |
2751 | } |
2752 | } |
2753 | else |
2754 | { |
2755 | if (any_auto_type_p || specs->constexpr_p) |
2756 | { |
2757 | error_at (here, |
2758 | "%qs requires an initialized data declaration" , |
2759 | any_auto_type_p ? auto_type_keyword : "constexpr" ); |
2760 | c_parser_skip_to_end_of_block_or_statement (parser); |
2761 | return; |
2762 | } |
2763 | |
2764 | location_t lastloc = UNKNOWN_LOCATION; |
2765 | tree attrs = chainon (postfix_attrs, all_prefix_attrs); |
2766 | tree d = start_decl (declarator, specs, false, attrs, true, |
2767 | &lastloc); |
2768 | if (d && TREE_CODE (d) == FUNCTION_DECL) |
2769 | { |
2770 | /* Find the innermost declarator that is neither cdk_id |
2771 | nor cdk_attrs. */ |
2772 | const struct c_declarator *decl = declarator; |
2773 | const struct c_declarator *last_non_id_attrs = NULL; |
2774 | |
2775 | while (decl) |
2776 | switch (decl->kind) |
2777 | { |
2778 | case cdk_array: |
2779 | case cdk_function: |
2780 | case cdk_pointer: |
2781 | last_non_id_attrs = decl; |
2782 | decl = decl->declarator; |
2783 | break; |
2784 | |
2785 | case cdk_attrs: |
2786 | decl = decl->declarator; |
2787 | break; |
2788 | |
2789 | case cdk_id: |
2790 | decl = 0; |
2791 | break; |
2792 | |
2793 | default: |
2794 | gcc_unreachable (); |
2795 | } |
2796 | |
2797 | /* If it exists and is cdk_function declaration whose |
2798 | arguments have not been set yet, use its arguments. */ |
2799 | if (last_non_id_attrs |
2800 | && last_non_id_attrs->kind == cdk_function) |
2801 | { |
2802 | tree parms = last_non_id_attrs->u.arg_info->parms; |
2803 | if (DECL_ARGUMENTS (d) == NULL_TREE |
2804 | && DECL_INITIAL (d) == NULL_TREE) |
2805 | DECL_ARGUMENTS (d) = parms; |
2806 | |
2807 | warn_parm_array_mismatch (lastloc, d, parms); |
2808 | } |
2809 | } |
2810 | if (omp_declare_simd_clauses |
2811 | || !omp_dsimd_idattr_clauses.is_empty ()) |
2812 | { |
2813 | tree parms = NULL_TREE; |
2814 | if (d && TREE_CODE (d) == FUNCTION_DECL) |
2815 | { |
2816 | struct c_declarator *ce = declarator; |
2817 | while (ce != NULL) |
2818 | if (ce->kind == cdk_function) |
2819 | { |
2820 | parms = ce->u.arg_info->parms; |
2821 | break; |
2822 | } |
2823 | else |
2824 | ce = ce->declarator; |
2825 | } |
2826 | if (parms) |
2827 | temp_store_parm_decls (d, parms); |
2828 | if (omp_declare_simd_clauses) |
2829 | c_finish_omp_declare_simd (parser, d, parms, |
2830 | omp_declare_simd_clauses); |
2831 | if (!specs->constexpr_p |
2832 | && !omp_dsimd_idattr_clauses.is_empty ()) |
2833 | c_finish_omp_declare_simd (parser, d, parms, |
2834 | &omp_dsimd_idattr_clauses); |
2835 | if (parms) |
2836 | temp_pop_parm_decls (); |
2837 | } |
2838 | if (oacc_routine_data) |
2839 | c_finish_oacc_routine (oacc_routine_data, d, false); |
2840 | if (d) |
2841 | finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, |
2842 | NULL_TREE, asm_name); |
2843 | |
2844 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
2845 | { |
2846 | if (d) |
2847 | *objc_foreach_object_declaration = d; |
2848 | else |
2849 | *objc_foreach_object_declaration = error_mark_node; |
2850 | } |
2851 | } |
2852 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
2853 | { |
2854 | if (any_auto_type_p || specs->constexpr_p) |
2855 | { |
2856 | error_at (here, |
2857 | "%qs may only be used with a single declarator" , |
2858 | any_auto_type_p ? auto_type_keyword : "constexpr" ); |
2859 | c_parser_skip_to_end_of_block_or_statement (parser); |
2860 | return; |
2861 | } |
2862 | c_parser_consume_token (parser); |
2863 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
2864 | all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), |
2865 | prefix_attrs); |
2866 | else |
2867 | all_prefix_attrs = prefix_attrs; |
2868 | continue; |
2869 | } |
2870 | else if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
2871 | { |
2872 | c_parser_consume_token (parser); |
2873 | return; |
2874 | } |
2875 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
2876 | { |
2877 | /* This can only happen in Objective-C: we found the |
2878 | 'in' that terminates the declaration inside an |
2879 | Objective-C foreach statement. Do not consume the |
2880 | token, so that the caller can use it to determine |
2881 | that this indeed is a foreach context. */ |
2882 | return; |
2883 | } |
2884 | else |
2885 | { |
2886 | c_parser_error (parser, gmsgid: "expected %<,%> or %<;%>" ); |
2887 | c_parser_skip_to_end_of_block_or_statement (parser); |
2888 | return; |
2889 | } |
2890 | } |
2891 | else if (any_auto_type_p || specs->constexpr_p) |
2892 | { |
2893 | error_at (here, |
2894 | "%qs requires an initialized data declaration" , |
2895 | any_auto_type_p ? auto_type_keyword : "constexpr" ); |
2896 | c_parser_skip_to_end_of_block_or_statement (parser); |
2897 | return; |
2898 | } |
2899 | else if (!fndef_ok) |
2900 | { |
2901 | c_parser_error (parser, gmsgid: "expected %<=%>, %<,%>, %<;%>, " |
2902 | "%<asm%> or %<__attribute__%>" ); |
2903 | c_parser_skip_to_end_of_block_or_statement (parser); |
2904 | return; |
2905 | } |
2906 | /* Function definition (nested or otherwise). */ |
2907 | if (nested) |
2908 | { |
2909 | pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions" ); |
2910 | c_push_function_context (); |
2911 | } |
2912 | if (!start_function (specs, declarator, all_prefix_attrs)) |
2913 | { |
2914 | /* At this point we've consumed: |
2915 | declaration-specifiers declarator |
2916 | and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON, |
2917 | RID_ASM, RID_ATTRIBUTE, or RID_IN, |
2918 | but the |
2919 | declaration-specifiers declarator |
2920 | aren't grokkable as a function definition, so we have |
2921 | an error. */ |
2922 | gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON)); |
2923 | if (c_parser_next_token_starts_declspecs (parser)) |
2924 | { |
2925 | /* If we have |
2926 | declaration-specifiers declarator decl-specs |
2927 | then assume we have a missing semicolon, which would |
2928 | give us: |
2929 | declaration-specifiers declarator decl-specs |
2930 | ^ |
2931 | ; |
2932 | <~~~~~~~~~ declaration ~~~~~~~~~~> |
2933 | Use c_parser_require to get an error with a fix-it hint. */ |
2934 | c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
2935 | parser->error = false; |
2936 | } |
2937 | else |
2938 | { |
2939 | /* This can appear in many cases looking nothing like a |
2940 | function definition, so we don't give a more specific |
2941 | error suggesting there was one. */ |
2942 | c_parser_error (parser, gmsgid: "expected %<=%>, %<,%>, %<;%>, %<asm%> " |
2943 | "or %<__attribute__%>" ); |
2944 | } |
2945 | if (nested) |
2946 | c_pop_function_context (); |
2947 | break; |
2948 | } |
2949 | |
2950 | if (DECL_DECLARED_INLINE_P (current_function_decl)) |
2951 | tv = TV_PARSE_INLINE; |
2952 | else |
2953 | tv = TV_PARSE_FUNC; |
2954 | auto_timevar at (g_timer, tv); |
2955 | |
2956 | /* Parse old-style parameter declarations. ??? Attributes are |
2957 | not allowed to start declaration specifiers here because of a |
2958 | syntax conflict between a function declaration with attribute |
2959 | suffix and a function definition with an attribute prefix on |
2960 | first old-style parameter declaration. Following the old |
2961 | parser, they are not accepted on subsequent old-style |
2962 | parameter declarations either. However, there is no |
2963 | ambiguity after the first declaration, nor indeed on the |
2964 | first as long as we don't allow postfix attributes after a |
2965 | declarator with a nonempty identifier list in a definition; |
2966 | and postfix attributes have never been accepted here in |
2967 | function definitions either. */ |
2968 | int save_debug_nonbind_markers_p = debug_nonbind_markers_p; |
2969 | debug_nonbind_markers_p = 0; |
2970 | while (c_parser_next_token_is_not (parser, type: CPP_EOF) |
2971 | && c_parser_next_token_is_not (parser, type: CPP_OPEN_BRACE)) |
2972 | c_parser_declaration_or_fndef (parser, fndef_ok: false, static_assert_ok: false, empty_ok: false, |
2973 | nested: true, start_attr_ok: false); |
2974 | debug_nonbind_markers_p = save_debug_nonbind_markers_p; |
2975 | store_parm_decls (); |
2976 | if (omp_declare_simd_clauses) |
2977 | c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, |
2978 | omp_declare_simd_clauses); |
2979 | if (!omp_dsimd_idattr_clauses.is_empty ()) |
2980 | c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, |
2981 | &omp_dsimd_idattr_clauses); |
2982 | if (oacc_routine_data) |
2983 | c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); |
2984 | location_t startloc = c_parser_peek_token (parser)->location; |
2985 | DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus |
2986 | = startloc; |
2987 | location_t endloc = startloc; |
2988 | |
2989 | /* If the definition was marked with __RTL, use the RTL parser now, |
2990 | consuming the function body. */ |
2991 | if (specs->declspec_il == cdil_rtl) |
2992 | { |
2993 | endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass); |
2994 | |
2995 | /* Normally, store_parm_decls sets next_is_function_body, |
2996 | anticipating a function body. We need a push_scope/pop_scope |
2997 | pair to flush out this state, or subsequent function parsing |
2998 | will go wrong. */ |
2999 | push_scope (); |
3000 | pop_scope (); |
3001 | |
3002 | finish_function (endloc); |
3003 | return; |
3004 | } |
3005 | /* If the definition was marked with __GIMPLE then parse the |
3006 | function body as GIMPLE. */ |
3007 | else if (specs->declspec_il != cdil_none) |
3008 | { |
3009 | bool saved = in_late_binary_op; |
3010 | in_late_binary_op = true; |
3011 | c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass, |
3012 | specs->declspec_il, |
3013 | specs->entry_bb_count); |
3014 | in_late_binary_op = saved; |
3015 | } |
3016 | else |
3017 | fnbody = c_parser_compound_statement (parser, &endloc); |
3018 | tree fndecl = current_function_decl; |
3019 | if (nested) |
3020 | { |
3021 | tree decl = current_function_decl; |
3022 | /* Mark nested functions as needing static-chain initially. |
3023 | lower_nested_functions will recompute it but the |
3024 | DECL_STATIC_CHAIN flag is also used before that happens, |
3025 | by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */ |
3026 | DECL_STATIC_CHAIN (decl) = 1; |
3027 | add_stmt (fnbody); |
3028 | finish_function (endloc); |
3029 | c_pop_function_context (); |
3030 | add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); |
3031 | } |
3032 | else |
3033 | { |
3034 | if (fnbody) |
3035 | add_stmt (fnbody); |
3036 | finish_function (endloc); |
3037 | } |
3038 | /* Get rid of the empty stmt list for GIMPLE/RTL. */ |
3039 | if (specs->declspec_il != cdil_none) |
3040 | DECL_SAVED_TREE (fndecl) = NULL_TREE; |
3041 | |
3042 | break; |
3043 | } |
3044 | } |
3045 | |
3046 | /* Parse an asm-definition (asm() outside a function body). This is a |
3047 | GNU extension. |
3048 | |
3049 | asm-definition: |
3050 | simple-asm-expr ; |
3051 | */ |
3052 | |
3053 | static void |
3054 | c_parser_asm_definition (c_parser *parser) |
3055 | { |
3056 | tree asm_str = c_parser_simple_asm_expr (parser); |
3057 | if (asm_str) |
3058 | symtab->finalize_toplevel_asm (asm_str); |
3059 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
3060 | } |
3061 | |
3062 | /* Parse a static assertion (C11 6.7.10). |
3063 | |
3064 | static_assert-declaration: |
3065 | static_assert-declaration-no-semi ; |
3066 | */ |
3067 | |
3068 | static void |
3069 | c_parser_static_assert_declaration (c_parser *parser) |
3070 | { |
3071 | c_parser_static_assert_declaration_no_semi (parser); |
3072 | if (parser->error |
3073 | || !c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
3074 | c_parser_skip_to_end_of_block_or_statement (parser); |
3075 | } |
3076 | |
3077 | /* Parse a static assertion (C11 6.7.10), without the trailing |
3078 | semicolon. |
3079 | |
3080 | static_assert-declaration-no-semi: |
3081 | _Static_assert ( constant-expression , string-literal ) |
3082 | |
3083 | C23: |
3084 | static_assert-declaration-no-semi: |
3085 | _Static_assert ( constant-expression ) |
3086 | */ |
3087 | |
3088 | static void |
3089 | c_parser_static_assert_declaration_no_semi (c_parser *parser) |
3090 | { |
3091 | location_t assert_loc, value_loc; |
3092 | tree value; |
3093 | tree string = NULL_TREE; |
3094 | |
3095 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)); |
3096 | tree spelling = c_parser_peek_token (parser)->value; |
3097 | assert_loc = c_parser_peek_token (parser)->location; |
3098 | if (flag_isoc99) |
3099 | pedwarn_c99 (assert_loc, opt: OPT_Wpedantic, |
3100 | "ISO C99 does not support %qE" , spelling); |
3101 | else |
3102 | pedwarn_c99 (assert_loc, opt: OPT_Wpedantic, |
3103 | "ISO C90 does not support %qE" , spelling); |
3104 | c_parser_consume_token (parser); |
3105 | matching_parens parens; |
3106 | if (!parens.require_open (parser)) |
3107 | return; |
3108 | location_t value_tok_loc = c_parser_peek_token (parser)->location; |
3109 | value = convert_lvalue_to_rvalue (value_tok_loc, |
3110 | c_parser_expr_no_commas (parser, NULL), |
3111 | true, true).value; |
3112 | value_loc = EXPR_LOC_OR_LOC (value, value_tok_loc); |
3113 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
3114 | { |
3115 | c_parser_consume_token (parser); |
3116 | switch (c_parser_peek_token (parser)->type) |
3117 | { |
3118 | case CPP_STRING: |
3119 | case CPP_STRING16: |
3120 | case CPP_STRING32: |
3121 | case CPP_WSTRING: |
3122 | case CPP_UTF8STRING: |
3123 | string = c_parser_string_literal (parser, false, true).value; |
3124 | break; |
3125 | default: |
3126 | c_parser_error (parser, gmsgid: "expected string literal" ); |
3127 | return; |
3128 | } |
3129 | } |
3130 | else if (flag_isoc11) |
3131 | /* If pedantic for pre-C11, the use of _Static_assert itself will |
3132 | have been diagnosed, so do not also diagnose the use of this |
3133 | new C23 feature of _Static_assert. */ |
3134 | pedwarn_c11 (assert_loc, opt: OPT_Wpedantic, |
3135 | "ISO C11 does not support omitting the string in " |
3136 | "%qE" , spelling); |
3137 | parens.require_close (parser); |
3138 | |
3139 | if (!INTEGRAL_TYPE_P (TREE_TYPE (value))) |
3140 | { |
3141 | error_at (value_loc, "expression in static assertion is not an integer" ); |
3142 | return; |
3143 | } |
3144 | if (TREE_CODE (value) != INTEGER_CST) |
3145 | { |
3146 | value = c_fully_fold (value, false, NULL); |
3147 | /* Strip no-op conversions. */ |
3148 | STRIP_TYPE_NOPS (value); |
3149 | if (TREE_CODE (value) == INTEGER_CST) |
3150 | pedwarn (value_loc, OPT_Wpedantic, "expression in static assertion " |
3151 | "is not an integer constant expression" ); |
3152 | } |
3153 | if (TREE_CODE (value) != INTEGER_CST) |
3154 | { |
3155 | error_at (value_loc, "expression in static assertion is not constant" ); |
3156 | return; |
3157 | } |
3158 | constant_expression_warning (value); |
3159 | if (integer_zerop (value)) |
3160 | { |
3161 | if (string) |
3162 | error_at (assert_loc, "static assertion failed: %E" , string); |
3163 | else |
3164 | error_at (assert_loc, "static assertion failed" ); |
3165 | } |
3166 | } |
3167 | |
3168 | /* Parse some declaration specifiers (possibly none) (C90 6.5, C99 |
3169 | 6.7, C11 6.7), adding them to SPECS (which may already include some). |
3170 | Storage class specifiers are accepted iff SCSPEC_OK; type |
3171 | specifiers are accepted iff TYPESPEC_OK; alignment specifiers are |
3172 | accepted iff ALIGNSPEC_OK; gnu-attributes are accepted at the start |
3173 | iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK. In |
3174 | addition to the syntax shown, standard attributes are accepted at |
3175 | the start iff START_STD_ATTR_OK and at the end iff END_STD_ATTR_OK; |
3176 | unlike gnu-attributes, they are not accepted in the middle of the |
3177 | list. (This combines various different syntax productions in the C |
3178 | standard, and in some cases gnu-attributes and standard attributes |
3179 | at the start may already have been parsed before this function is |
3180 | called.) |
3181 | |
3182 | declaration-specifiers: |
3183 | storage-class-specifier declaration-specifiers[opt] |
3184 | type-specifier declaration-specifiers[opt] |
3185 | type-qualifier declaration-specifiers[opt] |
3186 | function-specifier declaration-specifiers[opt] |
3187 | alignment-specifier declaration-specifiers[opt] |
3188 | |
3189 | Function specifiers (inline) are from C99, and are currently |
3190 | handled as storage class specifiers, as is __thread. Alignment |
3191 | specifiers are from C11. |
3192 | |
3193 | C90 6.5.1, C99 6.7.1, C11 6.7.1: |
3194 | storage-class-specifier: |
3195 | typedef |
3196 | extern |
3197 | static |
3198 | auto |
3199 | register |
3200 | _Thread_local |
3201 | |
3202 | (_Thread_local is new in C11.) |
3203 | |
3204 | C99 6.7.4, C11 6.7.4: |
3205 | function-specifier: |
3206 | inline |
3207 | _Noreturn |
3208 | |
3209 | (_Noreturn is new in C11.) |
3210 | |
3211 | C90 6.5.2, C99 6.7.2, C11 6.7.2: |
3212 | type-specifier: |
3213 | void |
3214 | char |
3215 | short |
3216 | int |
3217 | long |
3218 | float |
3219 | double |
3220 | signed |
3221 | unsigned |
3222 | _Bool |
3223 | _Complex |
3224 | [_Imaginary removed in C99 TC2] |
3225 | _BitInt ( constant-expression ) |
3226 | struct-or-union-specifier |
3227 | enum-specifier |
3228 | typedef-name |
3229 | atomic-type-specifier |
3230 | |
3231 | (_Bool and _Complex are new in C99.) |
3232 | (atomic-type-specifier is new in C11.) |
3233 | (_BitInt is new in C23.) |
3234 | |
3235 | C90 6.5.3, C99 6.7.3, C11 6.7.3: |
3236 | |
3237 | type-qualifier: |
3238 | const |
3239 | restrict |
3240 | volatile |
3241 | address-space-qualifier |
3242 | _Atomic |
3243 | |
3244 | (restrict is new in C99.) |
3245 | (_Atomic is new in C11.) |
3246 | |
3247 | GNU extensions: |
3248 | |
3249 | declaration-specifiers: |
3250 | gnu-attributes declaration-specifiers[opt] |
3251 | |
3252 | type-qualifier: |
3253 | address-space |
3254 | |
3255 | address-space: |
3256 | identifier recognized by the target |
3257 | |
3258 | storage-class-specifier: |
3259 | __thread |
3260 | |
3261 | type-specifier: |
3262 | typeof-specifier |
3263 | __auto_type |
3264 | __intN |
3265 | _Decimal32 |
3266 | _Decimal64 |
3267 | _Decimal128 |
3268 | _Fract |
3269 | _Accum |
3270 | _Sat |
3271 | |
3272 | (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037: |
3273 | http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf) |
3274 | |
3275 | atomic-type-specifier |
3276 | _Atomic ( type-name ) |
3277 | |
3278 | Objective-C: |
3279 | |
3280 | type-specifier: |
3281 | class-name objc-protocol-refs[opt] |
3282 | typedef-name objc-protocol-refs |
3283 | objc-protocol-refs |
3284 | */ |
3285 | |
3286 | void |
3287 | c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, |
3288 | bool scspec_ok, bool typespec_ok, bool start_attr_ok, |
3289 | bool alignspec_ok, bool auto_type_ok, |
3290 | bool start_std_attr_ok, bool end_std_attr_ok, |
3291 | enum c_lookahead_kind la) |
3292 | { |
3293 | bool attrs_ok = start_attr_ok; |
3294 | bool seen_type = specs->typespec_kind != ctsk_none; |
3295 | |
3296 | if (!typespec_ok) |
3297 | gcc_assert (la == cla_prefer_id); |
3298 | |
3299 | if (start_std_attr_ok |
3300 | && c_parser_nth_token_starts_std_attributes (parser, 1)) |
3301 | { |
3302 | gcc_assert (!specs->non_std_attrs_seen_p); |
3303 | location_t loc = c_parser_peek_token (parser)->location; |
3304 | tree attrs = c_parser_std_attribute_specifier_sequence (parser); |
3305 | declspecs_add_attrs (loc, specs, attrs); |
3306 | specs->non_std_attrs_seen_p = false; |
3307 | } |
3308 | |
3309 | while (c_parser_next_token_is (parser, type: CPP_NAME) |
3310 | || c_parser_next_token_is (parser, type: CPP_KEYWORD) |
3311 | || (c_dialect_objc () && c_parser_next_token_is (parser, type: CPP_LESS))) |
3312 | { |
3313 | struct c_typespec t; |
3314 | tree attrs; |
3315 | tree align; |
3316 | location_t loc = c_parser_peek_token (parser)->location; |
3317 | |
3318 | /* If we cannot accept a type, exit if the next token must start |
3319 | one. Also, if we already have seen a tagged definition, |
3320 | a typename would be an error anyway and likely the user |
3321 | has simply forgotten a semicolon, so we exit. */ |
3322 | if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef) |
3323 | && c_parser_next_tokens_start_typename (parser, la) |
3324 | && !c_parser_next_token_is_qualifier (parser) |
3325 | && !c_parser_next_token_is_keyword (parser, keyword: RID_ALIGNAS)) |
3326 | break; |
3327 | |
3328 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
3329 | { |
3330 | c_token *name_token = c_parser_peek_token (parser); |
3331 | tree value = name_token->value; |
3332 | c_id_kind kind = name_token->id_kind; |
3333 | |
3334 | if (kind == C_ID_ADDRSPACE) |
3335 | { |
3336 | addr_space_t as |
3337 | = name_token->keyword - RID_FIRST_ADDR_SPACE; |
3338 | declspecs_add_addrspace (name_token->location, specs, as); |
3339 | c_parser_consume_token (parser); |
3340 | attrs_ok = true; |
3341 | continue; |
3342 | } |
3343 | |
3344 | gcc_assert (!c_parser_next_token_is_qualifier (parser)); |
3345 | |
3346 | /* If we cannot accept a type, and the next token must start one, |
3347 | exit. Do the same if we already have seen a tagged definition, |
3348 | since it would be an error anyway and likely the user has simply |
3349 | forgotten a semicolon. */ |
3350 | if (seen_type || !c_parser_next_tokens_start_typename (parser, la)) |
3351 | break; |
3352 | |
3353 | /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or |
3354 | a C_ID_CLASSNAME. */ |
3355 | c_parser_consume_token (parser); |
3356 | seen_type = true; |
3357 | attrs_ok = true; |
3358 | if (kind == C_ID_ID) |
3359 | { |
3360 | auto_diagnostic_group d; |
3361 | name_hint hint = lookup_name_fuzzy (value, FUZZY_LOOKUP_TYPENAME, |
3362 | loc); |
3363 | if (const char *suggestion = hint.suggestion ()) |
3364 | { |
3365 | gcc_rich_location richloc (loc); |
3366 | richloc.add_fixit_replace (new_content: suggestion); |
3367 | error_at (&richloc, |
3368 | "unknown type name %qE; did you mean %qs?" , |
3369 | value, suggestion); |
3370 | } |
3371 | else |
3372 | error_at (loc, "unknown type name %qE" , value); |
3373 | t.kind = ctsk_typedef; |
3374 | t.spec = error_mark_node; |
3375 | } |
3376 | else if (kind == C_ID_TYPENAME |
3377 | && (!c_dialect_objc () |
3378 | || c_parser_next_token_is_not (parser, type: CPP_LESS))) |
3379 | { |
3380 | t.kind = ctsk_typedef; |
3381 | /* For a typedef name, record the meaning, not the name. |
3382 | In case of 'foo foo, bar;'. */ |
3383 | t.spec = lookup_name (value); |
3384 | } |
3385 | else |
3386 | { |
3387 | tree proto = NULL_TREE; |
3388 | gcc_assert (c_dialect_objc ()); |
3389 | t.kind = ctsk_objc; |
3390 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
3391 | proto = c_parser_objc_protocol_refs (parser); |
3392 | t.spec = objc_get_protocol_qualified_type (value, proto); |
3393 | } |
3394 | t.expr = NULL_TREE; |
3395 | t.expr_const_operands = true; |
3396 | t.has_enum_type_specifier = false; |
3397 | declspecs_add_type (name_token->location, specs, t); |
3398 | continue; |
3399 | } |
3400 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
3401 | { |
3402 | /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" - |
3403 | nisse@lysator.liu.se. */ |
3404 | tree proto; |
3405 | gcc_assert (c_dialect_objc ()); |
3406 | if (!typespec_ok || seen_type) |
3407 | break; |
3408 | proto = c_parser_objc_protocol_refs (parser); |
3409 | t.kind = ctsk_objc; |
3410 | t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); |
3411 | t.expr = NULL_TREE; |
3412 | t.expr_const_operands = true; |
3413 | t.has_enum_type_specifier = false; |
3414 | declspecs_add_type (loc, specs, t); |
3415 | continue; |
3416 | } |
3417 | gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD)); |
3418 | switch (c_parser_peek_token (parser)->keyword) |
3419 | { |
3420 | case RID_STATIC: |
3421 | case RID_EXTERN: |
3422 | case RID_REGISTER: |
3423 | case RID_TYPEDEF: |
3424 | case RID_INLINE: |
3425 | case RID_NORETURN: |
3426 | case RID_AUTO: |
3427 | case RID_THREAD: |
3428 | case RID_CONSTEXPR: |
3429 | if (!scspec_ok) |
3430 | goto out; |
3431 | attrs_ok = true; |
3432 | /* TODO: Distinguish between function specifiers (inline, noreturn) |
3433 | and storage class specifiers, either here or in |
3434 | declspecs_add_scspec. */ |
3435 | declspecs_add_scspec (loc, specs, |
3436 | c_parser_peek_token (parser)->value); |
3437 | c_parser_consume_token (parser); |
3438 | break; |
3439 | case RID_AUTO_TYPE: |
3440 | if (!auto_type_ok) |
3441 | goto out; |
3442 | /* Fall through. */ |
3443 | case RID_UNSIGNED: |
3444 | case RID_LONG: |
3445 | case RID_SHORT: |
3446 | case RID_SIGNED: |
3447 | case RID_COMPLEX: |
3448 | case RID_INT: |
3449 | case RID_CHAR: |
3450 | case RID_FLOAT: |
3451 | case RID_DOUBLE: |
3452 | case RID_VOID: |
3453 | case RID_DFLOAT32: |
3454 | case RID_DFLOAT64: |
3455 | case RID_DFLOAT128: |
3456 | CASE_RID_FLOATN_NX: |
3457 | case RID_BOOL: |
3458 | case RID_FRACT: |
3459 | case RID_ACCUM: |
3460 | case RID_SAT: |
3461 | case RID_INT_N_0: |
3462 | case RID_INT_N_1: |
3463 | case RID_INT_N_2: |
3464 | case RID_INT_N_3: |
3465 | if (!typespec_ok) |
3466 | goto out; |
3467 | attrs_ok = true; |
3468 | seen_type = true; |
3469 | if (c_dialect_objc ()) |
3470 | parser->objc_need_raw_identifier = true; |
3471 | t.kind = ctsk_resword; |
3472 | t.spec = c_parser_peek_token (parser)->value; |
3473 | t.expr = NULL_TREE; |
3474 | t.expr_const_operands = true; |
3475 | t.has_enum_type_specifier = false; |
3476 | declspecs_add_type (loc, specs, t); |
3477 | c_parser_consume_token (parser); |
3478 | break; |
3479 | case RID_ENUM: |
3480 | if (!typespec_ok) |
3481 | goto out; |
3482 | attrs_ok = true; |
3483 | seen_type = true; |
3484 | t = c_parser_enum_specifier (parser); |
3485 | invoke_plugin_callbacks (event: PLUGIN_FINISH_TYPE, gcc_data: t.spec); |
3486 | declspecs_add_type (loc, specs, t); |
3487 | break; |
3488 | case RID_STRUCT: |
3489 | case RID_UNION: |
3490 | if (!typespec_ok) |
3491 | goto out; |
3492 | attrs_ok = true; |
3493 | seen_type = true; |
3494 | t = c_parser_struct_or_union_specifier (parser); |
3495 | invoke_plugin_callbacks (event: PLUGIN_FINISH_TYPE, gcc_data: t.spec); |
3496 | declspecs_add_type (loc, specs, t); |
3497 | break; |
3498 | case RID_TYPEOF: |
3499 | case RID_TYPEOF_UNQUAL: |
3500 | /* ??? The old parser rejected typeof after other type |
3501 | specifiers, but is a syntax error the best way of |
3502 | handling this? */ |
3503 | if (!typespec_ok || seen_type) |
3504 | goto out; |
3505 | attrs_ok = true; |
3506 | seen_type = true; |
3507 | t = c_parser_typeof_specifier (parser); |
3508 | declspecs_add_type (loc, specs, t); |
3509 | break; |
3510 | case RID_BITINT: |
3511 | if (!typespec_ok) |
3512 | goto out; |
3513 | else |
3514 | { |
3515 | attrs_ok = true; |
3516 | seen_type = true; |
3517 | t.kind = ctsk_resword; |
3518 | t.spec = c_parser_peek_token (parser)->value; |
3519 | t.expr = error_mark_node; |
3520 | t.expr_const_operands = true; |
3521 | t.has_enum_type_specifier = false; |
3522 | c_parser_consume_token (parser); |
3523 | matching_parens parens; |
3524 | if (parens.require_open (parser)) |
3525 | { |
3526 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
3527 | t.expr = convert_lvalue_to_rvalue (loc, expr, true, |
3528 | true).value; |
3529 | parens.skip_until_found_close (parser); |
3530 | } |
3531 | declspecs_add_type (loc, specs, t); |
3532 | } |
3533 | break; |
3534 | case RID_ATOMIC: |
3535 | /* C parser handling of Objective-C constructs needs |
3536 | checking for correct lvalue-to-rvalue conversions, and |
3537 | the code in build_modify_expr handling various |
3538 | Objective-C cases, and that in build_unary_op handling |
3539 | Objective-C cases for increment / decrement, also needs |
3540 | updating; uses of TYPE_MAIN_VARIANT in objc_compare_types |
3541 | and objc_types_are_equivalent may also need updates. */ |
3542 | if (c_dialect_objc ()) |
3543 | sorry ("%<_Atomic%> in Objective-C" ); |
3544 | if (flag_isoc99) |
3545 | pedwarn_c99 (loc, opt: OPT_Wpedantic, |
3546 | "ISO C99 does not support the %<_Atomic%> qualifier" ); |
3547 | else |
3548 | pedwarn_c99 (loc, opt: OPT_Wpedantic, |
3549 | "ISO C90 does not support the %<_Atomic%> qualifier" ); |
3550 | attrs_ok = true; |
3551 | tree value; |
3552 | value = c_parser_peek_token (parser)->value; |
3553 | c_parser_consume_token (parser); |
3554 | if (typespec_ok && c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
3555 | { |
3556 | /* _Atomic ( type-name ). */ |
3557 | seen_type = true; |
3558 | c_parser_consume_token (parser); |
3559 | struct c_type_name *type = c_parser_type_name (parser); |
3560 | t.kind = ctsk_typeof; |
3561 | t.spec = error_mark_node; |
3562 | t.expr = NULL_TREE; |
3563 | t.expr_const_operands = true; |
3564 | t.has_enum_type_specifier = false; |
3565 | if (type != NULL) |
3566 | t.spec = groktypename (type, &t.expr, |
3567 | &t.expr_const_operands); |
3568 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
3569 | msgid: "expected %<)%>" ); |
3570 | if (t.spec != error_mark_node) |
3571 | { |
3572 | if (TREE_CODE (t.spec) == ARRAY_TYPE) |
3573 | error_at (loc, "%<_Atomic%>-qualified array type" ); |
3574 | else if (TREE_CODE (t.spec) == FUNCTION_TYPE) |
3575 | error_at (loc, "%<_Atomic%>-qualified function type" ); |
3576 | else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED) |
3577 | error_at (loc, "%<_Atomic%> applied to a qualified type" ); |
3578 | else |
3579 | t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC); |
3580 | } |
3581 | declspecs_add_type (loc, specs, t); |
3582 | } |
3583 | else |
3584 | declspecs_add_qual (loc, specs, value); |
3585 | break; |
3586 | case RID_CONST: |
3587 | case RID_VOLATILE: |
3588 | case RID_RESTRICT: |
3589 | attrs_ok = true; |
3590 | declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value); |
3591 | c_parser_consume_token (parser); |
3592 | break; |
3593 | case RID_ATTRIBUTE: |
3594 | if (!attrs_ok) |
3595 | goto out; |
3596 | attrs = c_parser_gnu_attributes (parser); |
3597 | declspecs_add_attrs (loc, specs, attrs); |
3598 | break; |
3599 | case RID_ALIGNAS: |
3600 | if (!alignspec_ok) |
3601 | goto out; |
3602 | align = c_parser_alignas_specifier (parser); |
3603 | declspecs_add_alignas (loc, specs, align); |
3604 | break; |
3605 | case RID_GIMPLE: |
3606 | if (! flag_gimple) |
3607 | error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>" ); |
3608 | c_parser_consume_token (parser); |
3609 | specs->declspec_il = cdil_gimple; |
3610 | specs->locations[cdw_gimple] = loc; |
3611 | c_parser_gimple_or_rtl_pass_list (parser, specs); |
3612 | break; |
3613 | case RID_RTL: |
3614 | c_parser_consume_token (parser); |
3615 | specs->declspec_il = cdil_rtl; |
3616 | specs->locations[cdw_rtl] = loc; |
3617 | c_parser_gimple_or_rtl_pass_list (parser, specs); |
3618 | break; |
3619 | default: |
3620 | goto out; |
3621 | } |
3622 | } |
3623 | out: |
3624 | if (end_std_attr_ok |
3625 | && c_parser_nth_token_starts_std_attributes (parser, 1)) |
3626 | specs->postfix_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3627 | } |
3628 | |
3629 | /* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2). |
3630 | |
3631 | enum-specifier: |
3632 | enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt] |
3633 | { enumerator-list } gnu-attributes[opt] |
3634 | enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt] |
3635 | { enumerator-list , } gnu-attributes[opt] enum-type-specifier[opt] |
3636 | enum gnu-attributes[opt] identifier |
3637 | |
3638 | The form with trailing comma is new in C99; enum-type-specifiers |
3639 | are new in C23. The forms with gnu-attributes are GNU extensions. |
3640 | In GNU C, we accept any expression without commas in the syntax |
3641 | (assignment expressions, not just conditional expressions); |
3642 | assignment expressions will be diagnosed as non-constant. |
3643 | |
3644 | enum-type-specifier: |
3645 | : specifier-qualifier-list |
3646 | |
3647 | enumerator-list: |
3648 | enumerator |
3649 | enumerator-list , enumerator |
3650 | |
3651 | enumerator: |
3652 | enumeration-constant attribute-specifier-sequence[opt] |
3653 | enumeration-constant attribute-specifier-sequence[opt] |
3654 | = constant-expression |
3655 | |
3656 | GNU Extensions: |
3657 | |
3658 | enumerator: |
3659 | enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] |
3660 | enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt] |
3661 | = constant-expression |
3662 | |
3663 | */ |
3664 | |
3665 | static struct c_typespec |
3666 | c_parser_enum_specifier (c_parser *parser) |
3667 | { |
3668 | struct c_typespec ret; |
3669 | bool have_std_attrs; |
3670 | tree std_attrs = NULL_TREE; |
3671 | tree attrs; |
3672 | tree ident = NULL_TREE; |
3673 | tree fixed_underlying_type = NULL_TREE; |
3674 | location_t enum_loc; |
3675 | location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
3676 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); |
3677 | c_parser_consume_token (parser); |
3678 | have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); |
3679 | if (have_std_attrs) |
3680 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3681 | attrs = c_parser_gnu_attributes (parser); |
3682 | enum_loc = c_parser_peek_token (parser)->location; |
3683 | /* Set the location in case we create a decl now. */ |
3684 | c_parser_set_source_position_from_token (token: c_parser_peek_token (parser)); |
3685 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
3686 | { |
3687 | ident = c_parser_peek_token (parser)->value; |
3688 | ident_loc = c_parser_peek_token (parser)->location; |
3689 | enum_loc = ident_loc; |
3690 | c_parser_consume_token (parser); |
3691 | } |
3692 | if (c_parser_next_token_is (parser, type: CPP_COLON) |
3693 | /* Distinguish an enum-type-specifier from a bit-field |
3694 | declaration of the form "enum e : constant-expression;". */ |
3695 | && c_token_starts_typename (token: c_parser_peek_2nd_token (parser))) |
3696 | { |
3697 | pedwarn_c11 (enum_loc, opt: OPT_Wpedantic, |
3698 | "ISO C does not support specifying %<enum%> underlying " |
3699 | "types before C23" ); |
3700 | if (ident) |
3701 | { |
3702 | /* The tag is in scope during the enum-type-specifier (which |
3703 | may refer to the tag inside typeof). */ |
3704 | ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, |
3705 | have_std_attrs, std_attrs, true); |
3706 | if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)) |
3707 | error_at (enum_loc, "%<enum%> declared both with and without " |
3708 | "fixed underlying type" ); |
3709 | } |
3710 | else |
3711 | { |
3712 | /* There must be an enum definition, so this initialization |
3713 | (to avoid possible warnings about uninitialized data) |
3714 | will be replaced later (either with the results of that |
3715 | definition, or with the results of error handling for the |
3716 | case of no tag and no definition). */ |
3717 | ret.spec = NULL_TREE; |
3718 | ret.kind = ctsk_tagdef; |
3719 | ret.expr = NULL_TREE; |
3720 | ret.expr_const_operands = true; |
3721 | ret.has_enum_type_specifier = true; |
3722 | } |
3723 | c_parser_consume_token (parser); |
3724 | struct c_declspecs *specs = build_null_declspecs (); |
3725 | c_parser_declspecs (parser, specs, scspec_ok: false, typespec_ok: true, start_attr_ok: false, alignspec_ok: false, auto_type_ok: false, |
3726 | start_std_attr_ok: false, end_std_attr_ok: true, la: cla_prefer_id); |
3727 | finish_declspecs (specs); |
3728 | if (specs->default_int_p) |
3729 | error_at (enum_loc, "no %<enum%> underlying type specified" ); |
3730 | else if (TREE_CODE (specs->type) != INTEGER_TYPE |
3731 | && TREE_CODE (specs->type) != BOOLEAN_TYPE) |
3732 | { |
3733 | error_at (enum_loc, "invalid %<enum%> underlying type" ); |
3734 | specs->type = integer_type_node; |
3735 | } |
3736 | else if (specs->restrict_p) |
3737 | error_at (enum_loc, "invalid use of %<restrict%>" ); |
3738 | fixed_underlying_type = TYPE_MAIN_VARIANT (specs->type); |
3739 | if (ident) |
3740 | { |
3741 | /* The type specified must be consistent with any previously |
3742 | specified underlying type. If this is a newly declared |
3743 | type, it is now a complete type. */ |
3744 | if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) |
3745 | && ENUM_UNDERLYING_TYPE (ret.spec) == NULL_TREE) |
3746 | { |
3747 | TYPE_MIN_VALUE (ret.spec) = |
3748 | TYPE_MIN_VALUE (fixed_underlying_type); |
3749 | TYPE_MAX_VALUE (ret.spec) = |
3750 | TYPE_MAX_VALUE (fixed_underlying_type); |
3751 | TYPE_UNSIGNED (ret.spec) = TYPE_UNSIGNED (fixed_underlying_type); |
3752 | SET_TYPE_ALIGN (ret.spec, TYPE_ALIGN (fixed_underlying_type)); |
3753 | TYPE_SIZE (ret.spec) = NULL_TREE; |
3754 | TYPE_PRECISION (ret.spec) = |
3755 | TYPE_PRECISION (fixed_underlying_type); |
3756 | ENUM_UNDERLYING_TYPE (ret.spec) = fixed_underlying_type; |
3757 | layout_type (ret.spec); |
3758 | } |
3759 | else if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) |
3760 | && !comptypes (fixed_underlying_type, |
3761 | ENUM_UNDERLYING_TYPE (ret.spec))) |
3762 | { |
3763 | error_at (enum_loc, "%<enum%> underlying type incompatible with " |
3764 | "previous declaration" ); |
3765 | fixed_underlying_type = ENUM_UNDERLYING_TYPE (ret.spec); |
3766 | } |
3767 | } |
3768 | } |
3769 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
3770 | { |
3771 | /* Parse an enum definition. */ |
3772 | struct c_enum_contents the_enum; |
3773 | tree type; |
3774 | tree postfix_attrs; |
3775 | /* We chain the enumerators in reverse order, then put them in |
3776 | forward order at the end. */ |
3777 | tree values; |
3778 | timevar_push (tv: TV_PARSE_ENUM); |
3779 | type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type); |
3780 | values = NULL_TREE; |
3781 | c_parser_consume_token (parser); |
3782 | while (true) |
3783 | { |
3784 | tree enum_id; |
3785 | tree enum_value; |
3786 | tree enum_decl; |
3787 | bool seen_comma; |
3788 | c_token *token; |
3789 | location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
3790 | location_t decl_loc, value_loc; |
3791 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
3792 | { |
3793 | /* Give a nicer error for "enum {}". */ |
3794 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE) |
3795 | && !parser->error) |
3796 | { |
3797 | error_at (c_parser_peek_token (parser)->location, |
3798 | "empty enum is invalid" ); |
3799 | parser->error = true; |
3800 | } |
3801 | else |
3802 | c_parser_error (parser, gmsgid: "expected identifier" ); |
3803 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
3804 | values = error_mark_node; |
3805 | break; |
3806 | } |
3807 | token = c_parser_peek_token (parser); |
3808 | enum_id = token->value; |
3809 | /* Set the location in case we create a decl now. */ |
3810 | c_parser_set_source_position_from_token (token); |
3811 | decl_loc = value_loc = token->location; |
3812 | c_parser_consume_token (parser); |
3813 | /* Parse any specified attributes. */ |
3814 | tree std_attrs = NULL_TREE; |
3815 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
3816 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3817 | tree enum_attrs = chainon (std_attrs, |
3818 | c_parser_gnu_attributes (parser)); |
3819 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
3820 | { |
3821 | c_parser_consume_token (parser); |
3822 | value_loc = c_parser_peek_token (parser)->location; |
3823 | enum_value = convert_lvalue_to_rvalue (value_loc, |
3824 | (c_parser_expr_no_commas |
3825 | (parser, NULL)), |
3826 | true, true).value; |
3827 | } |
3828 | else |
3829 | enum_value = NULL_TREE; |
3830 | enum_decl = build_enumerator (decl_loc, value_loc, |
3831 | &the_enum, enum_id, enum_value); |
3832 | if (enum_attrs) |
3833 | decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0); |
3834 | TREE_CHAIN (enum_decl) = values; |
3835 | values = enum_decl; |
3836 | seen_comma = false; |
3837 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
3838 | { |
3839 | comma_loc = c_parser_peek_token (parser)->location; |
3840 | seen_comma = true; |
3841 | c_parser_consume_token (parser); |
3842 | } |
3843 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
3844 | { |
3845 | if (seen_comma) |
3846 | pedwarn_c90 (comma_loc, opt: OPT_Wpedantic, |
3847 | "comma at end of enumerator list" ); |
3848 | c_parser_consume_token (parser); |
3849 | break; |
3850 | } |
3851 | if (!seen_comma) |
3852 | { |
3853 | c_parser_error (parser, gmsgid: "expected %<,%> or %<}%>" ); |
3854 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
3855 | values = error_mark_node; |
3856 | break; |
3857 | } |
3858 | } |
3859 | postfix_attrs = c_parser_gnu_attributes (parser); |
3860 | ret.spec = finish_enum (type, nreverse (values), |
3861 | chainon (std_attrs, |
3862 | chainon (attrs, postfix_attrs))); |
3863 | ret.kind = ctsk_tagdef; |
3864 | ret.expr = NULL_TREE; |
3865 | ret.expr_const_operands = true; |
3866 | ret.has_enum_type_specifier = fixed_underlying_type != NULL_TREE; |
3867 | timevar_pop (tv: TV_PARSE_ENUM); |
3868 | return ret; |
3869 | } |
3870 | else if (!ident) |
3871 | { |
3872 | c_parser_error (parser, gmsgid: "expected %<{%>" ); |
3873 | ret.spec = error_mark_node; |
3874 | ret.kind = ctsk_tagref; |
3875 | ret.expr = NULL_TREE; |
3876 | ret.expr_const_operands = true; |
3877 | ret.has_enum_type_specifier = false; |
3878 | return ret; |
3879 | } |
3880 | /* Attributes may only appear when the members are defined or in |
3881 | certain forward declarations (treat enum forward declarations in |
3882 | GNU C analogously to struct and union forward declarations in |
3883 | standard C). */ |
3884 | if (have_std_attrs && c_parser_next_token_is_not (parser, type: CPP_SEMICOLON)) |
3885 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
3886 | if (fixed_underlying_type == NULL_TREE) |
3887 | { |
3888 | ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, |
3889 | std_attrs, false); |
3890 | /* In ISO C, enumerated types without a fixed underlying type |
3891 | can be referred to only if already defined. */ |
3892 | if (pedantic && !COMPLETE_TYPE_P (ret.spec)) |
3893 | { |
3894 | gcc_assert (ident); |
3895 | pedwarn (enum_loc, OPT_Wpedantic, |
3896 | "ISO C forbids forward references to %<enum%> types" ); |
3897 | } |
3898 | } |
3899 | return ret; |
3900 | } |
3901 | |
3902 | /* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1). |
3903 | |
3904 | struct-or-union-specifier: |
3905 | struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] |
3906 | identifier[opt] { struct-contents } gnu-attributes[opt] |
3907 | struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] |
3908 | identifier |
3909 | |
3910 | struct-contents: |
3911 | struct-declaration-list |
3912 | |
3913 | struct-declaration-list: |
3914 | struct-declaration ; |
3915 | struct-declaration-list struct-declaration ; |
3916 | |
3917 | GNU extensions: |
3918 | |
3919 | struct-contents: |
3920 | empty |
3921 | struct-declaration |
3922 | struct-declaration-list struct-declaration |
3923 | |
3924 | struct-declaration-list: |
3925 | struct-declaration-list ; |
3926 | ; |
3927 | |
3928 | (Note that in the syntax here, unlike that in ISO C, the semicolons |
3929 | are included here rather than in struct-declaration, in order to |
3930 | describe the syntax with extra semicolons and missing semicolon at |
3931 | end.) |
3932 | |
3933 | Objective-C: |
3934 | |
3935 | struct-declaration-list: |
3936 | @defs ( class-name ) |
3937 | |
3938 | (Note this does not include a trailing semicolon, but can be |
3939 | followed by further declarations, and gets a pedwarn-if-pedantic |
3940 | when followed by a semicolon.) */ |
3941 | |
3942 | static struct c_typespec |
3943 | c_parser_struct_or_union_specifier (c_parser *parser) |
3944 | { |
3945 | struct c_typespec ret; |
3946 | bool have_std_attrs; |
3947 | tree std_attrs = NULL_TREE; |
3948 | tree attrs; |
3949 | tree ident = NULL_TREE; |
3950 | location_t struct_loc; |
3951 | location_t ident_loc = UNKNOWN_LOCATION; |
3952 | enum tree_code code; |
3953 | switch (c_parser_peek_token (parser)->keyword) |
3954 | { |
3955 | case RID_STRUCT: |
3956 | code = RECORD_TYPE; |
3957 | break; |
3958 | case RID_UNION: |
3959 | code = UNION_TYPE; |
3960 | break; |
3961 | default: |
3962 | gcc_unreachable (); |
3963 | } |
3964 | struct_loc = c_parser_peek_token (parser)->location; |
3965 | c_parser_consume_token (parser); |
3966 | have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); |
3967 | if (have_std_attrs) |
3968 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3969 | attrs = c_parser_gnu_attributes (parser); |
3970 | |
3971 | /* Set the location in case we create a decl now. */ |
3972 | c_parser_set_source_position_from_token (token: c_parser_peek_token (parser)); |
3973 | |
3974 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
3975 | { |
3976 | ident = c_parser_peek_token (parser)->value; |
3977 | ident_loc = c_parser_peek_token (parser)->location; |
3978 | struct_loc = ident_loc; |
3979 | c_parser_consume_token (parser); |
3980 | } |
3981 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
3982 | { |
3983 | /* Parse a struct or union definition. Start the scope of the |
3984 | tag before parsing components. */ |
3985 | class c_struct_parse_info *struct_info; |
3986 | tree type = start_struct (struct_loc, code, ident, &struct_info); |
3987 | tree postfix_attrs; |
3988 | /* We chain the components in reverse order, then put them in |
3989 | forward order at the end. Each struct-declaration may |
3990 | declare multiple components (comma-separated), so we must use |
3991 | chainon to join them, although when parsing each |
3992 | struct-declaration we can use TREE_CHAIN directly. |
3993 | |
3994 | The theory behind all this is that there will be more |
3995 | semicolon separated fields than comma separated fields, and |
3996 | so we'll be minimizing the number of node traversals required |
3997 | by chainon. */ |
3998 | tree contents; |
3999 | tree expr = NULL; |
4000 | timevar_push (tv: TV_PARSE_STRUCT); |
4001 | contents = NULL_TREE; |
4002 | c_parser_consume_token (parser); |
4003 | /* Handle the Objective-C @defs construct, |
4004 | e.g. foo(sizeof(struct{ @defs(ClassName) }));. */ |
4005 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_DEFS)) |
4006 | { |
4007 | tree name; |
4008 | gcc_assert (c_dialect_objc ()); |
4009 | c_parser_consume_token (parser); |
4010 | matching_parens parens; |
4011 | if (!parens.require_open (parser)) |
4012 | goto end_at_defs; |
4013 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
4014 | && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) |
4015 | { |
4016 | name = c_parser_peek_token (parser)->value; |
4017 | c_parser_consume_token (parser); |
4018 | } |
4019 | else |
4020 | { |
4021 | c_parser_error (parser, gmsgid: "expected class name" ); |
4022 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
4023 | goto end_at_defs; |
4024 | } |
4025 | parens.skip_until_found_close (parser); |
4026 | contents = nreverse (objc_get_class_ivars (name)); |
4027 | } |
4028 | end_at_defs: |
4029 | /* Parse the struct-declarations and semicolons. Problems with |
4030 | semicolons are diagnosed here; empty structures are diagnosed |
4031 | elsewhere. */ |
4032 | while (true) |
4033 | { |
4034 | tree decls; |
4035 | /* Parse any stray semicolon. */ |
4036 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
4037 | { |
4038 | location_t semicolon_loc |
4039 | = c_parser_peek_token (parser)->location; |
4040 | gcc_rich_location richloc (semicolon_loc); |
4041 | richloc.add_fixit_remove (); |
4042 | pedwarn (&richloc, OPT_Wpedantic, |
4043 | "extra semicolon in struct or union specified" ); |
4044 | c_parser_consume_token (parser); |
4045 | continue; |
4046 | } |
4047 | /* Stop if at the end of the struct or union contents. */ |
4048 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4049 | { |
4050 | c_parser_consume_token (parser); |
4051 | break; |
4052 | } |
4053 | /* Accept #pragmas at struct scope. */ |
4054 | if (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
4055 | { |
4056 | c_parser_pragma (parser, pragma_struct, NULL); |
4057 | continue; |
4058 | } |
4059 | /* Parse some comma-separated declarations, but not the |
4060 | trailing semicolon if any. */ |
4061 | decls = c_parser_struct_declaration (parser, &expr); |
4062 | contents = chainon (decls, contents); |
4063 | /* If no semicolon follows, either we have a parse error or |
4064 | are at the end of the struct or union and should |
4065 | pedwarn. */ |
4066 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
4067 | c_parser_consume_token (parser); |
4068 | else |
4069 | { |
4070 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4071 | pedwarn (c_parser_peek_token (parser)->location, 0, |
4072 | "no semicolon at end of struct or union" ); |
4073 | else if (parser->error |
4074 | || !c_parser_next_token_starts_declspecs (parser)) |
4075 | { |
4076 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
4077 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
4078 | break; |
4079 | } |
4080 | |
4081 | /* If we come here, we have already emitted an error |
4082 | for an expected `;', identifier or `(', and we also |
4083 | recovered already. Go on with the next field. */ |
4084 | } |
4085 | } |
4086 | postfix_attrs = c_parser_gnu_attributes (parser); |
4087 | ret.spec = finish_struct (struct_loc, type, nreverse (contents), |
4088 | chainon (std_attrs, |
4089 | chainon (attrs, postfix_attrs)), |
4090 | struct_info); |
4091 | ret.kind = ctsk_tagdef; |
4092 | ret.expr = expr; |
4093 | ret.expr_const_operands = true; |
4094 | ret.has_enum_type_specifier = false; |
4095 | timevar_pop (tv: TV_PARSE_STRUCT); |
4096 | return ret; |
4097 | } |
4098 | else if (!ident) |
4099 | { |
4100 | c_parser_error (parser, gmsgid: "expected %<{%>" ); |
4101 | ret.spec = error_mark_node; |
4102 | ret.kind = ctsk_tagref; |
4103 | ret.expr = NULL_TREE; |
4104 | ret.expr_const_operands = true; |
4105 | ret.has_enum_type_specifier = false; |
4106 | return ret; |
4107 | } |
4108 | /* Attributes may only appear when the members are defined or in |
4109 | certain forward declarations. */ |
4110 | if (have_std_attrs && c_parser_next_token_is_not (parser, type: CPP_SEMICOLON)) |
4111 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
4112 | /* ??? Existing practice is that GNU attributes are ignored after |
4113 | the struct or union keyword when not defining the members. */ |
4114 | ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs, |
4115 | false); |
4116 | return ret; |
4117 | } |
4118 | |
4119 | /* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1), |
4120 | *without* the trailing semicolon. |
4121 | |
4122 | struct-declaration: |
4123 | attribute-specifier-sequence[opt] specifier-qualifier-list |
4124 | attribute-specifier-sequence[opt] struct-declarator-list |
4125 | static_assert-declaration-no-semi |
4126 | |
4127 | specifier-qualifier-list: |
4128 | type-specifier specifier-qualifier-list[opt] |
4129 | type-qualifier specifier-qualifier-list[opt] |
4130 | alignment-specifier specifier-qualifier-list[opt] |
4131 | gnu-attributes specifier-qualifier-list[opt] |
4132 | |
4133 | struct-declarator-list: |
4134 | struct-declarator |
4135 | struct-declarator-list , gnu-attributes[opt] struct-declarator |
4136 | |
4137 | struct-declarator: |
4138 | declarator gnu-attributes[opt] |
4139 | declarator[opt] : constant-expression gnu-attributes[opt] |
4140 | |
4141 | GNU extensions: |
4142 | |
4143 | struct-declaration: |
4144 | __extension__ struct-declaration |
4145 | specifier-qualifier-list |
4146 | |
4147 | Unlike the ISO C syntax, semicolons are handled elsewhere. The use |
4148 | of gnu-attributes where shown is a GNU extension. In GNU C, we accept |
4149 | any expression without commas in the syntax (assignment |
4150 | expressions, not just conditional expressions); assignment |
4151 | expressions will be diagnosed as non-constant. */ |
4152 | |
4153 | static tree |
4154 | c_parser_struct_declaration (c_parser *parser, tree *expr) |
4155 | { |
4156 | struct c_declspecs *specs; |
4157 | tree prefix_attrs; |
4158 | tree all_prefix_attrs; |
4159 | tree decls; |
4160 | location_t decl_loc; |
4161 | if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
4162 | { |
4163 | int ext; |
4164 | tree decl; |
4165 | ext = disable_extension_diagnostics (); |
4166 | c_parser_consume_token (parser); |
4167 | decl = c_parser_struct_declaration (parser, expr); |
4168 | restore_extension_diagnostics (flags: ext); |
4169 | return decl; |
4170 | } |
4171 | if (c_parser_next_token_is_keyword (parser, keyword: RID_STATIC_ASSERT)) |
4172 | { |
4173 | c_parser_static_assert_declaration_no_semi (parser); |
4174 | return NULL_TREE; |
4175 | } |
4176 | specs = build_null_declspecs (); |
4177 | decl_loc = c_parser_peek_token (parser)->location; |
4178 | /* Strictly by the standard, we shouldn't allow _Alignas here, |
4179 | but it appears to have been intended to allow it there, so |
4180 | we're keeping it as it is until WG14 reaches a conclusion |
4181 | of N1731. |
4182 | <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf> */ |
4183 | c_parser_declspecs (parser, specs, scspec_ok: false, typespec_ok: true, start_attr_ok: true, |
4184 | alignspec_ok: true, auto_type_ok: false, start_std_attr_ok: true, end_std_attr_ok: true, la: cla_nonabstract_decl); |
4185 | if (parser->error) |
4186 | return NULL_TREE; |
4187 | if (!specs->declspecs_seen_p) |
4188 | { |
4189 | c_parser_error (parser, gmsgid: "expected specifier-qualifier-list" ); |
4190 | return NULL_TREE; |
4191 | } |
4192 | finish_declspecs (specs); |
4193 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
4194 | || c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4195 | { |
4196 | tree ret; |
4197 | if (specs->typespec_kind == ctsk_none) |
4198 | { |
4199 | pedwarn (decl_loc, OPT_Wpedantic, |
4200 | "ISO C forbids member declarations with no members" ); |
4201 | shadow_tag_warned (specs, pedantic); |
4202 | ret = NULL_TREE; |
4203 | } |
4204 | else |
4205 | { |
4206 | /* Support for unnamed structs or unions as members of |
4207 | structs or unions (which is [a] useful and [b] supports |
4208 | MS P-SDK). */ |
4209 | tree attrs = NULL; |
4210 | |
4211 | ret = grokfield (c_parser_peek_token (parser)->location, |
4212 | build_id_declarator (NULL_TREE), specs, |
4213 | NULL_TREE, &attrs, expr); |
4214 | if (ret) |
4215 | decl_attributes (&ret, attrs, 0); |
4216 | } |
4217 | return ret; |
4218 | } |
4219 | |
4220 | /* Provide better error recovery. Note that a type name here is valid, |
4221 | and will be treated as a field name. */ |
4222 | if (specs->typespec_kind == ctsk_tagdef |
4223 | && TREE_CODE (specs->type) != ENUMERAL_TYPE |
4224 | && c_parser_next_token_starts_declspecs (parser) |
4225 | && !c_parser_next_token_is (parser, type: CPP_NAME)) |
4226 | { |
4227 | c_parser_error (parser, gmsgid: "expected %<;%>, identifier or %<(%>" ); |
4228 | parser->error = false; |
4229 | return NULL_TREE; |
4230 | } |
4231 | |
4232 | pending_xref_error (); |
4233 | prefix_attrs = specs->attrs; |
4234 | all_prefix_attrs = prefix_attrs; |
4235 | specs->attrs = NULL_TREE; |
4236 | decls = NULL_TREE; |
4237 | while (true) |
4238 | { |
4239 | /* Declaring one or more declarators or un-named bit-fields. */ |
4240 | struct c_declarator *declarator; |
4241 | bool dummy = false; |
4242 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
4243 | declarator = build_id_declarator (NULL_TREE); |
4244 | else |
4245 | declarator = c_parser_declarator (parser, |
4246 | type_seen_p: specs->typespec_kind != ctsk_none, |
4247 | kind: C_DTR_NORMAL, seen_id: &dummy); |
4248 | if (declarator == NULL) |
4249 | { |
4250 | c_parser_skip_to_end_of_block_or_statement (parser); |
4251 | break; |
4252 | } |
4253 | if (c_parser_next_token_is (parser, type: CPP_COLON) |
4254 | || c_parser_next_token_is (parser, type: CPP_COMMA) |
4255 | || c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
4256 | || c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE) |
4257 | || c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
4258 | { |
4259 | tree postfix_attrs = NULL_TREE; |
4260 | tree width = NULL_TREE; |
4261 | tree d; |
4262 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
4263 | { |
4264 | c_parser_consume_token (parser); |
4265 | location_t loc = c_parser_peek_token (parser)->location; |
4266 | width = convert_lvalue_to_rvalue (loc, |
4267 | (c_parser_expr_no_commas |
4268 | (parser, NULL)), |
4269 | true, true).value; |
4270 | } |
4271 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
4272 | postfix_attrs = c_parser_gnu_attributes (parser); |
4273 | d = grokfield (c_parser_peek_token (parser)->location, |
4274 | declarator, specs, width, &all_prefix_attrs, expr); |
4275 | decl_attributes (&d, chainon (postfix_attrs, |
4276 | all_prefix_attrs), 0); |
4277 | DECL_CHAIN (d) = decls; |
4278 | decls = d; |
4279 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
4280 | all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), |
4281 | prefix_attrs); |
4282 | else |
4283 | all_prefix_attrs = prefix_attrs; |
4284 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
4285 | c_parser_consume_token (parser); |
4286 | else if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
4287 | || c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4288 | { |
4289 | /* Semicolon consumed in caller. */ |
4290 | break; |
4291 | } |
4292 | else |
4293 | { |
4294 | c_parser_error (parser, gmsgid: "expected %<,%>, %<;%> or %<}%>" ); |
4295 | break; |
4296 | } |
4297 | } |
4298 | else |
4299 | { |
4300 | c_parser_error (parser, |
4301 | gmsgid: "expected %<:%>, %<,%>, %<;%>, %<}%> or " |
4302 | "%<__attribute__%>" ); |
4303 | break; |
4304 | } |
4305 | } |
4306 | return decls; |
4307 | } |
4308 | |
4309 | /* Parse a typeof specifier (a GNU extension adopted in C23). |
4310 | |
4311 | typeof-specifier: |
4312 | typeof ( expression ) |
4313 | typeof ( type-name ) |
4314 | typeof_unqual ( expression ) |
4315 | typeof_unqual ( type-name ) |
4316 | */ |
4317 | |
4318 | static struct c_typespec |
4319 | c_parser_typeof_specifier (c_parser *parser) |
4320 | { |
4321 | bool is_unqual; |
4322 | bool is_std; |
4323 | struct c_typespec ret; |
4324 | ret.kind = ctsk_typeof; |
4325 | ret.spec = error_mark_node; |
4326 | ret.expr = NULL_TREE; |
4327 | ret.expr_const_operands = true; |
4328 | ret.has_enum_type_specifier = false; |
4329 | if (c_parser_next_token_is_keyword (parser, keyword: RID_TYPEOF)) |
4330 | { |
4331 | is_unqual = false; |
4332 | tree spelling = c_parser_peek_token (parser)->value; |
4333 | is_std = (flag_isoc23 |
4334 | && strcmp (IDENTIFIER_POINTER (spelling), s2: "typeof" ) == 0); |
4335 | } |
4336 | else |
4337 | { |
4338 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL)); |
4339 | is_unqual = true; |
4340 | tree spelling = c_parser_peek_token (parser)->value; |
4341 | is_std = strcmp (IDENTIFIER_POINTER (spelling), s2: "typeof_unqual" ) == 0; |
4342 | } |
4343 | c_parser_consume_token (parser); |
4344 | c_inhibit_evaluation_warnings++; |
4345 | in_typeof++; |
4346 | matching_parens parens; |
4347 | if (!parens.require_open (parser)) |
4348 | { |
4349 | c_inhibit_evaluation_warnings--; |
4350 | in_typeof--; |
4351 | return ret; |
4352 | } |
4353 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
4354 | { |
4355 | struct c_type_name *type = c_parser_type_name (parser); |
4356 | c_inhibit_evaluation_warnings--; |
4357 | in_typeof--; |
4358 | if (type != NULL) |
4359 | { |
4360 | ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); |
4361 | pop_maybe_used (c_type_variably_modified_p (t: ret.spec)); |
4362 | } |
4363 | } |
4364 | else |
4365 | { |
4366 | bool was_vm; |
4367 | location_t here = c_parser_peek_token (parser)->location; |
4368 | struct c_expr expr = c_parser_expression (parser); |
4369 | c_inhibit_evaluation_warnings--; |
4370 | in_typeof--; |
4371 | if (TREE_CODE (expr.value) == COMPONENT_REF |
4372 | && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) |
4373 | error_at (here, "%<typeof%> applied to a bit-field" ); |
4374 | mark_exp_read (expr.value); |
4375 | ret.spec = TREE_TYPE (expr.value); |
4376 | was_vm = c_type_variably_modified_p (t: ret.spec); |
4377 | /* This is returned with the type so that when the type is |
4378 | evaluated, this can be evaluated. */ |
4379 | if (was_vm) |
4380 | ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands); |
4381 | pop_maybe_used (was_vm); |
4382 | } |
4383 | parens.skip_until_found_close (parser); |
4384 | if (ret.spec != error_mark_node) |
4385 | { |
4386 | if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED) |
4387 | ret.spec = TYPE_MAIN_VARIANT (ret.spec); |
4388 | if (is_std) |
4389 | { |
4390 | /* In ISO C terms, _Noreturn is not part of the type of |
4391 | expressions such as &abort, but in GCC it is represented |
4392 | internally as a type qualifier. */ |
4393 | if (TREE_CODE (ret.spec) == FUNCTION_TYPE |
4394 | && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED) |
4395 | ret.spec = TYPE_MAIN_VARIANT (ret.spec); |
4396 | else if (FUNCTION_POINTER_TYPE_P (ret.spec) |
4397 | && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED) |
4398 | ret.spec |
4399 | = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec))); |
4400 | } |
4401 | } |
4402 | return ret; |
4403 | } |
4404 | |
4405 | /* Parse an alignment-specifier. |
4406 | |
4407 | C11 6.7.5: |
4408 | |
4409 | alignment-specifier: |
4410 | _Alignas ( type-name ) |
4411 | _Alignas ( constant-expression ) |
4412 | */ |
4413 | |
4414 | static tree |
4415 | c_parser_alignas_specifier (c_parser * parser) |
4416 | { |
4417 | tree ret = error_mark_node; |
4418 | location_t loc = c_parser_peek_token (parser)->location; |
4419 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); |
4420 | tree spelling = c_parser_peek_token (parser)->value; |
4421 | c_parser_consume_token (parser); |
4422 | if (flag_isoc99) |
4423 | pedwarn_c99 (loc, opt: OPT_Wpedantic, |
4424 | "ISO C99 does not support %qE" , spelling); |
4425 | else |
4426 | pedwarn_c99 (loc, opt: OPT_Wpedantic, |
4427 | "ISO C90 does not support %qE" , spelling); |
4428 | matching_parens parens; |
4429 | if (!parens.require_open (parser)) |
4430 | return ret; |
4431 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
4432 | { |
4433 | struct c_type_name *type = c_parser_type_name (parser); |
4434 | if (type != NULL) |
4435 | ret = c_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL), |
4436 | false, true, 1); |
4437 | } |
4438 | else |
4439 | ret = convert_lvalue_to_rvalue (loc, |
4440 | c_parser_expr_no_commas (parser, NULL), |
4441 | true, true).value; |
4442 | parens.skip_until_found_close (parser); |
4443 | return ret; |
4444 | } |
4445 | |
4446 | /* Parse a declarator, possibly an abstract declarator (C90 6.5.4, |
4447 | 6.5.5, C99 6.7.5, 6.7.6, C11 6.7.6, 6.7.7). If TYPE_SEEN_P then |
4448 | a typedef name may be redeclared; otherwise it may not. KIND |
4449 | indicates which kind of declarator is wanted. Returns a valid |
4450 | declarator except in the case of a syntax error in which case NULL is |
4451 | returned. *SEEN_ID is set to true if an identifier being declared is |
4452 | seen; this is used to diagnose bad forms of abstract array declarators |
4453 | and to determine whether an identifier list is syntactically permitted. |
4454 | |
4455 | declarator: |
4456 | pointer[opt] direct-declarator |
4457 | |
4458 | direct-declarator: |
4459 | identifier |
4460 | ( gnu-attributes[opt] declarator ) |
4461 | direct-declarator array-declarator |
4462 | direct-declarator ( parameter-type-list ) |
4463 | direct-declarator ( identifier-list[opt] ) |
4464 | |
4465 | pointer: |
4466 | * type-qualifier-list[opt] |
4467 | * type-qualifier-list[opt] pointer |
4468 | |
4469 | type-qualifier-list: |
4470 | type-qualifier |
4471 | gnu-attributes |
4472 | type-qualifier-list type-qualifier |
4473 | type-qualifier-list gnu-attributes |
4474 | |
4475 | array-declarator: |
4476 | [ type-qualifier-list[opt] assignment-expression[opt] ] |
4477 | [ static type-qualifier-list[opt] assignment-expression ] |
4478 | [ type-qualifier-list static assignment-expression ] |
4479 | [ type-qualifier-list[opt] * ] |
4480 | |
4481 | parameter-type-list: |
4482 | parameter-list |
4483 | parameter-list , ... |
4484 | |
4485 | parameter-list: |
4486 | parameter-declaration |
4487 | parameter-list , parameter-declaration |
4488 | |
4489 | parameter-declaration: |
4490 | declaration-specifiers declarator gnu-attributes[opt] |
4491 | declaration-specifiers abstract-declarator[opt] gnu-attributes[opt] |
4492 | |
4493 | identifier-list: |
4494 | identifier |
4495 | identifier-list , identifier |
4496 | |
4497 | abstract-declarator: |
4498 | pointer |
4499 | pointer[opt] direct-abstract-declarator |
4500 | |
4501 | direct-abstract-declarator: |
4502 | ( gnu-attributes[opt] abstract-declarator ) |
4503 | direct-abstract-declarator[opt] array-declarator |
4504 | direct-abstract-declarator[opt] ( parameter-type-list[opt] ) |
4505 | |
4506 | GNU extensions: |
4507 | |
4508 | direct-declarator: |
4509 | direct-declarator ( parameter-forward-declarations |
4510 | parameter-type-list[opt] ) |
4511 | |
4512 | direct-abstract-declarator: |
4513 | direct-abstract-declarator[opt] ( parameter-forward-declarations |
4514 | parameter-type-list[opt] ) |
4515 | |
4516 | parameter-forward-declarations: |
4517 | parameter-list ; |
4518 | parameter-forward-declarations parameter-list ; |
4519 | |
4520 | The uses of gnu-attributes shown above are GNU extensions. |
4521 | |
4522 | Some forms of array declarator are not included in C99 in the |
4523 | syntax for abstract declarators; these are disallowed elsewhere. |
4524 | This may be a defect (DR#289). |
4525 | |
4526 | This function also accepts an omitted abstract declarator as being |
4527 | an abstract declarator, although not part of the formal syntax. */ |
4528 | |
4529 | struct c_declarator * |
4530 | c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, |
4531 | bool *seen_id) |
4532 | { |
4533 | /* Parse any initial pointer part. */ |
4534 | if (c_parser_next_token_is (parser, type: CPP_MULT)) |
4535 | { |
4536 | struct c_declspecs *quals_attrs = build_null_declspecs (); |
4537 | struct c_declarator *inner; |
4538 | c_parser_consume_token (parser); |
4539 | c_parser_declspecs (parser, specs: quals_attrs, scspec_ok: false, typespec_ok: false, start_attr_ok: true, |
4540 | alignspec_ok: false, auto_type_ok: false, start_std_attr_ok: true, end_std_attr_ok: false, la: cla_prefer_id); |
4541 | inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); |
4542 | if (inner == NULL) |
4543 | return NULL; |
4544 | else |
4545 | return make_pointer_declarator (quals_attrs, inner); |
4546 | } |
4547 | /* Now we have a direct declarator, direct abstract declarator or |
4548 | nothing (which counts as a direct abstract declarator here). */ |
4549 | return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id); |
4550 | } |
4551 | |
4552 | /* Parse a direct declarator or direct abstract declarator; arguments |
4553 | as c_parser_declarator. */ |
4554 | |
4555 | static struct c_declarator * |
4556 | c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, |
4557 | bool *seen_id) |
4558 | { |
4559 | /* The direct declarator must start with an identifier (possibly |
4560 | omitted) or a parenthesized declarator (possibly abstract). In |
4561 | an ordinary declarator, initial parentheses must start a |
4562 | parenthesized declarator. In an abstract declarator or parameter |
4563 | declarator, they could start a parenthesized declarator or a |
4564 | parameter list. To tell which, the open parenthesis and any |
4565 | following gnu-attributes must be read. If a declaration |
4566 | specifier or standard attributes follow, then it is a parameter |
4567 | list; if the specifier is a typedef name, there might be an |
4568 | ambiguity about redeclaring it, which is resolved in the |
4569 | direction of treating it as a typedef name. If a close |
4570 | parenthesis follows, it is also an empty parameter list, as the |
4571 | syntax does not permit empty abstract declarators. Otherwise, it |
4572 | is a parenthesized declarator (in which case the analysis may be |
4573 | repeated inside it, recursively). |
4574 | |
4575 | ??? There is an ambiguity in a parameter declaration "int |
4576 | (__attribute__((foo)) x)", where x is not a typedef name: it |
4577 | could be an abstract declarator for a function, or declare x with |
4578 | parentheses. The proper resolution of this ambiguity needs |
4579 | documenting. At present we follow an accident of the old |
4580 | parser's implementation, whereby the first parameter must have |
4581 | some declaration specifiers other than just gnu-attributes. Thus as |
4582 | a parameter declaration it is treated as a parenthesized |
4583 | parameter named x, and as an abstract declarator it is |
4584 | rejected. |
4585 | |
4586 | ??? Also following the old parser, gnu-attributes inside an empty |
4587 | parameter list are ignored, making it a list not yielding a |
4588 | prototype, rather than giving an error or making it have one |
4589 | parameter with implicit type int. |
4590 | |
4591 | ??? Also following the old parser, typedef names may be |
4592 | redeclared in declarators, but not Objective-C class names. */ |
4593 | |
4594 | if (kind != C_DTR_ABSTRACT |
4595 | && c_parser_next_token_is (parser, type: CPP_NAME) |
4596 | && ((type_seen_p |
4597 | && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME |
4598 | || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) |
4599 | || c_parser_peek_token (parser)->id_kind == C_ID_ID)) |
4600 | { |
4601 | struct c_declarator *inner |
4602 | = build_id_declarator (c_parser_peek_token (parser)->value); |
4603 | *seen_id = true; |
4604 | inner->id_loc = c_parser_peek_token (parser)->location; |
4605 | c_parser_consume_token (parser); |
4606 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
4607 | inner->u.id.attrs = c_parser_std_attribute_specifier_sequence (parser); |
4608 | return c_parser_direct_declarator_inner (parser, *seen_id, inner); |
4609 | } |
4610 | |
4611 | if (kind != C_DTR_NORMAL |
4612 | && c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE) |
4613 | && !c_parser_nth_token_starts_std_attributes (parser, 1)) |
4614 | { |
4615 | struct c_declarator *inner = build_id_declarator (NULL_TREE); |
4616 | inner->id_loc = c_parser_peek_token (parser)->location; |
4617 | return c_parser_direct_declarator_inner (parser, *seen_id, inner); |
4618 | } |
4619 | |
4620 | /* Either we are at the end of an abstract declarator, or we have |
4621 | parentheses. */ |
4622 | |
4623 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
4624 | { |
4625 | tree attrs; |
4626 | struct c_declarator *inner; |
4627 | c_parser_consume_token (parser); |
4628 | bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, |
4629 | keyword: RID_ATTRIBUTE); |
4630 | attrs = c_parser_gnu_attributes (parser); |
4631 | if (kind != C_DTR_NORMAL |
4632 | && (c_parser_next_token_starts_declspecs (parser) |
4633 | || (!have_gnu_attrs |
4634 | && (c_parser_nth_token_starts_std_attributes (parser, 1) |
4635 | || c_parser_next_token_is (parser, type: CPP_ELLIPSIS))) |
4636 | || c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN))) |
4637 | { |
4638 | struct c_arg_info *args |
4639 | = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL, |
4640 | attrs, have_gnu_attrs); |
4641 | if (args == NULL) |
4642 | return NULL; |
4643 | else |
4644 | { |
4645 | inner = build_id_declarator (NULL_TREE); |
4646 | if (!(args->types |
4647 | && args->types != error_mark_node |
4648 | && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) |
4649 | && c_parser_nth_token_starts_std_attributes (parser, 1)) |
4650 | { |
4651 | tree std_attrs |
4652 | = c_parser_std_attribute_specifier_sequence (parser); |
4653 | if (std_attrs) |
4654 | inner = build_attrs_declarator (std_attrs, inner); |
4655 | } |
4656 | inner = build_function_declarator (args, inner); |
4657 | return c_parser_direct_declarator_inner (parser, *seen_id, |
4658 | inner); |
4659 | } |
4660 | } |
4661 | /* A parenthesized declarator. */ |
4662 | inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); |
4663 | if (inner != NULL && attrs != NULL) |
4664 | inner = build_attrs_declarator (attrs, inner); |
4665 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4666 | { |
4667 | c_parser_consume_token (parser); |
4668 | if (inner == NULL) |
4669 | return NULL; |
4670 | else |
4671 | return c_parser_direct_declarator_inner (parser, *seen_id, inner); |
4672 | } |
4673 | else |
4674 | { |
4675 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4676 | msgid: "expected %<)%>" ); |
4677 | return NULL; |
4678 | } |
4679 | } |
4680 | else |
4681 | { |
4682 | if (kind == C_DTR_NORMAL) |
4683 | { |
4684 | c_parser_error (parser, gmsgid: "expected identifier or %<(%>" ); |
4685 | return NULL; |
4686 | } |
4687 | else |
4688 | return build_id_declarator (NULL_TREE); |
4689 | } |
4690 | } |
4691 | |
4692 | /* Parse part of a direct declarator or direct abstract declarator, |
4693 | given that some (in INNER) has already been parsed; ID_PRESENT is |
4694 | true if an identifier is present, false for an abstract |
4695 | declarator. */ |
4696 | |
4697 | static struct c_declarator * |
4698 | c_parser_direct_declarator_inner (c_parser *parser, bool id_present, |
4699 | struct c_declarator *inner) |
4700 | { |
4701 | /* Parse a sequence of array declarators and parameter lists. */ |
4702 | if (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE) |
4703 | && !c_parser_nth_token_starts_std_attributes (parser, 1)) |
4704 | { |
4705 | location_t brace_loc = c_parser_peek_token (parser)->location; |
4706 | struct c_declarator *declarator; |
4707 | struct c_declspecs *quals_attrs = build_null_declspecs (); |
4708 | bool static_seen; |
4709 | bool star_seen; |
4710 | struct c_expr dimen; |
4711 | dimen.value = NULL_TREE; |
4712 | dimen.original_code = ERROR_MARK; |
4713 | dimen.original_type = NULL_TREE; |
4714 | c_parser_consume_token (parser); |
4715 | c_parser_declspecs (parser, specs: quals_attrs, scspec_ok: false, typespec_ok: false, start_attr_ok: true, |
4716 | alignspec_ok: false, auto_type_ok: false, start_std_attr_ok: false, end_std_attr_ok: false, la: cla_prefer_id); |
4717 | static_seen = c_parser_next_token_is_keyword (parser, keyword: RID_STATIC); |
4718 | if (static_seen) |
4719 | c_parser_consume_token (parser); |
4720 | if (static_seen && !quals_attrs->declspecs_seen_p) |
4721 | c_parser_declspecs (parser, specs: quals_attrs, scspec_ok: false, typespec_ok: false, start_attr_ok: true, |
4722 | alignspec_ok: false, auto_type_ok: false, start_std_attr_ok: false, end_std_attr_ok: false, la: cla_prefer_id); |
4723 | if (!quals_attrs->declspecs_seen_p) |
4724 | quals_attrs = NULL; |
4725 | /* If "static" is present, there must be an array dimension. |
4726 | Otherwise, there may be a dimension, "*", or no |
4727 | dimension. */ |
4728 | if (static_seen) |
4729 | { |
4730 | star_seen = false; |
4731 | dimen = c_parser_expr_no_commas (parser, NULL); |
4732 | } |
4733 | else |
4734 | { |
4735 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
4736 | { |
4737 | dimen.value = NULL_TREE; |
4738 | star_seen = false; |
4739 | } |
4740 | else if (c_parser_next_token_is (parser, type: CPP_MULT)) |
4741 | { |
4742 | if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) |
4743 | { |
4744 | dimen.value = NULL_TREE; |
4745 | star_seen = true; |
4746 | c_parser_consume_token (parser); |
4747 | } |
4748 | else |
4749 | { |
4750 | star_seen = false; |
4751 | dimen = c_parser_expr_no_commas (parser, NULL); |
4752 | } |
4753 | } |
4754 | else |
4755 | { |
4756 | star_seen = false; |
4757 | dimen = c_parser_expr_no_commas (parser, NULL); |
4758 | } |
4759 | } |
4760 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
4761 | c_parser_consume_token (parser); |
4762 | else |
4763 | { |
4764 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
4765 | msgid: "expected %<]%>" ); |
4766 | return NULL; |
4767 | } |
4768 | if (dimen.value) |
4769 | dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true); |
4770 | declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs, |
4771 | static_seen, star_seen); |
4772 | if (declarator == NULL) |
4773 | return NULL; |
4774 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
4775 | { |
4776 | tree std_attrs |
4777 | = c_parser_std_attribute_specifier_sequence (parser); |
4778 | if (std_attrs) |
4779 | inner = build_attrs_declarator (std_attrs, inner); |
4780 | } |
4781 | inner = set_array_declarator_inner (declarator, inner); |
4782 | return c_parser_direct_declarator_inner (parser, id_present, inner); |
4783 | } |
4784 | else if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
4785 | { |
4786 | tree attrs; |
4787 | struct c_arg_info *args; |
4788 | c_parser_consume_token (parser); |
4789 | bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, |
4790 | keyword: RID_ATTRIBUTE); |
4791 | attrs = c_parser_gnu_attributes (parser); |
4792 | args = c_parser_parms_declarator (parser, id_present, attrs, |
4793 | have_gnu_attrs); |
4794 | if (args == NULL) |
4795 | return NULL; |
4796 | else |
4797 | { |
4798 | if (!(args->types |
4799 | && args->types != error_mark_node |
4800 | && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) |
4801 | && c_parser_nth_token_starts_std_attributes (parser, 1)) |
4802 | { |
4803 | tree std_attrs |
4804 | = c_parser_std_attribute_specifier_sequence (parser); |
4805 | if (std_attrs) |
4806 | inner = build_attrs_declarator (std_attrs, inner); |
4807 | } |
4808 | inner = build_function_declarator (args, inner); |
4809 | return c_parser_direct_declarator_inner (parser, id_present, inner); |
4810 | } |
4811 | } |
4812 | return inner; |
4813 | } |
4814 | |
4815 | /* Parse a parameter list or identifier list, including the closing |
4816 | parenthesis but not the opening one. ATTRS are the gnu-attributes |
4817 | at the start of the list. ID_LIST_OK is true if an identifier list |
4818 | is acceptable; such a list must not have attributes at the start. |
4819 | HAVE_GNU_ATTRS says whether any gnu-attributes (including empty |
4820 | attributes) were present (in which case standard attributes cannot |
4821 | occur). */ |
4822 | |
4823 | static struct c_arg_info * |
4824 | c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs, |
4825 | bool have_gnu_attrs) |
4826 | { |
4827 | push_scope (); |
4828 | declare_parm_level (); |
4829 | /* If the list starts with an identifier, it is an identifier list. |
4830 | Otherwise, it is either a prototype list or an empty list. */ |
4831 | if (id_list_ok |
4832 | && !attrs |
4833 | && c_parser_next_token_is (parser, type: CPP_NAME) |
4834 | && c_parser_peek_token (parser)->id_kind == C_ID_ID |
4835 | |
4836 | /* Look ahead to detect typos in type names. */ |
4837 | && c_parser_peek_2nd_token (parser)->type != CPP_NAME |
4838 | && c_parser_peek_2nd_token (parser)->type != CPP_MULT |
4839 | && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN |
4840 | && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE |
4841 | && c_parser_peek_2nd_token (parser)->type != CPP_KEYWORD) |
4842 | { |
4843 | tree list = NULL_TREE, *nextp = &list; |
4844 | while (c_parser_next_token_is (parser, type: CPP_NAME) |
4845 | && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
4846 | { |
4847 | *nextp = build_tree_list (NULL_TREE, |
4848 | c_parser_peek_token (parser)->value); |
4849 | nextp = & TREE_CHAIN (*nextp); |
4850 | c_parser_consume_token (parser); |
4851 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
4852 | break; |
4853 | c_parser_consume_token (parser); |
4854 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4855 | { |
4856 | c_parser_error (parser, gmsgid: "expected identifier" ); |
4857 | break; |
4858 | } |
4859 | } |
4860 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4861 | { |
4862 | struct c_arg_info *ret = build_arg_info (); |
4863 | ret->types = list; |
4864 | c_parser_consume_token (parser); |
4865 | pop_scope (); |
4866 | return ret; |
4867 | } |
4868 | else |
4869 | { |
4870 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4871 | msgid: "expected %<)%>" ); |
4872 | pop_scope (); |
4873 | return NULL; |
4874 | } |
4875 | } |
4876 | else |
4877 | { |
4878 | struct c_arg_info *ret |
4879 | = c_parser_parms_list_declarator (parser, attrs, NULL, have_gnu_attrs); |
4880 | pop_scope (); |
4881 | return ret; |
4882 | } |
4883 | } |
4884 | |
4885 | /* Parse a parameter list (possibly empty), including the closing |
4886 | parenthesis but not the opening one. ATTRS are the gnu-attributes |
4887 | at the start of the list; if HAVE_GNU_ATTRS, there were some such |
4888 | attributes (possibly empty, in which case ATTRS is NULL_TREE), |
4889 | which means standard attributes cannot start the list. EXPR is |
4890 | NULL or an expression that needs to be evaluated for the side |
4891 | effects of array size expressions in the parameters. */ |
4892 | |
4893 | static struct c_arg_info * |
4894 | c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr, |
4895 | bool have_gnu_attrs) |
4896 | { |
4897 | bool bad_parm = false; |
4898 | |
4899 | /* ??? Following the old parser, forward parameter declarations may |
4900 | use abstract declarators, and if no real parameter declarations |
4901 | follow the forward declarations then this is not diagnosed. Also |
4902 | note as above that gnu-attributes are ignored as the only contents of |
4903 | the parentheses, or as the only contents after forward |
4904 | declarations. */ |
4905 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4906 | { |
4907 | struct c_arg_info *ret = build_arg_info (); |
4908 | c_parser_consume_token (parser); |
4909 | return ret; |
4910 | } |
4911 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS) && !have_gnu_attrs) |
4912 | { |
4913 | struct c_arg_info *ret = build_arg_info (); |
4914 | |
4915 | ret->types = NULL_TREE; |
4916 | pedwarn_c11 (c_parser_peek_token (parser)->location, opt: OPT_Wpedantic, |
4917 | "ISO C requires a named argument before %<...%> " |
4918 | "before C23" ); |
4919 | c_parser_consume_token (parser); |
4920 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4921 | { |
4922 | ret->no_named_args_stdarg_p = true; |
4923 | c_parser_consume_token (parser); |
4924 | return ret; |
4925 | } |
4926 | else |
4927 | { |
4928 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4929 | msgid: "expected %<)%>" ); |
4930 | return NULL; |
4931 | } |
4932 | } |
4933 | /* Nonempty list of parameters, either terminated with semicolon |
4934 | (forward declarations; recurse) or with close parenthesis (normal |
4935 | function) or with ", ... )" (variadic function). */ |
4936 | while (true) |
4937 | { |
4938 | /* Parse a parameter. */ |
4939 | struct c_parm *parm = c_parser_parameter_declaration (parser, attrs, |
4940 | have_gnu_attrs); |
4941 | attrs = NULL_TREE; |
4942 | have_gnu_attrs = false; |
4943 | if (parm == NULL) |
4944 | bad_parm = true; |
4945 | else |
4946 | push_parm_decl (parm, &expr); |
4947 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
4948 | { |
4949 | tree new_attrs; |
4950 | c_parser_consume_token (parser); |
4951 | mark_forward_parm_decls (); |
4952 | bool new_have_gnu_attrs |
4953 | = c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE); |
4954 | new_attrs = c_parser_gnu_attributes (parser); |
4955 | return c_parser_parms_list_declarator (parser, attrs: new_attrs, expr, |
4956 | have_gnu_attrs: new_have_gnu_attrs); |
4957 | } |
4958 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4959 | { |
4960 | c_parser_consume_token (parser); |
4961 | if (bad_parm) |
4962 | return NULL; |
4963 | else |
4964 | return get_parm_info (false, expr); |
4965 | } |
4966 | if (!c_parser_require (parser, type: CPP_COMMA, |
4967 | msgid: "expected %<;%>, %<,%> or %<)%>" , |
4968 | UNKNOWN_LOCATION, type_is_unique: false)) |
4969 | { |
4970 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
4971 | return NULL; |
4972 | } |
4973 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
4974 | { |
4975 | c_parser_consume_token (parser); |
4976 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4977 | { |
4978 | c_parser_consume_token (parser); |
4979 | if (bad_parm) |
4980 | return NULL; |
4981 | else |
4982 | return get_parm_info (true, expr); |
4983 | } |
4984 | else |
4985 | { |
4986 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4987 | msgid: "expected %<)%>" ); |
4988 | return NULL; |
4989 | } |
4990 | } |
4991 | } |
4992 | } |
4993 | |
4994 | /* Parse a parameter declaration. ATTRS are the gnu-attributes at the |
4995 | start of the declaration if it is the first parameter; |
4996 | HAVE_GNU_ATTRS is true if there were any gnu-attributes there (even |
4997 | empty) there. */ |
4998 | |
4999 | static struct c_parm * |
5000 | c_parser_parameter_declaration (c_parser *parser, tree attrs, |
5001 | bool have_gnu_attrs) |
5002 | { |
5003 | struct c_declspecs *specs; |
5004 | struct c_declarator *declarator; |
5005 | tree prefix_attrs; |
5006 | tree postfix_attrs = NULL_TREE; |
5007 | bool dummy = false; |
5008 | |
5009 | /* Accept #pragmas between parameter declarations. */ |
5010 | while (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
5011 | c_parser_pragma (parser, pragma_param, NULL); |
5012 | |
5013 | if (!c_parser_next_token_starts_declspecs (parser) |
5014 | && !c_parser_nth_token_starts_std_attributes (parser, 1)) |
5015 | { |
5016 | c_token *token = c_parser_peek_token (parser); |
5017 | if (parser->error) |
5018 | return NULL; |
5019 | c_parser_set_source_position_from_token (token); |
5020 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_type)) |
5021 | { |
5022 | auto_diagnostic_group d; |
5023 | name_hint hint = lookup_name_fuzzy (token->value, |
5024 | FUZZY_LOOKUP_TYPENAME, |
5025 | token->location); |
5026 | if (const char *suggestion = hint.suggestion ()) |
5027 | { |
5028 | gcc_rich_location richloc (token->location); |
5029 | richloc.add_fixit_replace (new_content: suggestion); |
5030 | error_at (&richloc, |
5031 | "unknown type name %qE; did you mean %qs?" , |
5032 | token->value, suggestion); |
5033 | } |
5034 | else |
5035 | error_at (token->location, "unknown type name %qE" , token->value); |
5036 | parser->error = true; |
5037 | } |
5038 | /* ??? In some Objective-C cases '...' isn't applicable so there |
5039 | should be a different message. */ |
5040 | else |
5041 | c_parser_error (parser, |
5042 | gmsgid: "expected declaration specifiers or %<...%>" ); |
5043 | c_parser_skip_to_end_of_parameter (parser); |
5044 | return NULL; |
5045 | } |
5046 | |
5047 | location_t start_loc = c_parser_peek_token (parser)->location; |
5048 | |
5049 | specs = build_null_declspecs (); |
5050 | if (attrs) |
5051 | { |
5052 | declspecs_add_attrs (input_location, specs, attrs); |
5053 | attrs = NULL_TREE; |
5054 | } |
5055 | c_parser_declspecs (parser, specs, scspec_ok: true, typespec_ok: true, start_attr_ok: true, alignspec_ok: true, auto_type_ok: false, |
5056 | start_std_attr_ok: !have_gnu_attrs, end_std_attr_ok: true, la: cla_nonabstract_decl); |
5057 | finish_declspecs (specs); |
5058 | pending_xref_error (); |
5059 | prefix_attrs = specs->attrs; |
5060 | specs->attrs = NULL_TREE; |
5061 | declarator = c_parser_declarator (parser, |
5062 | type_seen_p: specs->typespec_kind != ctsk_none, |
5063 | kind: C_DTR_PARM, seen_id: &dummy); |
5064 | if (declarator == NULL) |
5065 | { |
5066 | c_parser_skip_until_found (parser, type: CPP_COMMA, NULL); |
5067 | return NULL; |
5068 | } |
5069 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
5070 | postfix_attrs = c_parser_gnu_attributes (parser); |
5071 | |
5072 | /* Generate a location for the parameter, ranging from the start of the |
5073 | initial token to the end of the final token. |
5074 | |
5075 | If we have a identifier, then use it for the caret location, e.g. |
5076 | |
5077 | extern int callee (int one, int (*two)(int, int), float three); |
5078 | ~~~~~~^~~~~~~~~~~~~~ |
5079 | |
5080 | otherwise, reuse the start location for the caret location e.g.: |
5081 | |
5082 | extern int callee (int one, int (*)(int, int), float three); |
5083 | ^~~~~~~~~~~~~~~~~ |
5084 | */ |
5085 | location_t end_loc = parser->last_token_location; |
5086 | |
5087 | /* Find any cdk_id declarator; determine if we have an identifier. */ |
5088 | c_declarator *id_declarator = declarator; |
5089 | while (id_declarator && id_declarator->kind != cdk_id) |
5090 | id_declarator = id_declarator->declarator; |
5091 | location_t caret_loc = (id_declarator->u.id.id |
5092 | ? id_declarator->id_loc |
5093 | : start_loc); |
5094 | location_t param_loc = make_location (caret: caret_loc, start: start_loc, finish: end_loc); |
5095 | |
5096 | return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), |
5097 | declarator, param_loc); |
5098 | } |
5099 | |
5100 | /* Parse a string literal in an asm expression. It should not be |
5101 | translated, and wide string literals are an error although |
5102 | permitted by the syntax. This is a GNU extension. |
5103 | |
5104 | asm-string-literal: |
5105 | string-literal |
5106 | */ |
5107 | |
5108 | static tree |
5109 | c_parser_asm_string_literal (c_parser *parser) |
5110 | { |
5111 | tree str; |
5112 | int save_flag = warn_overlength_strings; |
5113 | warn_overlength_strings = 0; |
5114 | str = c_parser_string_literal (parser, false, false).value; |
5115 | warn_overlength_strings = save_flag; |
5116 | return str; |
5117 | } |
5118 | |
5119 | /* Parse a simple asm expression. This is used in restricted |
5120 | contexts, where a full expression with inputs and outputs does not |
5121 | make sense. This is a GNU extension. |
5122 | |
5123 | simple-asm-expr: |
5124 | asm ( asm-string-literal ) |
5125 | */ |
5126 | |
5127 | static tree |
5128 | c_parser_simple_asm_expr (c_parser *parser) |
5129 | { |
5130 | tree str; |
5131 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); |
5132 | c_parser_consume_token (parser); |
5133 | matching_parens parens; |
5134 | if (!parens.require_open (parser)) |
5135 | return NULL_TREE; |
5136 | str = c_parser_asm_string_literal (parser); |
5137 | if (!parens.require_close (parser)) |
5138 | { |
5139 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
5140 | return NULL_TREE; |
5141 | } |
5142 | return str; |
5143 | } |
5144 | |
5145 | static tree |
5146 | c_parser_gnu_attribute_any_word (c_parser *parser) |
5147 | { |
5148 | tree attr_name = NULL_TREE; |
5149 | |
5150 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD)) |
5151 | { |
5152 | /* ??? See comment above about what keywords are accepted here. */ |
5153 | bool ok; |
5154 | switch (c_parser_peek_token (parser)->keyword) |
5155 | { |
5156 | case RID_STATIC: |
5157 | case RID_UNSIGNED: |
5158 | case RID_LONG: |
5159 | case RID_CONST: |
5160 | case RID_EXTERN: |
5161 | case RID_REGISTER: |
5162 | case RID_TYPEDEF: |
5163 | case RID_SHORT: |
5164 | case RID_INLINE: |
5165 | case RID_NORETURN: |
5166 | case RID_VOLATILE: |
5167 | case RID_SIGNED: |
5168 | case RID_AUTO: |
5169 | case RID_RESTRICT: |
5170 | case RID_COMPLEX: |
5171 | case RID_THREAD: |
5172 | case RID_INT: |
5173 | case RID_CHAR: |
5174 | case RID_FLOAT: |
5175 | case RID_DOUBLE: |
5176 | case RID_VOID: |
5177 | case RID_DFLOAT32: |
5178 | case RID_DFLOAT64: |
5179 | case RID_DFLOAT128: |
5180 | CASE_RID_FLOATN_NX: |
5181 | case RID_BOOL: |
5182 | case RID_BITINT: |
5183 | case RID_FRACT: |
5184 | case RID_ACCUM: |
5185 | case RID_SAT: |
5186 | case RID_TRANSACTION_ATOMIC: |
5187 | case RID_TRANSACTION_CANCEL: |
5188 | case RID_ATOMIC: |
5189 | case RID_AUTO_TYPE: |
5190 | case RID_CONSTEXPR: |
5191 | case RID_INT_N_0: |
5192 | case RID_INT_N_1: |
5193 | case RID_INT_N_2: |
5194 | case RID_INT_N_3: |
5195 | ok = true; |
5196 | break; |
5197 | default: |
5198 | ok = false; |
5199 | break; |
5200 | } |
5201 | if (!ok) |
5202 | return NULL_TREE; |
5203 | |
5204 | /* Accept __attribute__((__const)) as __attribute__((const)) etc. */ |
5205 | attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword]; |
5206 | } |
5207 | else if (c_parser_next_token_is (parser, type: CPP_NAME)) |
5208 | attr_name = c_parser_peek_token (parser)->value; |
5209 | |
5210 | return attr_name; |
5211 | } |
5212 | |
5213 | /* Parse attribute arguments. This is a common form of syntax |
5214 | covering all currently valid GNU and standard attributes. |
5215 | |
5216 | gnu-attribute-arguments: |
5217 | identifier |
5218 | identifier , nonempty-expr-list |
5219 | expr-list |
5220 | |
5221 | where the "identifier" must not be declared as a type. ??? Why not |
5222 | allow identifiers declared as types to start the arguments? */ |
5223 | |
5224 | static tree |
5225 | c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, |
5226 | bool require_string, bool assume_attr, |
5227 | bool allow_empty_args) |
5228 | { |
5229 | vec<tree, va_gc> *expr_list; |
5230 | tree attr_args; |
5231 | /* Parse the attribute contents. If they start with an |
5232 | identifier which is followed by a comma or close |
5233 | parenthesis, then the arguments start with that |
5234 | identifier; otherwise they are an expression list. |
5235 | In objective-c the identifier may be a classname. */ |
5236 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
5237 | && (c_parser_peek_token (parser)->id_kind == C_ID_ID |
5238 | || (c_dialect_objc () |
5239 | && c_parser_peek_token (parser)->id_kind |
5240 | == C_ID_CLASSNAME)) |
5241 | && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA) |
5242 | || (c_parser_peek_2nd_token (parser)->type |
5243 | == CPP_CLOSE_PAREN)) |
5244 | && (takes_identifier |
5245 | || (c_dialect_objc () |
5246 | && !assume_attr |
5247 | && c_parser_peek_token (parser)->id_kind |
5248 | == C_ID_CLASSNAME))) |
5249 | { |
5250 | tree arg1 = c_parser_peek_token (parser)->value; |
5251 | c_parser_consume_token (parser); |
5252 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5253 | attr_args = build_tree_list (NULL_TREE, arg1); |
5254 | else |
5255 | { |
5256 | tree tree_list; |
5257 | c_parser_consume_token (parser); |
5258 | expr_list = c_parser_expr_list (parser, false, true, |
5259 | NULL, NULL, NULL, NULL); |
5260 | tree_list = build_tree_list_vec (expr_list); |
5261 | attr_args = tree_cons (NULL_TREE, arg1, tree_list); |
5262 | release_tree_vector (expr_list); |
5263 | } |
5264 | } |
5265 | else |
5266 | { |
5267 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5268 | { |
5269 | if (!allow_empty_args) |
5270 | error_at (c_parser_peek_token (parser)->location, |
5271 | "parentheses must be omitted if " |
5272 | "attribute argument list is empty" ); |
5273 | attr_args = NULL_TREE; |
5274 | } |
5275 | else if (require_string) |
5276 | { |
5277 | /* The only valid argument for this attribute is a string |
5278 | literal. Handle this specially here to avoid accepting |
5279 | string literals with excess parentheses. */ |
5280 | tree string = c_parser_string_literal (parser, false, true).value; |
5281 | attr_args = build_tree_list (NULL_TREE, string); |
5282 | } |
5283 | else if (assume_attr) |
5284 | { |
5285 | tree cond |
5286 | = c_parser_conditional_expression (parser, NULL, NULL_TREE).value; |
5287 | if (!c_parser_next_token_is (parser, type: CPP_COMMA)) |
5288 | attr_args = build_tree_list (NULL_TREE, cond); |
5289 | else |
5290 | { |
5291 | tree tree_list; |
5292 | c_parser_consume_token (parser); |
5293 | expr_list = c_parser_expr_list (parser, false, true, |
5294 | NULL, NULL, NULL, NULL); |
5295 | tree_list = build_tree_list_vec (expr_list); |
5296 | attr_args = tree_cons (NULL_TREE, cond, tree_list); |
5297 | release_tree_vector (expr_list); |
5298 | } |
5299 | } |
5300 | else |
5301 | { |
5302 | expr_list = c_parser_expr_list (parser, false, true, |
5303 | NULL, NULL, NULL, NULL); |
5304 | attr_args = build_tree_list_vec (expr_list); |
5305 | release_tree_vector (expr_list); |
5306 | } |
5307 | } |
5308 | return attr_args; |
5309 | } |
5310 | |
5311 | /* Parse (possibly empty) gnu-attributes. This is a GNU extension. |
5312 | |
5313 | gnu-attributes: |
5314 | empty |
5315 | gnu-attributes gnu-attribute |
5316 | |
5317 | gnu-attribute: |
5318 | __attribute__ ( ( gnu-attribute-list ) ) |
5319 | |
5320 | gnu-attribute-list: |
5321 | gnu-attrib |
5322 | gnu-attribute_list , gnu-attrib |
5323 | |
5324 | gnu-attrib: |
5325 | empty |
5326 | any-word |
5327 | any-word ( gnu-attribute-arguments ) |
5328 | |
5329 | where "any-word" may be any identifier (including one declared as a |
5330 | type), a reserved word storage class specifier, type specifier or |
5331 | type qualifier. ??? This still leaves out most reserved keywords |
5332 | (following the old parser), shouldn't we include them? |
5333 | When EXPECT_COMMA is true, expect the attribute to be preceded |
5334 | by a comma and fail if it isn't. |
5335 | When EMPTY_OK is true, allow and consume any number of consecutive |
5336 | commas with no attributes in between. */ |
5337 | |
5338 | static tree |
5339 | c_parser_gnu_attribute (c_parser *parser, tree attrs, |
5340 | bool expect_comma = false, bool empty_ok = true) |
5341 | { |
5342 | bool comma_first = c_parser_next_token_is (parser, type: CPP_COMMA); |
5343 | if (!comma_first |
5344 | && !c_parser_next_token_is (parser, type: CPP_NAME) |
5345 | && !c_parser_next_token_is (parser, type: CPP_KEYWORD)) |
5346 | return NULL_TREE; |
5347 | |
5348 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
5349 | { |
5350 | c_parser_consume_token (parser); |
5351 | if (!empty_ok) |
5352 | return attrs; |
5353 | } |
5354 | |
5355 | tree attr_name = c_parser_gnu_attribute_any_word (parser); |
5356 | if (attr_name == NULL_TREE) |
5357 | return NULL_TREE; |
5358 | |
5359 | attr_name = canonicalize_attr_name (attr_name); |
5360 | c_parser_consume_token (parser); |
5361 | |
5362 | tree attr; |
5363 | if (c_parser_next_token_is_not (parser, type: CPP_OPEN_PAREN)) |
5364 | { |
5365 | if (expect_comma && !comma_first) |
5366 | { |
5367 | /* A comma is missing between the last attribute on the chain |
5368 | and this one. */ |
5369 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5370 | msgid: "expected %<)%>" ); |
5371 | return error_mark_node; |
5372 | } |
5373 | attr = build_tree_list (attr_name, NULL_TREE); |
5374 | /* Add this attribute to the list. */ |
5375 | attrs = chainon (attrs, attr); |
5376 | return attrs; |
5377 | } |
5378 | c_parser_consume_token (parser); |
5379 | |
5380 | tree attr_args |
5381 | = c_parser_attribute_arguments (parser, |
5382 | takes_identifier: attribute_takes_identifier_p (attr_name), |
5383 | require_string: false, |
5384 | assume_attr: is_attribute_p (attr_name: "assume" , ident: attr_name), |
5385 | allow_empty_args: true); |
5386 | |
5387 | attr = build_tree_list (attr_name, attr_args); |
5388 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5389 | c_parser_consume_token (parser); |
5390 | else |
5391 | { |
5392 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5393 | msgid: "expected %<)%>" ); |
5394 | return error_mark_node; |
5395 | } |
5396 | |
5397 | if (expect_comma && !comma_first) |
5398 | { |
5399 | /* A comma is missing between the last attribute on the chain |
5400 | and this one. */ |
5401 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5402 | msgid: "expected %<)%>" ); |
5403 | return error_mark_node; |
5404 | } |
5405 | |
5406 | /* Add this attribute to the list. */ |
5407 | attrs = chainon (attrs, attr); |
5408 | return attrs; |
5409 | } |
5410 | |
5411 | static tree |
5412 | c_parser_gnu_attributes (c_parser *parser) |
5413 | { |
5414 | tree attrs = NULL_TREE; |
5415 | while (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
5416 | { |
5417 | bool save_translate_strings_p = parser->translate_strings_p; |
5418 | parser->translate_strings_p = false; |
5419 | /* Consume the `__attribute__' keyword. */ |
5420 | c_parser_consume_token (parser); |
5421 | /* Look for the two `(' tokens. */ |
5422 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
5423 | { |
5424 | parser->translate_strings_p = save_translate_strings_p; |
5425 | return attrs; |
5426 | } |
5427 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
5428 | { |
5429 | parser->translate_strings_p = save_translate_strings_p; |
5430 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
5431 | return attrs; |
5432 | } |
5433 | /* Parse the attribute list. Require a comma between successive |
5434 | (possibly empty) attributes. */ |
5435 | for (bool expect_comma = false; ; expect_comma = true) |
5436 | { |
5437 | /* Parse a single attribute. */ |
5438 | tree attr = c_parser_gnu_attribute (parser, attrs, expect_comma); |
5439 | if (attr == error_mark_node) |
5440 | return attrs; |
5441 | if (!attr) |
5442 | break; |
5443 | attrs = attr; |
5444 | } |
5445 | |
5446 | /* Look for the two `)' tokens. */ |
5447 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5448 | c_parser_consume_token (parser); |
5449 | else |
5450 | { |
5451 | parser->translate_strings_p = save_translate_strings_p; |
5452 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5453 | msgid: "expected %<)%>" ); |
5454 | return attrs; |
5455 | } |
5456 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5457 | c_parser_consume_token (parser); |
5458 | else |
5459 | { |
5460 | parser->translate_strings_p = save_translate_strings_p; |
5461 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5462 | msgid: "expected %<)%>" ); |
5463 | return attrs; |
5464 | } |
5465 | parser->translate_strings_p = save_translate_strings_p; |
5466 | } |
5467 | |
5468 | return attrs; |
5469 | } |
5470 | |
5471 | /* Parse an optional balanced token sequence. |
5472 | |
5473 | balanced-token-sequence: |
5474 | balanced-token |
5475 | balanced-token-sequence balanced-token |
5476 | |
5477 | balanced-token: |
5478 | ( balanced-token-sequence[opt] ) |
5479 | [ balanced-token-sequence[opt] ] |
5480 | { balanced-token-sequence[opt] } |
5481 | any token other than ()[]{} |
5482 | */ |
5483 | |
5484 | static void |
5485 | c_parser_balanced_token_sequence (c_parser *parser) |
5486 | { |
5487 | while (true) |
5488 | { |
5489 | c_token *token = c_parser_peek_token (parser); |
5490 | switch (token->type) |
5491 | { |
5492 | case CPP_OPEN_BRACE: |
5493 | { |
5494 | matching_braces braces; |
5495 | braces.consume_open (parser); |
5496 | c_parser_balanced_token_sequence (parser); |
5497 | braces.require_close (parser); |
5498 | break; |
5499 | } |
5500 | |
5501 | case CPP_OPEN_PAREN: |
5502 | { |
5503 | matching_parens parens; |
5504 | parens.consume_open (parser); |
5505 | c_parser_balanced_token_sequence (parser); |
5506 | parens.require_close (parser); |
5507 | break; |
5508 | } |
5509 | |
5510 | case CPP_OPEN_SQUARE: |
5511 | c_parser_consume_token (parser); |
5512 | c_parser_balanced_token_sequence (parser); |
5513 | c_parser_require (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5514 | break; |
5515 | |
5516 | case CPP_CLOSE_BRACE: |
5517 | case CPP_CLOSE_PAREN: |
5518 | case CPP_CLOSE_SQUARE: |
5519 | case CPP_EOF: |
5520 | return; |
5521 | |
5522 | case CPP_PRAGMA: |
5523 | c_parser_consume_pragma (parser); |
5524 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
5525 | break; |
5526 | |
5527 | default: |
5528 | c_parser_consume_token (parser); |
5529 | break; |
5530 | } |
5531 | } |
5532 | } |
5533 | |
5534 | static bool c_parser_check_balanced_raw_token_sequence (c_parser *, |
5535 | unsigned int *); |
5536 | |
5537 | /* Parse arguments of omp::directive or omp::decl attribute. |
5538 | |
5539 | directive-name ,[opt] clause-list[opt] |
5540 | |
5541 | For directive just remember the tokens in a vector for subsequent |
5542 | parsing. */ |
5543 | |
5544 | static void |
5545 | c_parser_omp_directive_args (c_parser *parser, tree attribute, bool decl_p) |
5546 | { |
5547 | unsigned int n = 1; |
5548 | c_token *first = c_parser_peek_token (parser); |
5549 | if (!c_parser_check_balanced_raw_token_sequence (parser, &n) |
5550 | || (c_parser_peek_nth_token_raw (parser, n)->type |
5551 | != CPP_CLOSE_PAREN)) |
5552 | { |
5553 | c_parser_balanced_token_sequence (parser); |
5554 | TREE_VALUE (attribute) = NULL_TREE; |
5555 | return; |
5556 | } |
5557 | if (n == 1) |
5558 | { |
5559 | error_at (first->location, "expected OpenMP directive name" ); |
5560 | TREE_VALUE (attribute) = NULL_TREE; |
5561 | return; |
5562 | } |
5563 | vec<c_token, va_gc> *v; |
5564 | vec_alloc (v, nelems: n - 1); |
5565 | for (--n; n; --n) |
5566 | { |
5567 | c_token *tok = c_parser_peek_token (parser); |
5568 | v->quick_push (obj: *tok); |
5569 | c_parser_consume_token (parser); |
5570 | } |
5571 | tree arg = make_node (C_TOKEN_VEC); |
5572 | C_TOKEN_VEC_TOKENS (arg) = v; |
5573 | if (decl_p) |
5574 | TREE_PUBLIC (arg) = 1; |
5575 | TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute)); |
5576 | } |
5577 | |
5578 | /* Parse arguments of omp::sequence attribute. |
5579 | |
5580 | omp::[opt] directive-attr [ , omp::[opt] directive-attr ]... */ |
5581 | |
5582 | static void |
5583 | c_parser_omp_sequence_args (c_parser *parser, tree attribute) |
5584 | { |
5585 | do |
5586 | { |
5587 | c_token *token = c_parser_peek_token (parser); |
5588 | if (token->type == CPP_NAME |
5589 | && strcmp (IDENTIFIER_POINTER (token->value), s2: "omp" ) == 0 |
5590 | && c_parser_peek_2nd_token (parser)->type == CPP_SCOPE) |
5591 | { |
5592 | c_parser_consume_token (parser); |
5593 | c_parser_consume_token (parser); |
5594 | token = c_parser_peek_token (parser); |
5595 | } |
5596 | bool directive = false; |
5597 | const char *p; |
5598 | if (token->type != CPP_NAME) |
5599 | p = "" ; |
5600 | else |
5601 | p = IDENTIFIER_POINTER (token->value); |
5602 | if (strcmp (s1: p, s2: "directive" ) == 0) |
5603 | directive = true; |
5604 | else if (strcmp (s1: p, s2: "sequence" ) != 0) |
5605 | { |
5606 | error_at (token->location, "expected %<directive%> or %<sequence%>" ); |
5607 | unsigned nesting_depth = 0; |
5608 | |
5609 | while (true) |
5610 | { |
5611 | /* Peek at the next token. */ |
5612 | token = c_parser_peek_token (parser); |
5613 | /* If we've reached the token we want, consume it and stop. */ |
5614 | if ((token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) |
5615 | && !nesting_depth) |
5616 | break; |
5617 | /* If we've run out of tokens, stop. */ |
5618 | if (token->type == CPP_EOF) |
5619 | break; |
5620 | if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) |
5621 | break; |
5622 | if (token->type == CPP_OPEN_BRACE |
5623 | || token->type == CPP_OPEN_PAREN |
5624 | || token->type == CPP_OPEN_SQUARE) |
5625 | ++nesting_depth; |
5626 | else if (token->type == CPP_CLOSE_BRACE |
5627 | || token->type == CPP_CLOSE_PAREN |
5628 | || token->type == CPP_CLOSE_SQUARE) |
5629 | { |
5630 | if (nesting_depth-- == 0) |
5631 | break; |
5632 | } |
5633 | /* Consume this token. */ |
5634 | c_parser_consume_token (parser); |
5635 | } |
5636 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5637 | break; |
5638 | c_parser_consume_token (parser); |
5639 | continue; |
5640 | } |
5641 | c_parser_consume_token (parser); |
5642 | matching_parens parens; |
5643 | if (parens.require_open (parser)) |
5644 | { |
5645 | if (directive) |
5646 | c_parser_omp_directive_args (parser, attribute, decl_p: false); |
5647 | else |
5648 | c_parser_omp_sequence_args (parser, attribute); |
5649 | parens.skip_until_found_close (parser); |
5650 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5651 | break; |
5652 | c_parser_consume_token (parser); |
5653 | } |
5654 | else if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5655 | break; |
5656 | else |
5657 | c_parser_consume_token (parser); |
5658 | } |
5659 | while (1); |
5660 | } |
5661 | |
5662 | /* Parse standard (C23) attributes (including GNU attributes in the |
5663 | gnu:: namespace). |
5664 | |
5665 | attribute-specifier-sequence: |
5666 | attribute-specifier-sequence[opt] attribute-specifier |
5667 | |
5668 | attribute-specifier: |
5669 | [ [ attribute-list ] ] |
5670 | |
5671 | attribute-list: |
5672 | attribute[opt] |
5673 | attribute-list, attribute[opt] |
5674 | |
5675 | attribute: |
5676 | attribute-token attribute-argument-clause[opt] |
5677 | |
5678 | attribute-token: |
5679 | standard-attribute |
5680 | attribute-prefixed-token |
5681 | |
5682 | standard-attribute: |
5683 | identifier |
5684 | |
5685 | attribute-prefixed-token: |
5686 | attribute-prefix :: identifier |
5687 | |
5688 | attribute-prefix: |
5689 | identifier |
5690 | |
5691 | attribute-argument-clause: |
5692 | ( balanced-token-sequence[opt] ) |
5693 | |
5694 | Keywords are accepted as identifiers for this purpose. |
5695 | |
5696 | As an extension, we permit an attribute-specifier to be: |
5697 | |
5698 | [ [ __extension__ attribute-list ] ] |
5699 | |
5700 | Two colons are then accepted as a synonym for ::. No attempt is made |
5701 | to check whether the colons are immediately adjacent. LOOSE_SCOPE_P |
5702 | indicates whether this relaxation is in effect. */ |
5703 | |
5704 | static tree |
5705 | c_parser_std_attribute (c_parser *parser, bool for_tm, |
5706 | bool loose_scope_p = false) |
5707 | { |
5708 | c_token *token = c_parser_peek_token (parser); |
5709 | tree ns, name, attribute; |
5710 | |
5711 | /* Parse the attribute-token. */ |
5712 | if (token->type != CPP_NAME && token->type != CPP_KEYWORD) |
5713 | { |
5714 | c_parser_error (parser, gmsgid: "expected identifier" ); |
5715 | return error_mark_node; |
5716 | } |
5717 | name = canonicalize_attr_name (attr_name: token->value); |
5718 | c_parser_consume_token (parser); |
5719 | if (c_parser_next_token_is (parser, type: CPP_SCOPE) |
5720 | || (loose_scope_p |
5721 | && c_parser_next_token_is (parser, type: CPP_COLON) |
5722 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
5723 | { |
5724 | ns = name; |
5725 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
5726 | c_parser_consume_token (parser); |
5727 | c_parser_consume_token (parser); |
5728 | token = c_parser_peek_token (parser); |
5729 | if (token->type != CPP_NAME && token->type != CPP_KEYWORD) |
5730 | { |
5731 | c_parser_error (parser, gmsgid: "expected identifier" ); |
5732 | return error_mark_node; |
5733 | } |
5734 | name = canonicalize_attr_name (attr_name: token->value); |
5735 | c_parser_consume_token (parser); |
5736 | } |
5737 | else |
5738 | ns = NULL_TREE; |
5739 | attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE); |
5740 | |
5741 | /* Parse the arguments, if any. */ |
5742 | const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute)); |
5743 | if (c_parser_next_token_is_not (parser, type: CPP_OPEN_PAREN)) |
5744 | { |
5745 | if ((flag_openmp || flag_openmp_simd) |
5746 | && ns |
5747 | && is_attribute_p (attr_name: "omp" , ident: ns) |
5748 | && (is_attribute_p (attr_name: "directive" , ident: name) |
5749 | || is_attribute_p (attr_name: "sequence" , ident: name) |
5750 | || is_attribute_p (attr_name: "decl" , ident: name))) |
5751 | { |
5752 | error ("%<omp::%E%> attribute requires argument" , name); |
5753 | return error_mark_node; |
5754 | } |
5755 | goto out; |
5756 | } |
5757 | { |
5758 | location_t open_loc = c_parser_peek_token (parser)->location; |
5759 | matching_parens parens; |
5760 | parens.consume_open (parser); |
5761 | if ((as && as->max_length == 0) |
5762 | /* Special-case the transactional-memory attribute "outer", |
5763 | which is specially handled but not registered as an |
5764 | attribute, to avoid allowing arbitrary balanced token |
5765 | sequences as arguments. */ |
5766 | || is_attribute_p (attr_name: "outer" , ident: name)) |
5767 | { |
5768 | error_at (open_loc, "%qE attribute does not take any arguments" , name); |
5769 | parens.skip_until_found_close (parser); |
5770 | return error_mark_node; |
5771 | } |
5772 | /* If this is a fake attribute created to handle -Wno-attributes, |
5773 | we must skip parsing the arguments. */ |
5774 | if (as && !attribute_ignored_p (as)) |
5775 | { |
5776 | bool takes_identifier |
5777 | = (ns != NULL_TREE |
5778 | && strcmp (IDENTIFIER_POINTER (ns), s2: "gnu" ) == 0 |
5779 | && attribute_takes_identifier_p (name)); |
5780 | bool require_string |
5781 | = (ns == NULL_TREE |
5782 | && (strcmp (IDENTIFIER_POINTER (name), s2: "deprecated" ) == 0 |
5783 | || strcmp (IDENTIFIER_POINTER (name), s2: "nodiscard" ) == 0)); |
5784 | bool assume_attr |
5785 | = (ns != NULL_TREE |
5786 | && strcmp (IDENTIFIER_POINTER (ns), s2: "gnu" ) == 0 |
5787 | && strcmp (IDENTIFIER_POINTER (name), s2: "assume" ) == 0); |
5788 | TREE_VALUE (attribute) |
5789 | = c_parser_attribute_arguments (parser, takes_identifier, |
5790 | require_string, assume_attr, allow_empty_args: false); |
5791 | } |
5792 | else |
5793 | { |
5794 | if ((flag_openmp || flag_openmp_simd) |
5795 | && ns |
5796 | && is_attribute_p (attr_name: "omp" , ident: ns)) |
5797 | { |
5798 | if (is_attribute_p (attr_name: "directive" , ident: name)) |
5799 | { |
5800 | c_parser_omp_directive_args (parser, attribute, decl_p: false); |
5801 | parens.skip_until_found_close (parser); |
5802 | return attribute; |
5803 | } |
5804 | else if (is_attribute_p (attr_name: "decl" , ident: name)) |
5805 | { |
5806 | TREE_VALUE (TREE_PURPOSE (attribute)) |
5807 | = get_identifier ("directive" ); |
5808 | c_parser_omp_directive_args (parser, attribute, decl_p: true); |
5809 | parens.skip_until_found_close (parser); |
5810 | return attribute; |
5811 | } |
5812 | else if (is_attribute_p (attr_name: "sequence" , ident: name)) |
5813 | { |
5814 | TREE_VALUE (TREE_PURPOSE (attribute)) |
5815 | = get_identifier ("directive" ); |
5816 | c_parser_omp_sequence_args (parser, attribute); |
5817 | parens.skip_until_found_close (parser); |
5818 | TREE_VALUE (attribute) = nreverse (TREE_VALUE (attribute)); |
5819 | return attribute; |
5820 | } |
5821 | } |
5822 | c_parser_balanced_token_sequence (parser); |
5823 | } |
5824 | parens.require_close (parser); |
5825 | } |
5826 | out: |
5827 | if (ns == NULL_TREE && !for_tm && !as) |
5828 | { |
5829 | /* An attribute with standard syntax and no namespace specified |
5830 | is a constraint violation if it is not one of the known |
5831 | standard attributes. Diagnose it here with a pedwarn and |
5832 | then discard it to prevent a duplicate warning later. */ |
5833 | pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored" , |
5834 | name); |
5835 | return error_mark_node; |
5836 | } |
5837 | return attribute; |
5838 | } |
5839 | |
5840 | static tree |
5841 | c_parser_std_attribute_list (c_parser *parser, bool for_tm, |
5842 | bool loose_scope_p = false) |
5843 | { |
5844 | tree attributes = NULL_TREE; |
5845 | while (true) |
5846 | { |
5847 | c_token *token = c_parser_peek_token (parser); |
5848 | if (token->type == CPP_CLOSE_SQUARE) |
5849 | break; |
5850 | if (token->type == CPP_COMMA) |
5851 | { |
5852 | c_parser_consume_token (parser); |
5853 | continue; |
5854 | } |
5855 | tree attribute = c_parser_std_attribute (parser, for_tm, loose_scope_p); |
5856 | if (attribute != error_mark_node) |
5857 | { |
5858 | TREE_CHAIN (attribute) = attributes; |
5859 | attributes = attribute; |
5860 | } |
5861 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5862 | break; |
5863 | } |
5864 | return attributes; |
5865 | } |
5866 | |
5867 | static tree |
5868 | c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) |
5869 | { |
5870 | location_t loc = c_parser_peek_token (parser)->location; |
5871 | if (!c_parser_require (parser, type: CPP_OPEN_SQUARE, msgid: "expected %<[%>" )) |
5872 | return NULL_TREE; |
5873 | if (!c_parser_require (parser, type: CPP_OPEN_SQUARE, msgid: "expected %<[%>" )) |
5874 | { |
5875 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5876 | return NULL_TREE; |
5877 | } |
5878 | tree attributes; |
5879 | if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
5880 | { |
5881 | auto ext = disable_extension_diagnostics (); |
5882 | c_parser_consume_token (parser); |
5883 | attributes = c_parser_std_attribute_list (parser, for_tm, loose_scope_p: true); |
5884 | restore_extension_diagnostics (flags: ext); |
5885 | } |
5886 | else |
5887 | { |
5888 | if (!for_tm) |
5889 | pedwarn_c11 (loc, opt: OPT_Wpedantic, |
5890 | "ISO C does not support %<[[]]%> attributes before C23" ); |
5891 | attributes = c_parser_std_attribute_list (parser, for_tm); |
5892 | } |
5893 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5894 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5895 | return nreverse (attributes); |
5896 | } |
5897 | |
5898 | /* Look past an optional balanced token sequence of raw look-ahead |
5899 | tokens starting with the *Nth token. *N is updated to point to the |
5900 | following token. Return true if such a sequence was found, false |
5901 | if the tokens parsed were not balanced. */ |
5902 | |
5903 | static bool |
5904 | c_parser_check_balanced_raw_token_sequence (c_parser *parser, unsigned int *n) |
5905 | { |
5906 | while (true) |
5907 | { |
5908 | c_token *token = c_parser_peek_nth_token_raw (parser, n: *n); |
5909 | switch (token->type) |
5910 | { |
5911 | case CPP_OPEN_BRACE: |
5912 | { |
5913 | ++*n; |
5914 | if (c_parser_check_balanced_raw_token_sequence (parser, n)) |
5915 | { |
5916 | token = c_parser_peek_nth_token_raw (parser, n: *n); |
5917 | if (token->type == CPP_CLOSE_BRACE) |
5918 | ++*n; |
5919 | else |
5920 | return false; |
5921 | } |
5922 | else |
5923 | return false; |
5924 | break; |
5925 | } |
5926 | |
5927 | case CPP_OPEN_PAREN: |
5928 | { |
5929 | ++*n; |
5930 | if (c_parser_check_balanced_raw_token_sequence (parser, n)) |
5931 | { |
5932 | token = c_parser_peek_nth_token_raw (parser, n: *n); |
5933 | if (token->type == CPP_CLOSE_PAREN) |
5934 | ++*n; |
5935 | else |
5936 | return false; |
5937 | } |
5938 | else |
5939 | return false; |
5940 | break; |
5941 | } |
5942 | |
5943 | case CPP_OPEN_SQUARE: |
5944 | { |
5945 | ++*n; |
5946 | if (c_parser_check_balanced_raw_token_sequence (parser, n)) |
5947 | { |
5948 | token = c_parser_peek_nth_token_raw (parser, n: *n); |
5949 | if (token->type == CPP_CLOSE_SQUARE) |
5950 | ++*n; |
5951 | else |
5952 | return false; |
5953 | } |
5954 | else |
5955 | return false; |
5956 | break; |
5957 | } |
5958 | |
5959 | case CPP_CLOSE_BRACE: |
5960 | case CPP_CLOSE_PAREN: |
5961 | case CPP_CLOSE_SQUARE: |
5962 | case CPP_EOF: |
5963 | return true; |
5964 | |
5965 | default: |
5966 | ++*n; |
5967 | break; |
5968 | } |
5969 | } |
5970 | } |
5971 | |
5972 | /* Return whether standard attributes start with the Nth token. */ |
5973 | |
5974 | static bool |
5975 | c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n) |
5976 | { |
5977 | if (!(c_parser_peek_nth_token (parser, n)->type == CPP_OPEN_SQUARE |
5978 | && c_parser_peek_nth_token (parser, n: n + 1)->type == CPP_OPEN_SQUARE)) |
5979 | return false; |
5980 | /* In C, '[[' must start attributes. In Objective-C, we need to |
5981 | check whether '[[' is matched by ']]'. */ |
5982 | if (!c_dialect_objc ()) |
5983 | return true; |
5984 | n += 2; |
5985 | if (!c_parser_check_balanced_raw_token_sequence (parser, n: &n)) |
5986 | return false; |
5987 | c_token *token = c_parser_peek_nth_token_raw (parser, n); |
5988 | if (token->type != CPP_CLOSE_SQUARE) |
5989 | return false; |
5990 | token = c_parser_peek_nth_token_raw (parser, n: n + 1); |
5991 | return token->type == CPP_CLOSE_SQUARE; |
5992 | } |
5993 | |
5994 | static tree |
5995 | c_parser_std_attribute_specifier_sequence (c_parser *parser) |
5996 | { |
5997 | tree attributes = NULL_TREE; |
5998 | do |
5999 | { |
6000 | tree attrs = c_parser_std_attribute_specifier (parser, for_tm: false); |
6001 | attributes = chainon (attributes, attrs); |
6002 | } |
6003 | while (c_parser_nth_token_starts_std_attributes (parser, n: 1)); |
6004 | return attributes; |
6005 | } |
6006 | |
6007 | /* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). ALIGNAS_OK |
6008 | says whether alignment specifiers are OK (only in cases that might |
6009 | be the type name of a compound literal). |
6010 | |
6011 | type-name: |
6012 | specifier-qualifier-list abstract-declarator[opt] |
6013 | */ |
6014 | |
6015 | struct c_type_name * |
6016 | c_parser_type_name (c_parser *parser, bool alignas_ok) |
6017 | { |
6018 | struct c_declspecs *specs = build_null_declspecs (); |
6019 | struct c_declarator *declarator; |
6020 | struct c_type_name *ret; |
6021 | bool dummy = false; |
6022 | c_parser_declspecs (parser, specs, scspec_ok: false, typespec_ok: true, start_attr_ok: true, alignspec_ok: alignas_ok, auto_type_ok: false, |
6023 | start_std_attr_ok: false, end_std_attr_ok: true, la: cla_prefer_type); |
6024 | if (!specs->declspecs_seen_p) |
6025 | { |
6026 | c_parser_error (parser, gmsgid: "expected specifier-qualifier-list" ); |
6027 | return NULL; |
6028 | } |
6029 | if (specs->type != error_mark_node) |
6030 | { |
6031 | pending_xref_error (); |
6032 | finish_declspecs (specs); |
6033 | } |
6034 | declarator = c_parser_declarator (parser, |
6035 | type_seen_p: specs->typespec_kind != ctsk_none, |
6036 | kind: C_DTR_ABSTRACT, seen_id: &dummy); |
6037 | if (declarator == NULL) |
6038 | return NULL; |
6039 | ret = XOBNEW (&parser_obstack, struct c_type_name); |
6040 | ret->specs = specs; |
6041 | ret->declarator = declarator; |
6042 | return ret; |
6043 | } |
6044 | |
6045 | /* Parse an initializer (C90 6.5.7, C99 6.7.8, C11 6.7.9). |
6046 | |
6047 | initializer: |
6048 | assignment-expression |
6049 | { initializer-list } |
6050 | { initializer-list , } |
6051 | |
6052 | initializer-list: |
6053 | designation[opt] initializer |
6054 | initializer-list , designation[opt] initializer |
6055 | |
6056 | designation: |
6057 | designator-list = |
6058 | |
6059 | designator-list: |
6060 | designator |
6061 | designator-list designator |
6062 | |
6063 | designator: |
6064 | array-designator |
6065 | . identifier |
6066 | |
6067 | array-designator: |
6068 | [ constant-expression ] |
6069 | |
6070 | GNU extensions: |
6071 | |
6072 | initializer: |
6073 | { } |
6074 | |
6075 | designation: |
6076 | array-designator |
6077 | identifier : |
6078 | |
6079 | array-designator: |
6080 | [ constant-expression ... constant-expression ] |
6081 | |
6082 | Any expression without commas is accepted in the syntax for the |
6083 | constant-expressions, with non-constant expressions rejected later. |
6084 | |
6085 | DECL is the declaration we're parsing this initializer for. |
6086 | |
6087 | This function is only used for top-level initializers; for nested |
6088 | ones, see c_parser_initval. */ |
6089 | |
6090 | static struct c_expr |
6091 | c_parser_initializer (c_parser *parser, tree decl) |
6092 | { |
6093 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
6094 | return c_parser_braced_init (parser, NULL_TREE, false, NULL, decl); |
6095 | else |
6096 | { |
6097 | struct c_expr ret; |
6098 | location_t loc = c_parser_peek_token (parser)->location; |
6099 | ret = c_parser_expr_no_commas (parser, NULL); |
6100 | if (decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) |
6101 | { |
6102 | error_at (loc, |
6103 | "variable-sized object may not be initialized except " |
6104 | "with an empty initializer" ); |
6105 | ret.set_error (); |
6106 | } |
6107 | /* This is handled mostly by gimplify.cc, but we have to deal with |
6108 | not warning about int x = x; as it is a GCC extension to turn off |
6109 | this warning but only if warn_init_self is zero. */ |
6110 | if (VAR_P (decl) |
6111 | && !DECL_EXTERNAL (decl) |
6112 | && !TREE_STATIC (decl) |
6113 | && ret.value == decl |
6114 | && !warning_enabled_at (DECL_SOURCE_LOCATION (decl), opt: OPT_Winit_self)) |
6115 | suppress_warning (decl, OPT_Winit_self); |
6116 | if (TREE_CODE (ret.value) != STRING_CST |
6117 | && (TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR |
6118 | || C_DECL_DECLARED_CONSTEXPR (COMPOUND_LITERAL_EXPR_DECL |
6119 | (ret.value)))) |
6120 | ret = convert_lvalue_to_rvalue (loc, ret, true, true, true); |
6121 | return ret; |
6122 | } |
6123 | } |
6124 | |
6125 | /* The location of the last comma within the current initializer list, |
6126 | or UNKNOWN_LOCATION if not within one. */ |
6127 | |
6128 | location_t last_init_list_comma; |
6129 | |
6130 | /* Parse a braced initializer list. TYPE is the type specified for a |
6131 | compound literal, and NULL_TREE for other initializers and for |
6132 | nested braced lists. NESTED_P is true for nested braced lists, |
6133 | false for the list of a compound literal or the list that is the |
6134 | top-level initializer in a declaration. DECL is the declaration for |
6135 | the top-level initializer for a declaration, otherwise NULL_TREE. */ |
6136 | |
6137 | static struct c_expr |
6138 | c_parser_braced_init (c_parser *parser, tree type, bool nested_p, |
6139 | struct obstack *outer_obstack, tree decl) |
6140 | { |
6141 | struct c_expr ret; |
6142 | struct obstack braced_init_obstack; |
6143 | location_t brace_loc = c_parser_peek_token (parser)->location; |
6144 | gcc_obstack_init (&braced_init_obstack); |
6145 | gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); |
6146 | matching_braces braces; |
6147 | braces.consume_open (parser); |
6148 | if (nested_p) |
6149 | { |
6150 | finish_implicit_inits (brace_loc, outer_obstack); |
6151 | push_init_level (brace_loc, 0, &braced_init_obstack); |
6152 | } |
6153 | else |
6154 | really_start_incremental_init (type); |
6155 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
6156 | { |
6157 | pedwarn_c11 (brace_loc, opt: OPT_Wpedantic, |
6158 | "ISO C forbids empty initializer braces before C23" ); |
6159 | } |
6160 | else |
6161 | { |
6162 | if (decl && decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) |
6163 | error_at (brace_loc, |
6164 | "variable-sized object may not be initialized except " |
6165 | "with an empty initializer" ); |
6166 | /* Parse a non-empty initializer list, possibly with a trailing |
6167 | comma. */ |
6168 | while (true) |
6169 | { |
6170 | c_parser_initelt (parser, &braced_init_obstack); |
6171 | if (parser->error) |
6172 | break; |
6173 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
6174 | { |
6175 | last_init_list_comma = c_parser_peek_token (parser)->location; |
6176 | c_parser_consume_token (parser); |
6177 | } |
6178 | else |
6179 | break; |
6180 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
6181 | break; |
6182 | } |
6183 | } |
6184 | c_token *next_tok = c_parser_peek_token (parser); |
6185 | if (next_tok->type != CPP_CLOSE_BRACE) |
6186 | { |
6187 | ret.set_error (); |
6188 | ret.original_code = ERROR_MARK; |
6189 | ret.original_type = NULL; |
6190 | braces.skip_until_found_close (parser); |
6191 | pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma); |
6192 | obstack_free (&braced_init_obstack, NULL); |
6193 | return ret; |
6194 | } |
6195 | location_t close_loc = next_tok->location; |
6196 | c_parser_consume_token (parser); |
6197 | ret = pop_init_level (brace_loc, 0, &braced_init_obstack, close_loc); |
6198 | obstack_free (&braced_init_obstack, NULL); |
6199 | set_c_expr_source_range (expr: &ret, start: brace_loc, finish: close_loc); |
6200 | return ret; |
6201 | } |
6202 | |
6203 | /* Parse a nested initializer, including designators. */ |
6204 | |
6205 | static void |
6206 | c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) |
6207 | { |
6208 | /* Parse any designator or designator list. A single array |
6209 | designator may have the subsequent "=" omitted in GNU C, but a |
6210 | longer list or a structure member designator may not. */ |
6211 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
6212 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
6213 | { |
6214 | /* Old-style structure member designator. */ |
6215 | set_init_label (c_parser_peek_token (parser)->location, |
6216 | c_parser_peek_token (parser)->value, |
6217 | c_parser_peek_token (parser)->location, |
6218 | braced_init_obstack); |
6219 | /* Use the colon as the error location. */ |
6220 | pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, |
6221 | "obsolete use of designated initializer with %<:%>" ); |
6222 | c_parser_consume_token (parser); |
6223 | c_parser_consume_token (parser); |
6224 | } |
6225 | else |
6226 | { |
6227 | /* des_seen is 0 if there have been no designators, 1 if there |
6228 | has been a single array designator and 2 otherwise. */ |
6229 | int des_seen = 0; |
6230 | /* Location of a designator. */ |
6231 | location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
6232 | while (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE) |
6233 | || c_parser_next_token_is (parser, type: CPP_DOT)) |
6234 | { |
6235 | int des_prev = des_seen; |
6236 | if (!des_seen) |
6237 | des_loc = c_parser_peek_token (parser)->location; |
6238 | if (des_seen < 2) |
6239 | des_seen++; |
6240 | if (c_parser_next_token_is (parser, type: CPP_DOT)) |
6241 | { |
6242 | des_seen = 2; |
6243 | c_parser_consume_token (parser); |
6244 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
6245 | { |
6246 | set_init_label (des_loc, c_parser_peek_token (parser)->value, |
6247 | c_parser_peek_token (parser)->location, |
6248 | braced_init_obstack); |
6249 | c_parser_consume_token (parser); |
6250 | } |
6251 | else |
6252 | { |
6253 | struct c_expr init; |
6254 | init.set_error (); |
6255 | init.original_code = ERROR_MARK; |
6256 | init.original_type = NULL; |
6257 | c_parser_error (parser, gmsgid: "expected identifier" ); |
6258 | c_parser_skip_until_found (parser, type: CPP_COMMA, NULL); |
6259 | process_init_element (input_location, init, false, |
6260 | braced_init_obstack); |
6261 | return; |
6262 | } |
6263 | } |
6264 | else |
6265 | { |
6266 | struct c_expr first_expr; |
6267 | tree first, second; |
6268 | location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
6269 | location_t array_index_loc = UNKNOWN_LOCATION; |
6270 | /* ??? Following the old parser, [ objc-receiver |
6271 | objc-message-args ] is accepted as an initializer, |
6272 | being distinguished from a designator by what follows |
6273 | the first assignment expression inside the square |
6274 | brackets, but after a first array designator a |
6275 | subsequent square bracket is for Objective-C taken to |
6276 | start an expression, using the obsolete form of |
6277 | designated initializer without '=', rather than |
6278 | possibly being a second level of designation: in LALR |
6279 | terms, the '[' is shifted rather than reducing |
6280 | designator to designator-list. */ |
6281 | if (des_prev == 1 && c_dialect_objc ()) |
6282 | { |
6283 | des_seen = des_prev; |
6284 | break; |
6285 | } |
6286 | if (des_prev == 0 && c_dialect_objc ()) |
6287 | { |
6288 | /* This might be an array designator or an |
6289 | Objective-C message expression. If the former, |
6290 | continue parsing here; if the latter, parse the |
6291 | remainder of the initializer given the starting |
6292 | primary-expression. ??? It might make sense to |
6293 | distinguish when des_prev == 1 as well; see |
6294 | previous comment. */ |
6295 | tree rec, args; |
6296 | struct c_expr mexpr; |
6297 | c_parser_consume_token (parser); |
6298 | if (c_parser_peek_token (parser)->type == CPP_NAME |
6299 | && ((c_parser_peek_token (parser)->id_kind |
6300 | == C_ID_TYPENAME) |
6301 | || (c_parser_peek_token (parser)->id_kind |
6302 | == C_ID_CLASSNAME))) |
6303 | { |
6304 | /* Type name receiver. */ |
6305 | tree id = c_parser_peek_token (parser)->value; |
6306 | c_parser_consume_token (parser); |
6307 | rec = objc_get_class_reference (id); |
6308 | goto parse_message_args; |
6309 | } |
6310 | array_index_loc = c_parser_peek_token (parser)->location; |
6311 | first_expr = c_parser_expr_no_commas (parser, NULL); |
6312 | mark_exp_read (first_expr.value); |
6313 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS) |
6314 | || c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
6315 | goto array_desig_after_first; |
6316 | first = first_expr.value; |
6317 | /* Expression receiver. So far only one part |
6318 | without commas has been parsed; there might be |
6319 | more of the expression. */ |
6320 | rec = first; |
6321 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
6322 | { |
6323 | struct c_expr next; |
6324 | location_t comma_loc, exp_loc; |
6325 | comma_loc = c_parser_peek_token (parser)->location; |
6326 | c_parser_consume_token (parser); |
6327 | exp_loc = c_parser_peek_token (parser)->location; |
6328 | next = c_parser_expr_no_commas (parser, NULL); |
6329 | next = convert_lvalue_to_rvalue (exp_loc, next, |
6330 | true, true); |
6331 | rec = build_compound_expr (comma_loc, rec, next.value); |
6332 | } |
6333 | parse_message_args: |
6334 | /* Now parse the objc-message-args. */ |
6335 | args = c_parser_objc_message_args (parser); |
6336 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
6337 | msgid: "expected %<]%>" ); |
6338 | mexpr.value |
6339 | = objc_build_message_expr (rec, args); |
6340 | mexpr.original_code = ERROR_MARK; |
6341 | mexpr.original_type = NULL; |
6342 | mexpr.m_decimal = 0; |
6343 | /* Now parse and process the remainder of the |
6344 | initializer, starting with this message |
6345 | expression as a primary-expression. */ |
6346 | c_parser_initval (parser, &mexpr, braced_init_obstack); |
6347 | return; |
6348 | } |
6349 | c_parser_consume_token (parser); |
6350 | array_index_loc = c_parser_peek_token (parser)->location; |
6351 | first_expr = c_parser_expr_no_commas (parser, NULL); |
6352 | mark_exp_read (first_expr.value); |
6353 | array_desig_after_first: |
6354 | first_expr = convert_lvalue_to_rvalue (array_index_loc, |
6355 | first_expr, |
6356 | true, true); |
6357 | first = first_expr.value; |
6358 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
6359 | { |
6360 | ellipsis_loc = c_parser_peek_token (parser)->location; |
6361 | c_parser_consume_token (parser); |
6362 | second = convert_lvalue_to_rvalue (ellipsis_loc, |
6363 | (c_parser_expr_no_commas |
6364 | (parser, NULL)), |
6365 | true, true).value; |
6366 | mark_exp_read (second); |
6367 | } |
6368 | else |
6369 | second = NULL_TREE; |
6370 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
6371 | { |
6372 | c_parser_consume_token (parser); |
6373 | set_init_index (array_index_loc, first, second, |
6374 | braced_init_obstack); |
6375 | if (second) |
6376 | pedwarn (ellipsis_loc, OPT_Wpedantic, |
6377 | "ISO C forbids specifying range of elements to initialize" ); |
6378 | } |
6379 | else |
6380 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
6381 | msgid: "expected %<]%>" ); |
6382 | } |
6383 | } |
6384 | if (des_seen >= 1) |
6385 | { |
6386 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
6387 | { |
6388 | pedwarn_c90 (des_loc, opt: OPT_Wpedantic, |
6389 | "ISO C90 forbids specifying subobject " |
6390 | "to initialize" ); |
6391 | c_parser_consume_token (parser); |
6392 | } |
6393 | else |
6394 | { |
6395 | if (des_seen == 1) |
6396 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
6397 | "obsolete use of designated initializer without %<=%>" ); |
6398 | else |
6399 | { |
6400 | struct c_expr init; |
6401 | init.set_error (); |
6402 | init.original_code = ERROR_MARK; |
6403 | init.original_type = NULL; |
6404 | c_parser_error (parser, gmsgid: "expected %<=%>" ); |
6405 | c_parser_skip_until_found (parser, type: CPP_COMMA, NULL); |
6406 | process_init_element (input_location, init, false, |
6407 | braced_init_obstack); |
6408 | return; |
6409 | } |
6410 | } |
6411 | } |
6412 | } |
6413 | c_parser_initval (parser, NULL, braced_init_obstack); |
6414 | } |
6415 | |
6416 | /* Parse a nested initializer; as c_parser_initializer but parses |
6417 | initializers within braced lists, after any designators have been |
6418 | applied. If AFTER is not NULL then it is an Objective-C message |
6419 | expression which is the primary-expression starting the |
6420 | initializer. */ |
6421 | |
6422 | static void |
6423 | c_parser_initval (c_parser *parser, struct c_expr *after, |
6424 | struct obstack * braced_init_obstack) |
6425 | { |
6426 | struct c_expr init; |
6427 | gcc_assert (!after || c_dialect_objc ()); |
6428 | location_t loc = c_parser_peek_token (parser)->location; |
6429 | |
6430 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE) && !after) |
6431 | init = c_parser_braced_init (parser, NULL_TREE, nested_p: true, |
6432 | outer_obstack: braced_init_obstack, NULL_TREE); |
6433 | else |
6434 | { |
6435 | init = c_parser_expr_no_commas (parser, after); |
6436 | if (init.value != NULL_TREE |
6437 | && TREE_CODE (init.value) != STRING_CST |
6438 | && (TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR |
6439 | || C_DECL_DECLARED_CONSTEXPR (COMPOUND_LITERAL_EXPR_DECL |
6440 | (init.value)))) |
6441 | init = convert_lvalue_to_rvalue (loc, init, true, true, true); |
6442 | } |
6443 | process_init_element (loc, init, false, braced_init_obstack); |
6444 | } |
6445 | |
6446 | /* Parse a compound statement (possibly a function body) (C90 6.6.2, |
6447 | C99 6.8.2, C11 6.8.2, C23 6.8.2). |
6448 | |
6449 | compound-statement: |
6450 | { block-item-list[opt] } |
6451 | { label-declarations block-item-list } |
6452 | |
6453 | block-item-list: |
6454 | block-item |
6455 | block-item-list block-item |
6456 | |
6457 | block-item: |
6458 | label |
6459 | nested-declaration |
6460 | statement |
6461 | |
6462 | nested-declaration: |
6463 | declaration |
6464 | |
6465 | GNU extensions: |
6466 | |
6467 | compound-statement: |
6468 | { label-declarations block-item-list } |
6469 | |
6470 | nested-declaration: |
6471 | __extension__ nested-declaration |
6472 | nested-function-definition |
6473 | |
6474 | label-declarations: |
6475 | label-declaration |
6476 | label-declarations label-declaration |
6477 | |
6478 | label-declaration: |
6479 | __label__ identifier-list ; |
6480 | |
6481 | Allowing the mixing of declarations and code is new in C99. The |
6482 | GNU syntax also permits (not shown above) labels at the end of |
6483 | compound statements, which yield an error. We don't allow labels |
6484 | on declarations; this might seem like a natural extension, but |
6485 | there would be a conflict between gnu-attributes on the label and |
6486 | prefix gnu-attributes on the declaration. ??? The syntax follows the |
6487 | old parser in requiring something after label declarations. |
6488 | Although they are erroneous if the labels declared aren't defined, |
6489 | is it useful for the syntax to be this way? |
6490 | |
6491 | OpenACC: |
6492 | |
6493 | block-item: |
6494 | openacc-directive |
6495 | |
6496 | openacc-directive: |
6497 | update-directive |
6498 | |
6499 | OpenMP: |
6500 | |
6501 | block-item: |
6502 | openmp-directive |
6503 | |
6504 | openmp-directive: |
6505 | barrier-directive |
6506 | flush-directive |
6507 | taskwait-directive |
6508 | taskyield-directive |
6509 | cancel-directive |
6510 | cancellation-point-directive */ |
6511 | |
6512 | static tree |
6513 | c_parser_compound_statement (c_parser *parser, location_t *endlocp) |
6514 | { |
6515 | tree stmt; |
6516 | location_t brace_loc; |
6517 | brace_loc = c_parser_peek_token (parser)->location; |
6518 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
6519 | { |
6520 | /* Ensure a scope is entered and left anyway to avoid confusion |
6521 | if we have just prepared to enter a function body. */ |
6522 | stmt = c_begin_compound_stmt (true); |
6523 | c_end_compound_stmt (brace_loc, stmt, true); |
6524 | return error_mark_node; |
6525 | } |
6526 | stmt = c_begin_compound_stmt (true); |
6527 | location_t end_loc = c_parser_compound_statement_nostart (parser); |
6528 | if (endlocp) |
6529 | *endlocp = end_loc; |
6530 | |
6531 | return c_end_compound_stmt (brace_loc, stmt, true); |
6532 | } |
6533 | |
6534 | /* Diagnose errors related to imperfectly nested loops in an OMP |
6535 | loop construct. This function is called when such code is seen. |
6536 | Only issue one such diagnostic no matter how much invalid |
6537 | intervening code there is in the loop. |
6538 | FIXME: maybe the location associated with the diagnostic should |
6539 | be the current parser token instead of the location of the outer loop |
6540 | nest. */ |
6541 | |
6542 | static void |
6543 | check_omp_intervening_code (c_parser *parser) |
6544 | { |
6545 | struct omp_for_parse_data *omp_for_parse_state = parser->omp_for_parse_state; |
6546 | gcc_assert (omp_for_parse_state); |
6547 | |
6548 | if (!omp_for_parse_state->in_intervening_code) |
6549 | return; |
6550 | omp_for_parse_state->saw_intervening_code = true; |
6551 | |
6552 | /* Only diagnose errors related to perfect nesting once. */ |
6553 | if (!omp_for_parse_state->perfect_nesting_fail) |
6554 | { |
6555 | |
6556 | /* OpenACC does not (yet) permit intervening code, in |
6557 | addition to situations forbidden by the OpenMP spec. */ |
6558 | if (omp_for_parse_state->code == OACC_LOOP) |
6559 | { |
6560 | error_at (omp_for_parse_state->for_loc, |
6561 | "inner loops must be perfectly nested in " |
6562 | "%<#pragma acc loop%>" ); |
6563 | omp_for_parse_state->perfect_nesting_fail = true; |
6564 | } |
6565 | else if (omp_for_parse_state->ordered) |
6566 | { |
6567 | error_at (omp_for_parse_state->for_loc, |
6568 | "inner loops must be perfectly nested with " |
6569 | "%<ordered%> clause" ); |
6570 | omp_for_parse_state->perfect_nesting_fail = true; |
6571 | } |
6572 | else if (omp_for_parse_state->inscan) |
6573 | { |
6574 | error_at (omp_for_parse_state->for_loc, |
6575 | "inner loops must be perfectly nested with " |
6576 | "%<reduction%> %<inscan%> clause" ); |
6577 | omp_for_parse_state->perfect_nesting_fail = true; |
6578 | } |
6579 | /* TODO: Also reject loops with TILE directive. */ |
6580 | if (omp_for_parse_state->perfect_nesting_fail) |
6581 | omp_for_parse_state->fail = true; |
6582 | } |
6583 | } |
6584 | |
6585 | /* Helper function for below: wrap an OMP_STRUCTURED_BLOCK around SL |
6586 | and add the statement to the current list. If SL is an empty statement |
6587 | list, do nothing. */ |
6588 | static void |
6589 | add_structured_block_stmt (tree sl) |
6590 | { |
6591 | if (TREE_CODE (sl) != STATEMENT_LIST |
6592 | || !tsi_end_p (i: tsi_start (t: sl))) |
6593 | add_stmt (build1 (OMP_STRUCTURED_BLOCK, void_type_node, sl)); |
6594 | } |
6595 | |
6596 | struct c_omp_attribute_data |
6597 | { |
6598 | vec<c_token, va_gc> *tokens; |
6599 | const c_omp_directive *dir; |
6600 | c_omp_directive_kind kind; |
6601 | }; |
6602 | |
6603 | /* Handle omp::directive and omp::sequence attributes in ATTRS |
6604 | (if any) at the start of a statement or in attribute-declaration. */ |
6605 | |
6606 | static bool |
6607 | c_parser_handle_statement_omp_attributes (c_parser *parser, tree &attrs, |
6608 | bool *have_std_attrs) |
6609 | { |
6610 | if (!flag_openmp && !flag_openmp_simd) |
6611 | return false; |
6612 | |
6613 | auto_vec<c_omp_attribute_data, 16> vd; |
6614 | int cnt = 0; |
6615 | int tokens = 0; |
6616 | bool bad = false; |
6617 | for (tree *pa = &attrs; *pa; ) |
6618 | if (is_attribute_namespace_p (attr_ns: "omp" , attr: *pa) |
6619 | && is_attribute_p (attr_name: "directive" , ident: get_attribute_name (*pa))) |
6620 | { |
6621 | cnt++; |
6622 | for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) |
6623 | { |
6624 | tree d = TREE_VALUE (a); |
6625 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
6626 | vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d); |
6627 | c_token *first = toks->address (); |
6628 | c_token *last = first + toks->length (); |
6629 | if (parser->omp_attrs_forbidden_p) |
6630 | { |
6631 | error_at (first->location, |
6632 | "mixing OpenMP directives with attribute and pragma " |
6633 | "syntax on the same statement" ); |
6634 | parser->omp_attrs_forbidden_p = false; |
6635 | bad = true; |
6636 | } |
6637 | else if (TREE_PUBLIC (d)) |
6638 | { |
6639 | error_at (first->location, |
6640 | "OpenMP %<omp::decl%> attribute on a statement" ); |
6641 | bad = true; |
6642 | } |
6643 | const char *directive[3] = {}; |
6644 | for (int i = 0; i < 3; i++) |
6645 | { |
6646 | tree id = NULL_TREE; |
6647 | if (first + i == last) |
6648 | break; |
6649 | if (first[i].type == CPP_NAME) |
6650 | id = first[i].value; |
6651 | else if (first[i].type == CPP_KEYWORD) |
6652 | id = ridpointers[(int) first[i].keyword]; |
6653 | else |
6654 | break; |
6655 | directive[i] = IDENTIFIER_POINTER (id); |
6656 | } |
6657 | const c_omp_directive *dir = NULL; |
6658 | if (directive[0]) |
6659 | dir = c_omp_categorize_directive (directive[0], directive[1], |
6660 | directive[2]); |
6661 | if (dir == NULL) |
6662 | { |
6663 | error_at (first->location, |
6664 | "unknown OpenMP directive name in %qs attribute " |
6665 | "argument" , |
6666 | TREE_PUBLIC (d) ? "omp::decl" : "omp::directive" ); |
6667 | continue; |
6668 | } |
6669 | c_omp_directive_kind kind = dir->kind; |
6670 | if (dir->id == PRAGMA_OMP_ORDERED) |
6671 | { |
6672 | /* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain |
6673 | depend/doacross clause. */ |
6674 | if (directive[1] |
6675 | && (strcmp (s1: directive[1], s2: "depend" ) == 0 |
6676 | || strcmp (s1: directive[1], s2: "doacross" ) == 0)) |
6677 | kind = C_OMP_DIR_STANDALONE; |
6678 | else if (first + 2 < last |
6679 | && first[1].type == CPP_COMMA |
6680 | && first[2].type == CPP_NAME |
6681 | && (strcmp (IDENTIFIER_POINTER (first[2].value), |
6682 | s2: "depend" ) == 0 |
6683 | || strcmp (IDENTIFIER_POINTER (first[2].value), |
6684 | s2: "doacross" ) == 0)) |
6685 | kind = C_OMP_DIR_STANDALONE; |
6686 | } |
6687 | else if (dir->id == PRAGMA_OMP_ERROR) |
6688 | { |
6689 | /* error with at(execution) clause is C_OMP_DIR_STANDALONE. */ |
6690 | int paren_depth = 0; |
6691 | for (int i = 1; first + i < last; i++) |
6692 | if (first[i].type == CPP_OPEN_PAREN) |
6693 | paren_depth++; |
6694 | else if (first[i].type == CPP_CLOSE_PAREN) |
6695 | paren_depth--; |
6696 | else if (paren_depth == 0 |
6697 | && first + i + 2 < last |
6698 | && first[i].type == CPP_NAME |
6699 | && first[i + 1].type == CPP_OPEN_PAREN |
6700 | && first[i + 2].type == CPP_NAME |
6701 | && !strcmp (IDENTIFIER_POINTER (first[i].value), |
6702 | s2: "at" ) |
6703 | && !strcmp (IDENTIFIER_POINTER (first[i |
6704 | + 2].value), |
6705 | s2: "execution" )) |
6706 | { |
6707 | kind = C_OMP_DIR_STANDALONE; |
6708 | break; |
6709 | } |
6710 | } |
6711 | c_omp_attribute_data v = { .tokens: toks, .dir: dir, .kind: kind }; |
6712 | vd.safe_push (obj: v); |
6713 | if (flag_openmp || dir->simd) |
6714 | tokens += (last - first) + 1; |
6715 | } |
6716 | c_omp_attribute_data v = {}; |
6717 | vd.safe_push (obj: v); |
6718 | *pa = TREE_CHAIN (*pa); |
6719 | } |
6720 | else |
6721 | pa = &TREE_CHAIN (*pa); |
6722 | |
6723 | if (bad) |
6724 | { |
6725 | fail: |
6726 | if (have_std_attrs && attrs == NULL) |
6727 | *have_std_attrs = false; |
6728 | return false; |
6729 | } |
6730 | |
6731 | unsigned int i; |
6732 | c_omp_attribute_data *v; |
6733 | c_omp_attribute_data *construct_seen = nullptr; |
6734 | c_omp_attribute_data *standalone_seen = nullptr; |
6735 | c_omp_attribute_data *prev_standalone_seen = nullptr; |
6736 | FOR_EACH_VEC_ELT (vd, i, v) |
6737 | if (v->tokens) |
6738 | { |
6739 | if (v->kind == C_OMP_DIR_CONSTRUCT && !construct_seen) |
6740 | construct_seen = v; |
6741 | else if (v->kind == C_OMP_DIR_STANDALONE && !standalone_seen) |
6742 | standalone_seen = v; |
6743 | } |
6744 | else |
6745 | { |
6746 | if (standalone_seen && !prev_standalone_seen) |
6747 | { |
6748 | prev_standalone_seen = standalone_seen; |
6749 | standalone_seen = nullptr; |
6750 | } |
6751 | } |
6752 | |
6753 | if (cnt > 1 && construct_seen) |
6754 | { |
6755 | error_at ((*construct_seen->tokens)[0].location, |
6756 | "OpenMP construct among %<omp::directive%> attributes" |
6757 | " requires all %<omp::directive%> attributes on the" |
6758 | " same statement to be in the same %<omp::sequence%>" ); |
6759 | goto fail; |
6760 | } |
6761 | if (cnt > 1 && standalone_seen && prev_standalone_seen) |
6762 | { |
6763 | error_at ((*standalone_seen->tokens)[0].location, |
6764 | "multiple OpenMP standalone directives among" |
6765 | " %<omp::directive%> attributes must be all within the" |
6766 | " same %<omp::sequence%>" ); |
6767 | goto fail; |
6768 | } |
6769 | |
6770 | if (prev_standalone_seen) |
6771 | standalone_seen = prev_standalone_seen; |
6772 | if (standalone_seen |
6773 | && !c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
6774 | { |
6775 | error_at (standalone_seen->tokens->address ()->location, |
6776 | "standalone OpenMP directives in %<omp::directive%> attribute" |
6777 | " can only appear on an empty statement" ); |
6778 | goto fail; |
6779 | } |
6780 | if (cnt && c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
6781 | { |
6782 | c_token *token = c_parser_peek_token (parser); |
6783 | enum pragma_kind kind = token->pragma_kind; |
6784 | if (kind >= PRAGMA_OMP__START_ && kind <= PRAGMA_OMP__LAST_) |
6785 | { |
6786 | error_at (token->location, |
6787 | "mixing OpenMP directives with attribute and pragma " |
6788 | "syntax on the same statement" ); |
6789 | goto fail; |
6790 | } |
6791 | } |
6792 | |
6793 | if (!tokens) |
6794 | return false; |
6795 | |
6796 | unsigned int tokens_avail = parser->tokens_avail; |
6797 | gcc_assert (parser->tokens == &parser->tokens_buf[0]); |
6798 | |
6799 | tokens++; |
6800 | vec<c_token, va_gc> *toks = NULL; |
6801 | vec_safe_reserve (v&: toks, nelems: tokens, exact: true); |
6802 | FOR_EACH_VEC_ELT (vd, i, v) |
6803 | { |
6804 | if (!v->tokens) |
6805 | continue; |
6806 | if (!flag_openmp && !v->dir->simd) |
6807 | continue; |
6808 | c_token *first = v->tokens->address (); |
6809 | c_token *last = first + v->tokens->length (); |
6810 | c_token tok = {}; |
6811 | tok.type = CPP_PRAGMA; |
6812 | tok.keyword = RID_MAX; |
6813 | tok.pragma_kind = pragma_kind (v->dir->id); |
6814 | tok.location = first->location; |
6815 | toks->quick_push (obj: tok); |
6816 | while (++first < last) |
6817 | toks->quick_push (obj: *first); |
6818 | tok = {}; |
6819 | tok.type = CPP_PRAGMA_EOL; |
6820 | tok.keyword = RID_MAX; |
6821 | tok.location = last[-1].location; |
6822 | toks->quick_push (obj: tok); |
6823 | } |
6824 | |
6825 | c_token tok = {}; |
6826 | tok.type = CPP_EOF; |
6827 | tok.keyword = RID_MAX; |
6828 | tok.location = toks->last ().location; |
6829 | tok.flags = tokens_avail; |
6830 | toks->quick_push (obj: tok); |
6831 | |
6832 | parser->tokens = toks->address (); |
6833 | parser->tokens_avail = tokens; |
6834 | parser->in_omp_attribute_pragma = toks; |
6835 | return true; |
6836 | } |
6837 | |
6838 | /* Handle omp::directive and omp::sequence attributes in ATTRS |
6839 | (if any) at the start or after declaration-id of a declaration. */ |
6840 | |
6841 | static void |
6842 | c_parser_handle_directive_omp_attributes (tree &attrs, |
6843 | vec<c_token> *&pragma_clauses, |
6844 | vec<c_token> *attr_clauses) |
6845 | { |
6846 | if (!flag_openmp && !flag_openmp_simd) |
6847 | return; |
6848 | |
6849 | for (tree *pa = &attrs; *pa; ) |
6850 | if (is_attribute_namespace_p (attr_ns: "omp" , attr: *pa) |
6851 | && is_attribute_p (attr_name: "directive" , ident: get_attribute_name (*pa))) |
6852 | { |
6853 | int cnt = 0; |
6854 | for (tree *pa2 = &TREE_VALUE (*pa); *pa2; ) |
6855 | { |
6856 | tree a = *pa2; |
6857 | tree d = TREE_VALUE (a); |
6858 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
6859 | vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d); |
6860 | c_token *first = toks->address (); |
6861 | c_token *last = first + toks->length (); |
6862 | const char *directive[3] = {}; |
6863 | for (int i = 0; i < 3; i++) |
6864 | { |
6865 | tree id = NULL_TREE; |
6866 | if (first + i == last) |
6867 | break; |
6868 | if (first[i].type == CPP_NAME) |
6869 | id = first[i].value; |
6870 | else if (first[i].type == CPP_KEYWORD) |
6871 | id = ridpointers[(int) first[i].keyword]; |
6872 | else |
6873 | break; |
6874 | directive[i] = IDENTIFIER_POINTER (id); |
6875 | } |
6876 | const c_omp_directive *dir = NULL; |
6877 | if (directive[0]) |
6878 | dir = c_omp_categorize_directive (directive[0], directive[1], |
6879 | directive[2]); |
6880 | if (dir == NULL) |
6881 | { |
6882 | error_at (first->location, |
6883 | "unknown OpenMP directive name in " |
6884 | "%qs attribute argument" , |
6885 | TREE_PUBLIC (d) ? "omp::decl" : "omp::directive" ); |
6886 | *pa2 = TREE_CHAIN (a); |
6887 | } |
6888 | else if (dir->id == PRAGMA_OMP_DECLARE |
6889 | && (strcmp (s1: directive[1], s2: "simd" ) == 0 |
6890 | || strcmp (s1: directive[1], s2: "variant" ) == 0)) |
6891 | { |
6892 | if (pragma_clauses) |
6893 | { |
6894 | error_at (first->location, |
6895 | "mixing OpenMP directives with attribute and " |
6896 | "pragma syntax on the same declaration" ); |
6897 | for (pa = &attrs; *pa; ) |
6898 | if (is_attribute_namespace_p (attr_ns: "omp" , attr: *pa) |
6899 | && is_attribute_p (attr_name: "directive" , |
6900 | ident: get_attribute_name (*pa))) |
6901 | *pa = TREE_CHAIN (*pa); |
6902 | else |
6903 | pa = &TREE_CHAIN (*pa); |
6904 | return; |
6905 | } |
6906 | ++cnt; |
6907 | attr_clauses->reserve (nelems: attr_clauses->length () |
6908 | + toks->length () + 2); |
6909 | for (++first; first < last; ++first) |
6910 | attr_clauses->quick_push (obj: *first); |
6911 | c_token tok = {}; |
6912 | tok.type = CPP_PRAGMA_EOL; |
6913 | tok.keyword = RID_MAX; |
6914 | tok.location = last[-1].location; |
6915 | attr_clauses->quick_push (obj: tok); |
6916 | *pa2 = TREE_CHAIN (a); |
6917 | } |
6918 | else |
6919 | pa2 = &TREE_CHAIN (a); |
6920 | } |
6921 | if (cnt && TREE_VALUE (*pa) == NULL_TREE) |
6922 | *pa = TREE_CHAIN (*pa); |
6923 | else |
6924 | pa = &TREE_CHAIN (*pa); |
6925 | } |
6926 | else |
6927 | pa = &TREE_CHAIN (*pa); |
6928 | if (attr_clauses->length ()) |
6929 | { |
6930 | c_token tok = {}; |
6931 | tok.type = CPP_EOF; |
6932 | tok.keyword = RID_MAX; |
6933 | tok.location = attr_clauses->last ().location; |
6934 | attr_clauses->quick_push (obj: tok); |
6935 | attr_clauses->quick_push (obj: tok); |
6936 | pragma_clauses = attr_clauses; |
6937 | } |
6938 | } |
6939 | |
6940 | /* Parse a compound statement except for the opening brace. This is |
6941 | used for parsing both compound statements and statement expressions |
6942 | (which follow different paths to handling the opening). */ |
6943 | |
6944 | static location_t |
6945 | c_parser_compound_statement_nostart (c_parser *parser) |
6946 | { |
6947 | bool last_stmt = false; |
6948 | bool last_label = false; |
6949 | bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); |
6950 | location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
6951 | struct omp_for_parse_data *omp_for_parse_state |
6952 | = parser->omp_for_parse_state; |
6953 | bool in_omp_loop_block |
6954 | = omp_for_parse_state ? omp_for_parse_state->want_nested_loop : false; |
6955 | tree sl = NULL_TREE; |
6956 | |
6957 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
6958 | { |
6959 | location_t endloc = c_parser_peek_token (parser)->location; |
6960 | add_debug_begin_stmt (loc: endloc); |
6961 | c_parser_consume_token (parser); |
6962 | return endloc; |
6963 | } |
6964 | |
6965 | /* If we're parsing a {} sequence in an OMP_FOR body, start a |
6966 | statement list for intervening code. */ |
6967 | if (in_omp_loop_block) |
6968 | sl = push_stmt_list (); |
6969 | |
6970 | mark_valid_location_for_stdc_pragma (true); |
6971 | if (c_parser_next_token_is_keyword (parser, keyword: RID_LABEL)) |
6972 | { |
6973 | /* Read zero or more forward-declarations for labels that nested |
6974 | functions can jump to. */ |
6975 | mark_valid_location_for_stdc_pragma (false); |
6976 | if (in_omp_loop_block) |
6977 | check_omp_intervening_code (parser); |
6978 | while (c_parser_next_token_is_keyword (parser, keyword: RID_LABEL)) |
6979 | { |
6980 | label_loc = c_parser_peek_token (parser)->location; |
6981 | c_parser_consume_token (parser); |
6982 | /* Any identifiers, including those declared as type names, |
6983 | are OK here. */ |
6984 | while (true) |
6985 | { |
6986 | tree label; |
6987 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
6988 | { |
6989 | c_parser_error (parser, gmsgid: "expected identifier" ); |
6990 | break; |
6991 | } |
6992 | label |
6993 | = declare_label (c_parser_peek_token (parser)->value); |
6994 | C_DECLARED_LABEL_FLAG (label) = 1; |
6995 | add_stmt (build_stmt (label_loc, DECL_EXPR, label)); |
6996 | c_parser_consume_token (parser); |
6997 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
6998 | c_parser_consume_token (parser); |
6999 | else |
7000 | break; |
7001 | } |
7002 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
7003 | } |
7004 | pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations" ); |
7005 | } |
7006 | /* We must now have at least one statement, label or declaration. */ |
7007 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
7008 | { |
7009 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7010 | c_parser_error (parser, gmsgid: "expected declaration or statement" ); |
7011 | location_t endloc = c_parser_peek_token (parser)->location; |
7012 | c_parser_consume_token (parser); |
7013 | return endloc; |
7014 | } |
7015 | while (c_parser_next_token_is_not (parser, type: CPP_CLOSE_BRACE)) |
7016 | { |
7017 | location_t loc = c_parser_peek_token (parser)->location; |
7018 | loc = expansion_point_location_if_in_system_header (loc); |
7019 | |
7020 | bool want_nested_loop = (omp_for_parse_state |
7021 | ? omp_for_parse_state->want_nested_loop |
7022 | : false); |
7023 | |
7024 | /* First take care of special cases for OpenMP "canonical loop |
7025 | nest form", that do not allow standard attributes, labels, or |
7026 | __extension__ before the nested statement. */ |
7027 | if (in_omp_loop_block && !last_label) |
7028 | { |
7029 | if (want_nested_loop |
7030 | && c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
7031 | { |
7032 | /* Found the next nested loop. If there were intervening |
7033 | code statements collected before now, wrap them in an |
7034 | OMP_STRUCTURED_BLOCK node, and start a new structured |
7035 | block to hold statements that may come after the FOR. */ |
7036 | gcc_assert (sl); |
7037 | add_structured_block_stmt (sl: pop_stmt_list (sl)); |
7038 | omp_for_parse_state->depth++; |
7039 | add_stmt (c_parser_omp_loop_nest (parser, NULL)); |
7040 | omp_for_parse_state->depth--; |
7041 | sl = push_stmt_list (); |
7042 | parser->error = false; |
7043 | continue; |
7044 | } |
7045 | else if (want_nested_loop |
7046 | && c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
7047 | { |
7048 | /* If this nested compound statement contains the nested loop, |
7049 | we need to separate the other statements in the current |
7050 | statement into separate blocks of intervening code. If |
7051 | there's no nested loop, it's all part of the same |
7052 | chunk of intervening code. */ |
7053 | tree pre_sl = pop_stmt_list (sl); |
7054 | tree nested_sl = push_stmt_list (); |
7055 | mark_valid_location_for_stdc_pragma (false); |
7056 | c_parser_statement_after_labels (parser, NULL); |
7057 | nested_sl = pop_stmt_list (nested_sl); |
7058 | if (omp_for_parse_state->want_nested_loop) |
7059 | { |
7060 | /* This block didn't contain a loop-nest, so it's |
7061 | all part of the same chunk of intervening code. */ |
7062 | check_omp_intervening_code (parser); |
7063 | sl = push_stmt_list (); |
7064 | add_stmt (pre_sl); |
7065 | add_stmt (nested_sl); |
7066 | } |
7067 | else |
7068 | { |
7069 | /* It contains the nested loop. */ |
7070 | add_structured_block_stmt (sl: pre_sl); |
7071 | add_stmt (nested_sl); |
7072 | sl = push_stmt_list (); |
7073 | } |
7074 | parser->error = false; |
7075 | continue; |
7076 | } |
7077 | else if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7078 | { |
7079 | /* Prior to implementing the OpenMP 5.1 syntax for canonical |
7080 | loop form, GCC used to accept an empty statements that |
7081 | would now be flagged as intervening code. Continue to |
7082 | do that, as an extension. */ |
7083 | /* FIXME: Maybe issue a warning or something here? */ |
7084 | c_parser_consume_token (parser); |
7085 | continue; |
7086 | } |
7087 | } |
7088 | |
7089 | /* Standard attributes may start a label, statement or declaration. */ |
7090 | bool have_std_attrs |
7091 | = c_parser_nth_token_starts_std_attributes (parser, n: 1); |
7092 | tree std_attrs = NULL_TREE; |
7093 | if (have_std_attrs) |
7094 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
7095 | if (c_parser_next_token_is_keyword (parser, keyword: RID_CASE) |
7096 | || c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT) |
7097 | || (c_parser_next_token_is (parser, type: CPP_NAME) |
7098 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
7099 | { |
7100 | if (c_parser_next_token_is_keyword (parser, keyword: RID_CASE)) |
7101 | label_loc = c_parser_peek_2nd_token (parser)->location; |
7102 | else |
7103 | label_loc = c_parser_peek_token (parser)->location; |
7104 | last_label = true; |
7105 | last_stmt = false; |
7106 | mark_valid_location_for_stdc_pragma (false); |
7107 | if (in_omp_loop_block) |
7108 | check_omp_intervening_code (parser); |
7109 | c_parser_label (parser, std_attrs); |
7110 | } |
7111 | else if (c_parser_next_tokens_start_declaration (parser) |
7112 | || (have_std_attrs |
7113 | && !c_parser_handle_statement_omp_attributes |
7114 | (parser, attrs&: std_attrs, have_std_attrs: &have_std_attrs) |
7115 | && c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
7116 | && (have_std_attrs = true))) |
7117 | { |
7118 | if (last_label) |
7119 | pedwarn_c11 (c_parser_peek_token (parser)->location, opt: OPT_Wpedantic, |
7120 | "a label can only be part of a statement and " |
7121 | "a declaration is not a statement" ); |
7122 | /* It's unlikely we'll see a nested loop in a declaration in |
7123 | intervening code in an OMP loop, but disallow it anyway. */ |
7124 | if (in_omp_loop_block) |
7125 | { |
7126 | check_omp_intervening_code (parser); |
7127 | omp_for_parse_state->want_nested_loop = false; |
7128 | } |
7129 | mark_valid_location_for_stdc_pragma (false); |
7130 | bool fallthru_attr_p = false; |
7131 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: !have_std_attrs, |
7132 | empty_ok: true, nested: true, start_attr_ok: true, NULL, |
7133 | NULL, have_attrs: have_std_attrs, attrs: std_attrs, |
7134 | NULL, fallthru_attr_p: &fallthru_attr_p); |
7135 | |
7136 | if (in_omp_loop_block) |
7137 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7138 | if (last_stmt && !fallthru_attr_p) |
7139 | pedwarn_c90 (loc, opt: OPT_Wdeclaration_after_statement, |
7140 | "ISO C90 forbids mixed declarations and code" ); |
7141 | last_stmt = fallthru_attr_p; |
7142 | last_label = false; |
7143 | } |
7144 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
7145 | { |
7146 | /* __extension__ can start a declaration, but is also an |
7147 | unary operator that can start an expression. Consume all |
7148 | but the last of a possible series of __extension__ to |
7149 | determine which. If standard attributes have already |
7150 | been seen, it must start a statement, not a declaration, |
7151 | but standard attributes starting a declaration may appear |
7152 | after __extension__. */ |
7153 | while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD |
7154 | && (c_parser_peek_2nd_token (parser)->keyword |
7155 | == RID_EXTENSION)) |
7156 | c_parser_consume_token (parser); |
7157 | if (!have_std_attrs |
7158 | && (c_token_starts_declaration (token: c_parser_peek_2nd_token (parser)) |
7159 | || c_parser_nth_token_starts_std_attributes (parser, n: 2))) |
7160 | { |
7161 | int ext; |
7162 | ext = disable_extension_diagnostics (); |
7163 | c_parser_consume_token (parser); |
7164 | last_label = false; |
7165 | /* It's unlikely we'll see a nested loop in a declaration in |
7166 | intervening code in an OMP loop, but disallow it anyway. */ |
7167 | if (in_omp_loop_block) |
7168 | { |
7169 | check_omp_intervening_code (parser); |
7170 | omp_for_parse_state->want_nested_loop = false; |
7171 | } |
7172 | mark_valid_location_for_stdc_pragma (false); |
7173 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, |
7174 | start_attr_ok: true); |
7175 | if (in_omp_loop_block) |
7176 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7177 | /* Following the old parser, __extension__ does not |
7178 | disable this diagnostic. */ |
7179 | restore_extension_diagnostics (flags: ext); |
7180 | if (last_stmt) |
7181 | pedwarn_c90 (loc, opt: OPT_Wdeclaration_after_statement, |
7182 | "ISO C90 forbids mixed declarations and code" ); |
7183 | last_stmt = false; |
7184 | } |
7185 | else |
7186 | goto statement; |
7187 | } |
7188 | else if (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
7189 | { |
7190 | if (have_std_attrs && !parser->in_omp_attribute_pragma) |
7191 | c_parser_error (parser, gmsgid: "expected declaration or statement" ); |
7192 | else if (std_attrs) |
7193 | c_warn_unused_attributes (std_attrs); |
7194 | /* External pragmas, and some omp pragmas, are not associated |
7195 | with regular c code, and so are not to be considered statements |
7196 | syntactically. This ensures that the user doesn't put them |
7197 | places that would turn into syntax errors if the directive |
7198 | were ignored. */ |
7199 | if (omp_for_parse_state) |
7200 | omp_for_parse_state->want_nested_loop = false; |
7201 | if (c_parser_pragma (parser, |
7202 | last_label ? pragma_stmt : pragma_compound, |
7203 | NULL)) |
7204 | { |
7205 | last_label = false; |
7206 | last_stmt = true; |
7207 | if (omp_for_parse_state) |
7208 | check_omp_intervening_code (parser); |
7209 | } |
7210 | if (omp_for_parse_state) |
7211 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7212 | } |
7213 | else if (c_parser_next_token_is (parser, type: CPP_EOF)) |
7214 | { |
7215 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7216 | c_parser_error (parser, gmsgid: "expected declaration or statement" ); |
7217 | return c_parser_peek_token (parser)->location; |
7218 | } |
7219 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
7220 | { |
7221 | if (parser->in_if_block) |
7222 | { |
7223 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7224 | error_at (loc, "expected %<}%> before %<else%>" ); |
7225 | return c_parser_peek_token (parser)->location; |
7226 | } |
7227 | else |
7228 | { |
7229 | error_at (loc, "%<else%> without a previous %<if%>" ); |
7230 | c_parser_consume_token (parser); |
7231 | continue; |
7232 | } |
7233 | } |
7234 | else |
7235 | { |
7236 | statement: |
7237 | c_warn_unused_attributes (std_attrs); |
7238 | last_label = false; |
7239 | last_stmt = true; |
7240 | mark_valid_location_for_stdc_pragma (false); |
7241 | if (!omp_for_parse_state) |
7242 | c_parser_statement_after_labels (parser, NULL); |
7243 | else |
7244 | { |
7245 | /* In canonical loop nest form, nested loops can only appear |
7246 | directly, or in a directly nested compound statement. We |
7247 | already took care of those cases above, so now we have |
7248 | something else. This statement and everything inside |
7249 | it must be intervening code. */ |
7250 | omp_for_parse_state->want_nested_loop = false; |
7251 | check_omp_intervening_code (parser); |
7252 | c_parser_statement_after_labels (parser, NULL); |
7253 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7254 | } |
7255 | } |
7256 | |
7257 | parser->error = false; |
7258 | } |
7259 | if (last_label) |
7260 | pedwarn_c11 (label_loc, opt: OPT_Wpedantic, "label at end of compound statement" ); |
7261 | location_t endloc = c_parser_peek_token (parser)->location; |
7262 | c_parser_consume_token (parser); |
7263 | |
7264 | /* Restore the value we started with. */ |
7265 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7266 | |
7267 | /* Package leftover intervening code, or the whole contents of the |
7268 | compound statement if we were looking for a nested loop in an OMP_FOR |
7269 | construct and didn't find one. */ |
7270 | if (sl) |
7271 | { |
7272 | sl = pop_stmt_list (sl); |
7273 | if (omp_for_parse_state->want_nested_loop) |
7274 | add_stmt (sl); |
7275 | else |
7276 | add_structured_block_stmt (sl); |
7277 | } |
7278 | return endloc; |
7279 | } |
7280 | |
7281 | /* Parse all consecutive labels, possibly preceded by standard |
7282 | attributes. In this context, a statement is required, not a |
7283 | declaration, so attributes must be followed by a statement that is |
7284 | not just a semicolon. */ |
7285 | |
7286 | static void |
7287 | c_parser_all_labels (c_parser *parser) |
7288 | { |
7289 | bool have_std_attrs; |
7290 | tree std_attrs = NULL; |
7291 | if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, n: 1))) |
7292 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
7293 | while (c_parser_next_token_is_keyword (parser, keyword: RID_CASE) |
7294 | || c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT) |
7295 | || (c_parser_next_token_is (parser, type: CPP_NAME) |
7296 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
7297 | { |
7298 | c_parser_label (parser, std_attrs); |
7299 | std_attrs = NULL; |
7300 | if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, |
7301 | n: 1))) |
7302 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
7303 | } |
7304 | if (std_attrs |
7305 | && (!c_parser_handle_statement_omp_attributes (parser, attrs&: std_attrs, have_std_attrs: &have_std_attrs) |
7306 | || std_attrs)) |
7307 | { |
7308 | if (have_std_attrs && c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7309 | c_parser_error (parser, gmsgid: "expected statement" ); |
7310 | c_warn_unused_attributes (std_attrs); |
7311 | } |
7312 | else if (have_std_attrs && c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7313 | c_parser_error (parser, gmsgid: "expected statement" ); |
7314 | } |
7315 | |
7316 | /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). |
7317 | |
7318 | label: |
7319 | identifier : gnu-attributes[opt] |
7320 | case constant-expression : |
7321 | default : |
7322 | |
7323 | GNU extensions: |
7324 | |
7325 | label: |
7326 | case constant-expression ... constant-expression : |
7327 | |
7328 | The use of gnu-attributes on labels is a GNU extension. The syntax in |
7329 | GNU C accepts any expressions without commas, non-constant |
7330 | expressions being rejected later. Any standard |
7331 | attribute-specifier-sequence before the first label has been parsed |
7332 | in the caller, to distinguish statements from declarations. Any |
7333 | attribute-specifier-sequence after the label is parsed in this |
7334 | function. */ |
7335 | static void |
7336 | c_parser_label (c_parser *parser, tree std_attrs) |
7337 | { |
7338 | location_t loc1 = c_parser_peek_token (parser)->location; |
7339 | tree label = NULL_TREE; |
7340 | |
7341 | /* Remember whether this case or a user-defined label is allowed to fall |
7342 | through to. */ |
7343 | bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH; |
7344 | |
7345 | if (c_parser_next_token_is_keyword (parser, keyword: RID_CASE)) |
7346 | { |
7347 | tree exp1, exp2; |
7348 | c_parser_consume_token (parser); |
7349 | exp1 = convert_lvalue_to_rvalue (loc1, |
7350 | c_parser_expr_no_commas (parser, NULL), |
7351 | true, true).value; |
7352 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
7353 | { |
7354 | c_parser_consume_token (parser); |
7355 | label = do_case (loc1, exp1, NULL_TREE, std_attrs); |
7356 | } |
7357 | else if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
7358 | { |
7359 | c_parser_consume_token (parser); |
7360 | exp2 = convert_lvalue_to_rvalue (loc1, |
7361 | c_parser_expr_no_commas (parser, |
7362 | NULL), |
7363 | true, true).value; |
7364 | if (c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
7365 | label = do_case (loc1, exp1, exp2, std_attrs); |
7366 | } |
7367 | else |
7368 | c_parser_error (parser, gmsgid: "expected %<:%> or %<...%>" ); |
7369 | } |
7370 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT)) |
7371 | { |
7372 | c_parser_consume_token (parser); |
7373 | if (c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
7374 | label = do_case (loc1, NULL_TREE, NULL_TREE, std_attrs); |
7375 | } |
7376 | else |
7377 | { |
7378 | tree name = c_parser_peek_token (parser)->value; |
7379 | tree tlab; |
7380 | tree attrs; |
7381 | location_t loc2 = c_parser_peek_token (parser)->location; |
7382 | gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); |
7383 | c_parser_consume_token (parser); |
7384 | gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); |
7385 | c_parser_consume_token (parser); |
7386 | attrs = c_parser_gnu_attributes (parser); |
7387 | tlab = define_label (loc2, name); |
7388 | if (tlab) |
7389 | { |
7390 | decl_attributes (&tlab, attrs, 0); |
7391 | decl_attributes (&tlab, std_attrs, 0); |
7392 | label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); |
7393 | } |
7394 | if (attrs |
7395 | && c_parser_next_tokens_start_declaration (parser)) |
7396 | warning_at (loc2, OPT_Wattributes, "GNU-style attribute between" |
7397 | " label and declaration appertains to the label" ); |
7398 | } |
7399 | if (label) |
7400 | { |
7401 | if (TREE_CODE (label) == LABEL_EXPR) |
7402 | FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p; |
7403 | else |
7404 | FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p; |
7405 | } |
7406 | } |
7407 | |
7408 | /* Parse a statement (C90 6.6, C99 6.8, C11 6.8). |
7409 | |
7410 | statement: |
7411 | labeled-statement |
7412 | attribute-specifier-sequence[opt] compound-statement |
7413 | expression-statement |
7414 | attribute-specifier-sequence[opt] selection-statement |
7415 | attribute-specifier-sequence[opt] iteration-statement |
7416 | attribute-specifier-sequence[opt] jump-statement |
7417 | |
7418 | labeled-statement: |
7419 | attribute-specifier-sequence[opt] label statement |
7420 | |
7421 | expression-statement: |
7422 | expression[opt] ; |
7423 | attribute-specifier-sequence expression ; |
7424 | |
7425 | selection-statement: |
7426 | if-statement |
7427 | switch-statement |
7428 | |
7429 | iteration-statement: |
7430 | while-statement |
7431 | do-statement |
7432 | for-statement |
7433 | |
7434 | jump-statement: |
7435 | goto identifier ; |
7436 | continue ; |
7437 | break ; |
7438 | return expression[opt] ; |
7439 | |
7440 | GNU extensions: |
7441 | |
7442 | statement: |
7443 | attribute-specifier-sequence[opt] asm-statement |
7444 | |
7445 | jump-statement: |
7446 | goto * expression ; |
7447 | |
7448 | expression-statement: |
7449 | gnu-attributes ; |
7450 | |
7451 | Objective-C: |
7452 | |
7453 | statement: |
7454 | attribute-specifier-sequence[opt] objc-throw-statement |
7455 | attribute-specifier-sequence[opt] objc-try-catch-statement |
7456 | attribute-specifier-sequence[opt] objc-synchronized-statement |
7457 | |
7458 | objc-throw-statement: |
7459 | @throw expression ; |
7460 | @throw ; |
7461 | |
7462 | OpenACC: |
7463 | |
7464 | statement: |
7465 | attribute-specifier-sequence[opt] openacc-construct |
7466 | |
7467 | openacc-construct: |
7468 | parallel-construct |
7469 | kernels-construct |
7470 | data-construct |
7471 | loop-construct |
7472 | |
7473 | parallel-construct: |
7474 | parallel-directive structured-block |
7475 | |
7476 | kernels-construct: |
7477 | kernels-directive structured-block |
7478 | |
7479 | data-construct: |
7480 | data-directive structured-block |
7481 | |
7482 | loop-construct: |
7483 | loop-directive structured-block |
7484 | |
7485 | OpenMP: |
7486 | |
7487 | statement: |
7488 | attribute-specifier-sequence[opt] openmp-construct |
7489 | |
7490 | openmp-construct: |
7491 | parallel-construct |
7492 | for-construct |
7493 | simd-construct |
7494 | for-simd-construct |
7495 | sections-construct |
7496 | single-construct |
7497 | parallel-for-construct |
7498 | parallel-for-simd-construct |
7499 | parallel-sections-construct |
7500 | master-construct |
7501 | critical-construct |
7502 | atomic-construct |
7503 | ordered-construct |
7504 | |
7505 | parallel-construct: |
7506 | parallel-directive structured-block |
7507 | |
7508 | for-construct: |
7509 | for-directive iteration-statement |
7510 | |
7511 | simd-construct: |
7512 | simd-directive iteration-statements |
7513 | |
7514 | for-simd-construct: |
7515 | for-simd-directive iteration-statements |
7516 | |
7517 | sections-construct: |
7518 | sections-directive section-scope |
7519 | |
7520 | single-construct: |
7521 | single-directive structured-block |
7522 | |
7523 | parallel-for-construct: |
7524 | parallel-for-directive iteration-statement |
7525 | |
7526 | parallel-for-simd-construct: |
7527 | parallel-for-simd-directive iteration-statement |
7528 | |
7529 | parallel-sections-construct: |
7530 | parallel-sections-directive section-scope |
7531 | |
7532 | master-construct: |
7533 | master-directive structured-block |
7534 | |
7535 | critical-construct: |
7536 | critical-directive structured-block |
7537 | |
7538 | atomic-construct: |
7539 | atomic-directive expression-statement |
7540 | |
7541 | ordered-construct: |
7542 | ordered-directive structured-block |
7543 | |
7544 | Transactional Memory: |
7545 | |
7546 | statement: |
7547 | attribute-specifier-sequence[opt] transaction-statement |
7548 | attribute-specifier-sequence[opt] transaction-cancel-statement |
7549 | |
7550 | IF_P is used to track whether there's a (possibly labeled) if statement |
7551 | which is not enclosed in braces and has an else clause. This is used to |
7552 | implement -Wparentheses. */ |
7553 | |
7554 | static void |
7555 | c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) |
7556 | { |
7557 | c_parser_all_labels (parser); |
7558 | if (loc_after_labels) |
7559 | *loc_after_labels = c_parser_peek_token (parser)->location; |
7560 | parser->omp_attrs_forbidden_p = false; |
7561 | c_parser_statement_after_labels (parser, if_p, NULL); |
7562 | } |
7563 | |
7564 | /* Parse a statement, other than a labeled statement. CHAIN is a vector |
7565 | of if-else-if conditions. All labels and standard attributes have |
7566 | been parsed in the caller. |
7567 | |
7568 | IF_P is used to track whether there's a (possibly labeled) if statement |
7569 | which is not enclosed in braces and has an else clause. This is used to |
7570 | implement -Wparentheses. */ |
7571 | |
7572 | static void |
7573 | c_parser_statement_after_labels (c_parser *parser, bool *if_p, |
7574 | vec<tree> *chain) |
7575 | { |
7576 | location_t loc = c_parser_peek_token (parser)->location; |
7577 | tree stmt = NULL_TREE; |
7578 | bool in_if_block = parser->in_if_block; |
7579 | parser->in_if_block = false; |
7580 | if (if_p != NULL) |
7581 | *if_p = false; |
7582 | |
7583 | if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) |
7584 | add_debug_begin_stmt (loc); |
7585 | |
7586 | restart: |
7587 | switch (c_parser_peek_token (parser)->type) |
7588 | { |
7589 | case CPP_OPEN_BRACE: |
7590 | add_stmt (c_parser_compound_statement (parser)); |
7591 | break; |
7592 | case CPP_KEYWORD: |
7593 | switch (c_parser_peek_token (parser)->keyword) |
7594 | { |
7595 | case RID_IF: |
7596 | c_parser_if_statement (parser, if_p, chain); |
7597 | break; |
7598 | case RID_SWITCH: |
7599 | c_parser_switch_statement (parser, if_p); |
7600 | break; |
7601 | case RID_WHILE: |
7602 | c_parser_while_statement (parser, false, 0, false, if_p); |
7603 | break; |
7604 | case RID_DO: |
7605 | c_parser_do_statement (parser, false, 0, false); |
7606 | break; |
7607 | case RID_FOR: |
7608 | c_parser_for_statement (parser, false, 0, false, if_p); |
7609 | break; |
7610 | case RID_GOTO: |
7611 | c_parser_consume_token (parser); |
7612 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
7613 | { |
7614 | stmt = c_finish_goto_label (loc, |
7615 | c_parser_peek_token (parser)->value); |
7616 | c_parser_consume_token (parser); |
7617 | } |
7618 | else if (c_parser_next_token_is (parser, type: CPP_MULT)) |
7619 | { |
7620 | struct c_expr val; |
7621 | |
7622 | c_parser_consume_token (parser); |
7623 | val = c_parser_expression (parser); |
7624 | val = convert_lvalue_to_rvalue (loc, val, false, true); |
7625 | stmt = c_finish_goto_ptr (loc, val); |
7626 | } |
7627 | else |
7628 | c_parser_error (parser, gmsgid: "expected identifier or %<*%>" ); |
7629 | goto expect_semicolon; |
7630 | case RID_CONTINUE: |
7631 | c_parser_consume_token (parser); |
7632 | stmt = c_finish_bc_stmt (loc, objc_foreach_continue_label, false); |
7633 | goto expect_semicolon; |
7634 | case RID_BREAK: |
7635 | c_parser_consume_token (parser); |
7636 | stmt = c_finish_bc_stmt (loc, objc_foreach_break_label, true); |
7637 | goto expect_semicolon; |
7638 | case RID_RETURN: |
7639 | c_parser_consume_token (parser); |
7640 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7641 | { |
7642 | stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); |
7643 | c_parser_consume_token (parser); |
7644 | } |
7645 | else |
7646 | { |
7647 | location_t xloc = c_parser_peek_token (parser)->location; |
7648 | struct c_expr expr = c_parser_expression_conv (parser); |
7649 | mark_exp_read (expr.value); |
7650 | stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), |
7651 | expr.value, expr.original_type); |
7652 | goto expect_semicolon; |
7653 | } |
7654 | break; |
7655 | case RID_ASM: |
7656 | stmt = c_parser_asm_statement (parser); |
7657 | break; |
7658 | case RID_TRANSACTION_ATOMIC: |
7659 | case RID_TRANSACTION_RELAXED: |
7660 | stmt = c_parser_transaction (parser, |
7661 | c_parser_peek_token (parser)->keyword); |
7662 | break; |
7663 | case RID_TRANSACTION_CANCEL: |
7664 | stmt = c_parser_transaction_cancel (parser); |
7665 | goto expect_semicolon; |
7666 | case RID_AT_THROW: |
7667 | gcc_assert (c_dialect_objc ()); |
7668 | c_parser_consume_token (parser); |
7669 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7670 | { |
7671 | stmt = objc_build_throw_stmt (loc, NULL_TREE); |
7672 | c_parser_consume_token (parser); |
7673 | } |
7674 | else |
7675 | { |
7676 | struct c_expr expr = c_parser_expression (parser); |
7677 | expr = convert_lvalue_to_rvalue (loc, expr, false, false); |
7678 | expr.value = c_fully_fold (expr.value, false, NULL); |
7679 | stmt = objc_build_throw_stmt (loc, expr.value); |
7680 | goto expect_semicolon; |
7681 | } |
7682 | break; |
7683 | case RID_AT_TRY: |
7684 | gcc_assert (c_dialect_objc ()); |
7685 | c_parser_objc_try_catch_finally_statement (parser); |
7686 | break; |
7687 | case RID_AT_SYNCHRONIZED: |
7688 | gcc_assert (c_dialect_objc ()); |
7689 | c_parser_objc_synchronized_statement (parser); |
7690 | break; |
7691 | case RID_ATTRIBUTE: |
7692 | { |
7693 | /* Allow '__attribute__((fallthrough));' or |
7694 | '__attribute__((assume(cond)));'. */ |
7695 | tree attrs = c_parser_gnu_attributes (parser); |
7696 | bool has_assume = lookup_attribute (attr_name: "assume" , list: attrs); |
7697 | if (has_assume) |
7698 | { |
7699 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7700 | attrs = handle_assume_attribute (here: loc, attrs, nested: true); |
7701 | else |
7702 | { |
7703 | warning_at (loc, OPT_Wattributes, |
7704 | "%<assume%> attribute not followed by %<;%>" ); |
7705 | has_assume = false; |
7706 | } |
7707 | } |
7708 | if (attribute_fallthrough_p (attrs)) |
7709 | { |
7710 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7711 | { |
7712 | tree fn = build_call_expr_internal_loc (loc, |
7713 | IFN_FALLTHROUGH, |
7714 | void_type_node, 0); |
7715 | add_stmt (fn); |
7716 | /* Eat the ';'. */ |
7717 | c_parser_consume_token (parser); |
7718 | } |
7719 | else |
7720 | warning_at (loc, OPT_Wattributes, |
7721 | "%<fallthrough%> attribute not followed " |
7722 | "by %<;%>" ); |
7723 | } |
7724 | else if (has_assume) |
7725 | /* Eat the ';'. */ |
7726 | c_parser_consume_token (parser); |
7727 | else if (attrs != NULL_TREE) |
7728 | warning_at (loc, OPT_Wattributes, |
7729 | "only attribute %<fallthrough%> or %<assume%> can " |
7730 | "be applied to a null statement" ); |
7731 | break; |
7732 | } |
7733 | default: |
7734 | goto expr_stmt; |
7735 | } |
7736 | break; |
7737 | case CPP_SEMICOLON: |
7738 | c_parser_consume_token (parser); |
7739 | break; |
7740 | case CPP_CLOSE_PAREN: |
7741 | case CPP_CLOSE_SQUARE: |
7742 | /* Avoid infinite loop in error recovery: |
7743 | c_parser_skip_until_found stops at a closing nesting |
7744 | delimiter without consuming it, but here we need to consume |
7745 | it to proceed further. */ |
7746 | c_parser_error (parser, gmsgid: "expected statement" ); |
7747 | c_parser_consume_token (parser); |
7748 | break; |
7749 | case CPP_PRAGMA: |
7750 | if (!c_parser_pragma (parser, pragma_stmt, if_p)) |
7751 | goto restart; |
7752 | break; |
7753 | default: |
7754 | expr_stmt: |
7755 | stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); |
7756 | expect_semicolon: |
7757 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
7758 | break; |
7759 | } |
7760 | /* Two cases cannot and do not have line numbers associated: If stmt |
7761 | is degenerate, such as "2;", then stmt is an INTEGER_CST, which |
7762 | cannot hold line numbers. But that's OK because the statement |
7763 | will either be changed to a MODIFY_EXPR during gimplification of |
7764 | the statement expr, or discarded. If stmt was compound, but |
7765 | without new variables, we will have skipped the creation of a |
7766 | BIND and will have a bare STATEMENT_LIST. But that's OK because |
7767 | (recursively) all of the component statements should already have |
7768 | line numbers assigned. ??? Can we discard no-op statements |
7769 | earlier? */ |
7770 | if (EXPR_LOCATION (stmt) == UNKNOWN_LOCATION) |
7771 | protected_set_expr_location (stmt, loc); |
7772 | |
7773 | parser->in_if_block = in_if_block; |
7774 | } |
7775 | |
7776 | /* Parse the condition from an if, do, while or for statements. */ |
7777 | |
7778 | static tree |
7779 | c_parser_condition (c_parser *parser) |
7780 | { |
7781 | location_t loc = c_parser_peek_token (parser)->location; |
7782 | tree cond; |
7783 | cond = c_parser_expression_conv (parser).value; |
7784 | cond = c_objc_common_truthvalue_conversion (loc, cond); |
7785 | cond = c_fully_fold (cond, false, NULL); |
7786 | if (warn_sequence_point) |
7787 | verify_sequence_points (cond); |
7788 | return cond; |
7789 | } |
7790 | |
7791 | /* Parse a parenthesized condition from an if, do or while statement. |
7792 | |
7793 | condition: |
7794 | ( expression ) |
7795 | */ |
7796 | static tree |
7797 | c_parser_paren_condition (c_parser *parser) |
7798 | { |
7799 | tree cond; |
7800 | matching_parens parens; |
7801 | if (!parens.require_open (parser)) |
7802 | return error_mark_node; |
7803 | cond = c_parser_condition (parser); |
7804 | parens.skip_until_found_close (parser); |
7805 | return cond; |
7806 | } |
7807 | |
7808 | /* Parse a statement which is a block in C99. |
7809 | |
7810 | IF_P is used to track whether there's a (possibly labeled) if statement |
7811 | which is not enclosed in braces and has an else clause. This is used to |
7812 | implement -Wparentheses. */ |
7813 | |
7814 | static tree |
7815 | c_parser_c99_block_statement (c_parser *parser, bool *if_p, |
7816 | location_t *loc_after_labels) |
7817 | { |
7818 | tree block = c_begin_compound_stmt (flag_isoc99); |
7819 | location_t loc = c_parser_peek_token (parser)->location; |
7820 | c_parser_statement (parser, if_p, loc_after_labels); |
7821 | return c_end_compound_stmt (loc, block, flag_isoc99); |
7822 | } |
7823 | |
7824 | /* Parse the body of an if statement. This is just parsing a |
7825 | statement but (a) it is a block in C99, (b) we track whether the |
7826 | body is an if statement for the sake of -Wparentheses warnings, (c) |
7827 | we handle an empty body specially for the sake of -Wempty-body |
7828 | warnings, and (d) we call parser_compound_statement directly |
7829 | because c_parser_statement_after_labels resets |
7830 | parser->in_if_block. |
7831 | |
7832 | IF_P is used to track whether there's a (possibly labeled) if statement |
7833 | which is not enclosed in braces and has an else clause. This is used to |
7834 | implement -Wparentheses. */ |
7835 | |
7836 | static tree |
7837 | c_parser_if_body (c_parser *parser, bool *if_p, |
7838 | const token_indent_info &if_tinfo) |
7839 | { |
7840 | tree block = c_begin_compound_stmt (flag_isoc99); |
7841 | location_t body_loc = c_parser_peek_token (parser)->location; |
7842 | location_t body_loc_after_labels = UNKNOWN_LOCATION; |
7843 | token_indent_info body_tinfo |
7844 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7845 | |
7846 | c_parser_all_labels (parser); |
7847 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7848 | { |
7849 | location_t loc = c_parser_peek_token (parser)->location; |
7850 | add_stmt (build_empty_stmt (loc)); |
7851 | c_parser_consume_token (parser); |
7852 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
7853 | warning_at (loc, OPT_Wempty_body, |
7854 | "suggest braces around empty body in an %<if%> statement" ); |
7855 | } |
7856 | else if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
7857 | add_stmt (c_parser_compound_statement (parser)); |
7858 | else |
7859 | { |
7860 | body_loc_after_labels = c_parser_peek_token (parser)->location; |
7861 | c_parser_statement_after_labels (parser, if_p); |
7862 | } |
7863 | |
7864 | token_indent_info next_tinfo |
7865 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7866 | warn_for_misleading_indentation (guard_tinfo: if_tinfo, body_tinfo, next_tinfo); |
7867 | if (body_loc_after_labels != UNKNOWN_LOCATION |
7868 | && next_tinfo.type != CPP_SEMICOLON) |
7869 | warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, |
7870 | if_tinfo.location, RID_IF); |
7871 | |
7872 | return c_end_compound_stmt (body_loc, block, flag_isoc99); |
7873 | } |
7874 | |
7875 | /* Parse the else body of an if statement. This is just parsing a |
7876 | statement but (a) it is a block in C99, (b) we handle an empty body |
7877 | specially for the sake of -Wempty-body warnings. CHAIN is a vector |
7878 | of if-else-if conditions. */ |
7879 | |
7880 | static tree |
7881 | c_parser_else_body (c_parser *parser, const token_indent_info &else_tinfo, |
7882 | vec<tree> *chain) |
7883 | { |
7884 | location_t body_loc = c_parser_peek_token (parser)->location; |
7885 | tree block = c_begin_compound_stmt (flag_isoc99); |
7886 | token_indent_info body_tinfo |
7887 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7888 | location_t body_loc_after_labels = UNKNOWN_LOCATION; |
7889 | |
7890 | c_parser_all_labels (parser); |
7891 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7892 | { |
7893 | location_t loc = c_parser_peek_token (parser)->location; |
7894 | warning_at (loc, |
7895 | OPT_Wempty_body, |
7896 | "suggest braces around empty body in an %<else%> statement" ); |
7897 | add_stmt (build_empty_stmt (loc)); |
7898 | c_parser_consume_token (parser); |
7899 | } |
7900 | else |
7901 | { |
7902 | if (!c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
7903 | body_loc_after_labels = c_parser_peek_token (parser)->location; |
7904 | c_parser_statement_after_labels (parser, NULL, chain); |
7905 | } |
7906 | |
7907 | token_indent_info next_tinfo |
7908 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7909 | warn_for_misleading_indentation (guard_tinfo: else_tinfo, body_tinfo, next_tinfo); |
7910 | if (body_loc_after_labels != UNKNOWN_LOCATION |
7911 | && next_tinfo.type != CPP_SEMICOLON) |
7912 | warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, |
7913 | else_tinfo.location, RID_ELSE); |
7914 | |
7915 | return c_end_compound_stmt (body_loc, block, flag_isoc99); |
7916 | } |
7917 | |
7918 | /* We might need to reclassify any previously-lexed identifier, e.g. |
7919 | when we've left a for loop with an if-statement without else in the |
7920 | body - we might have used a wrong scope for the token. See PR67784. */ |
7921 | |
7922 | static void |
7923 | c_parser_maybe_reclassify_token (c_parser *parser) |
7924 | { |
7925 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
7926 | { |
7927 | c_token *token = c_parser_peek_token (parser); |
7928 | |
7929 | if (token->id_kind != C_ID_CLASSNAME) |
7930 | { |
7931 | tree decl = lookup_name (token->value); |
7932 | |
7933 | token->id_kind = C_ID_ID; |
7934 | if (decl) |
7935 | { |
7936 | if (TREE_CODE (decl) == TYPE_DECL) |
7937 | token->id_kind = C_ID_TYPENAME; |
7938 | } |
7939 | else if (c_dialect_objc ()) |
7940 | { |
7941 | tree objc_interface_decl = objc_is_class_name (token->value); |
7942 | /* Objective-C class names are in the same namespace as |
7943 | variables and typedefs, and hence are shadowed by local |
7944 | declarations. */ |
7945 | if (objc_interface_decl) |
7946 | { |
7947 | token->value = objc_interface_decl; |
7948 | token->id_kind = C_ID_CLASSNAME; |
7949 | } |
7950 | } |
7951 | } |
7952 | } |
7953 | } |
7954 | |
7955 | /* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). |
7956 | |
7957 | if-statement: |
7958 | if ( expression ) statement |
7959 | if ( expression ) statement else statement |
7960 | |
7961 | CHAIN is a vector of if-else-if conditions. |
7962 | IF_P is used to track whether there's a (possibly labeled) if statement |
7963 | which is not enclosed in braces and has an else clause. This is used to |
7964 | implement -Wparentheses. */ |
7965 | |
7966 | static void |
7967 | c_parser_if_statement (c_parser *parser, bool *if_p, vec<tree> *chain) |
7968 | { |
7969 | tree block; |
7970 | location_t loc; |
7971 | tree cond; |
7972 | bool nested_if = false; |
7973 | tree first_body, second_body; |
7974 | bool in_if_block; |
7975 | |
7976 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); |
7977 | token_indent_info if_tinfo |
7978 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7979 | c_parser_consume_token (parser); |
7980 | block = c_begin_compound_stmt (flag_isoc99); |
7981 | loc = c_parser_peek_token (parser)->location; |
7982 | cond = c_parser_paren_condition (parser); |
7983 | in_if_block = parser->in_if_block; |
7984 | parser->in_if_block = true; |
7985 | first_body = c_parser_if_body (parser, if_p: &nested_if, if_tinfo); |
7986 | parser->in_if_block = in_if_block; |
7987 | |
7988 | if (warn_duplicated_cond) |
7989 | warn_duplicated_cond_add_or_warn (EXPR_LOCATION (cond), cond, &chain); |
7990 | |
7991 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
7992 | { |
7993 | token_indent_info else_tinfo |
7994 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7995 | c_parser_consume_token (parser); |
7996 | if (warn_duplicated_cond) |
7997 | { |
7998 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IF) |
7999 | && chain == NULL) |
8000 | { |
8001 | /* We've got "if (COND) else if (COND2)". Start the |
8002 | condition chain and add COND as the first element. */ |
8003 | chain = new vec<tree> (); |
8004 | if (!CONSTANT_CLASS_P (cond) && !TREE_SIDE_EFFECTS (cond)) |
8005 | chain->safe_push (obj: cond); |
8006 | } |
8007 | else if (!c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
8008 | /* This is if-else without subsequent if. Zap the condition |
8009 | chain; we would have already warned at this point. */ |
8010 | vec_free (v&: chain); |
8011 | } |
8012 | second_body = c_parser_else_body (parser, else_tinfo, chain); |
8013 | /* Set IF_P to true to indicate that this if statement has an |
8014 | else clause. This may trigger the Wparentheses warning |
8015 | below when we get back up to the parent if statement. */ |
8016 | if (if_p != NULL) |
8017 | *if_p = true; |
8018 | } |
8019 | else |
8020 | { |
8021 | second_body = NULL_TREE; |
8022 | |
8023 | /* Diagnose an ambiguous else if if-then-else is nested inside |
8024 | if-then. */ |
8025 | if (nested_if) |
8026 | warning_at (loc, OPT_Wdangling_else, |
8027 | "suggest explicit braces to avoid ambiguous %<else%>" ); |
8028 | |
8029 | if (warn_duplicated_cond) |
8030 | /* This if statement does not have an else clause. We don't |
8031 | need the condition chain anymore. */ |
8032 | vec_free (v&: chain); |
8033 | } |
8034 | c_finish_if_stmt (loc, cond, first_body, second_body); |
8035 | add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); |
8036 | |
8037 | c_parser_maybe_reclassify_token (parser); |
8038 | } |
8039 | |
8040 | /* Parse a switch statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). |
8041 | |
8042 | switch-statement: |
8043 | switch (expression) statement |
8044 | */ |
8045 | |
8046 | static void |
8047 | c_parser_switch_statement (c_parser *parser, bool *if_p) |
8048 | { |
8049 | struct c_expr ce; |
8050 | tree block, expr, body; |
8051 | unsigned char save_in_statement; |
8052 | location_t switch_loc = c_parser_peek_token (parser)->location; |
8053 | location_t switch_cond_loc; |
8054 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); |
8055 | c_parser_consume_token (parser); |
8056 | block = c_begin_compound_stmt (flag_isoc99); |
8057 | bool explicit_cast_p = false; |
8058 | matching_parens parens; |
8059 | if (parens.require_open (parser)) |
8060 | { |
8061 | switch_cond_loc = c_parser_peek_token (parser)->location; |
8062 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
8063 | && c_token_starts_typename (token: c_parser_peek_2nd_token (parser))) |
8064 | explicit_cast_p = true; |
8065 | ce = c_parser_expression (parser); |
8066 | ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true); |
8067 | expr = ce.value; |
8068 | /* ??? expr has no valid location? */ |
8069 | parens.skip_until_found_close (parser); |
8070 | } |
8071 | else |
8072 | { |
8073 | switch_cond_loc = UNKNOWN_LOCATION; |
8074 | expr = error_mark_node; |
8075 | ce.original_type = error_mark_node; |
8076 | } |
8077 | c_start_switch (switch_loc, switch_cond_loc, expr, explicit_cast_p); |
8078 | save_in_statement = in_statement; |
8079 | in_statement |= IN_SWITCH_STMT; |
8080 | location_t loc_after_labels; |
8081 | bool open_brace_p = c_parser_peek_token (parser)->type == CPP_OPEN_BRACE; |
8082 | body = c_parser_c99_block_statement (parser, if_p, loc_after_labels: &loc_after_labels); |
8083 | location_t next_loc = c_parser_peek_token (parser)->location; |
8084 | if (!open_brace_p && c_parser_peek_token (parser)->type != CPP_SEMICOLON) |
8085 | warn_for_multistatement_macros (loc_after_labels, next_loc, switch_loc, |
8086 | RID_SWITCH); |
8087 | c_finish_switch (body, ce.original_type); |
8088 | in_statement = save_in_statement; |
8089 | add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99)); |
8090 | c_parser_maybe_reclassify_token (parser); |
8091 | } |
8092 | |
8093 | /* Parse a while statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). |
8094 | |
8095 | while-statement: |
8096 | while (expression) statement |
8097 | |
8098 | IF_P is used to track whether there's a (possibly labeled) if statement |
8099 | which is not enclosed in braces and has an else clause. This is used to |
8100 | implement -Wparentheses. */ |
8101 | |
8102 | static void |
8103 | c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, |
8104 | bool novector, bool *if_p) |
8105 | { |
8106 | tree block, cond, body; |
8107 | unsigned char save_in_statement; |
8108 | location_t loc; |
8109 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); |
8110 | token_indent_info while_tinfo |
8111 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8112 | |
8113 | if (parser->omp_for_parse_state) |
8114 | { |
8115 | error_at (c_parser_peek_token (parser)->location, |
8116 | "loop not permitted in intervening code in OpenMP loop body" ); |
8117 | parser->omp_for_parse_state->fail = true; |
8118 | } |
8119 | |
8120 | c_parser_consume_token (parser); |
8121 | block = c_begin_compound_stmt (flag_isoc99); |
8122 | loc = c_parser_peek_token (parser)->location; |
8123 | cond = c_parser_paren_condition (parser); |
8124 | if (ivdep && cond != error_mark_node) |
8125 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8126 | build_int_cst (integer_type_node, |
8127 | annot_expr_ivdep_kind), |
8128 | integer_zero_node); |
8129 | if (unroll && cond != error_mark_node) |
8130 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8131 | build_int_cst (integer_type_node, |
8132 | annot_expr_unroll_kind), |
8133 | build_int_cst (integer_type_node, unroll)); |
8134 | if (novector && cond != error_mark_node) |
8135 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8136 | build_int_cst (integer_type_node, |
8137 | annot_expr_no_vector_kind), |
8138 | integer_zero_node); |
8139 | save_in_statement = in_statement; |
8140 | in_statement = IN_ITERATION_STMT; |
8141 | |
8142 | token_indent_info body_tinfo |
8143 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8144 | |
8145 | location_t loc_after_labels; |
8146 | bool open_brace = c_parser_next_token_is (parser, type: CPP_OPEN_BRACE); |
8147 | body = c_parser_c99_block_statement (parser, if_p, loc_after_labels: &loc_after_labels); |
8148 | add_stmt (build_stmt (loc, WHILE_STMT, cond, body)); |
8149 | add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); |
8150 | c_parser_maybe_reclassify_token (parser); |
8151 | |
8152 | token_indent_info next_tinfo |
8153 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8154 | warn_for_misleading_indentation (guard_tinfo: while_tinfo, body_tinfo, next_tinfo); |
8155 | |
8156 | if (next_tinfo.type != CPP_SEMICOLON && !open_brace) |
8157 | warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, |
8158 | while_tinfo.location, RID_WHILE); |
8159 | |
8160 | in_statement = save_in_statement; |
8161 | } |
8162 | |
8163 | /* Parse a do statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). |
8164 | |
8165 | do-statement: |
8166 | do statement while ( expression ) ; |
8167 | */ |
8168 | |
8169 | static void |
8170 | c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll, |
8171 | bool novector) |
8172 | { |
8173 | tree block, cond, body; |
8174 | unsigned char save_in_statement; |
8175 | location_t loc; |
8176 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); |
8177 | |
8178 | if (parser->omp_for_parse_state) |
8179 | { |
8180 | error_at (c_parser_peek_token (parser)->location, |
8181 | "loop not permitted in intervening code in OpenMP loop body" ); |
8182 | parser->omp_for_parse_state->fail = true; |
8183 | } |
8184 | |
8185 | c_parser_consume_token (parser); |
8186 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
8187 | warning_at (c_parser_peek_token (parser)->location, |
8188 | OPT_Wempty_body, |
8189 | "suggest braces around empty body in %<do%> statement" ); |
8190 | block = c_begin_compound_stmt (flag_isoc99); |
8191 | loc = c_parser_peek_token (parser)->location; |
8192 | save_in_statement = in_statement; |
8193 | in_statement = IN_ITERATION_STMT; |
8194 | body = c_parser_c99_block_statement (parser, NULL); |
8195 | c_parser_require_keyword (parser, keyword: RID_WHILE, msgid: "expected %<while%>" ); |
8196 | in_statement = save_in_statement; |
8197 | cond = c_parser_paren_condition (parser); |
8198 | if (ivdep && cond != error_mark_node) |
8199 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8200 | build_int_cst (integer_type_node, |
8201 | annot_expr_ivdep_kind), |
8202 | integer_zero_node); |
8203 | if (unroll && cond != error_mark_node) |
8204 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8205 | build_int_cst (integer_type_node, |
8206 | annot_expr_unroll_kind), |
8207 | build_int_cst (integer_type_node, unroll)); |
8208 | if (novector && cond != error_mark_node) |
8209 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8210 | build_int_cst (integer_type_node, |
8211 | annot_expr_no_vector_kind), |
8212 | integer_zero_node); |
8213 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
8214 | c_parser_skip_to_end_of_block_or_statement (parser); |
8215 | |
8216 | add_stmt (build_stmt (loc, DO_STMT, cond, body)); |
8217 | add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); |
8218 | } |
8219 | |
8220 | /* Parse a for statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). |
8221 | |
8222 | for-statement: |
8223 | for ( expression[opt] ; expression[opt] ; expression[opt] ) statement |
8224 | for ( nested-declaration expression[opt] ; expression[opt] ) statement |
8225 | |
8226 | The form with a declaration is new in C99. |
8227 | |
8228 | ??? In accordance with the old parser, the declaration may be a |
8229 | nested function, which is then rejected in check_for_loop_decls, |
8230 | but does it make any sense for this to be included in the grammar? |
8231 | Note in particular that the nested function does not include a |
8232 | trailing ';', whereas the "declaration" production includes one. |
8233 | Also, can we reject bad declarations earlier and cheaper than |
8234 | check_for_loop_decls? |
8235 | |
8236 | In Objective-C, there are two additional variants: |
8237 | |
8238 | foreach-statement: |
8239 | for ( expression in expresssion ) statement |
8240 | for ( declaration in expression ) statement |
8241 | |
8242 | This is inconsistent with C, because the second variant is allowed |
8243 | even if c99 is not enabled. |
8244 | |
8245 | The rest of the comment documents these Objective-C foreach-statement. |
8246 | |
8247 | Here is the canonical example of the first variant: |
8248 | for (object in array) { do something with object } |
8249 | we call the first expression ("object") the "object_expression" and |
8250 | the second expression ("array") the "collection_expression". |
8251 | object_expression must be an lvalue of type "id" (a generic Objective-C |
8252 | object) because the loop works by assigning to object_expression the |
8253 | various objects from the collection_expression. collection_expression |
8254 | must evaluate to something of type "id" which responds to the method |
8255 | countByEnumeratingWithState:objects:count:. |
8256 | |
8257 | The canonical example of the second variant is: |
8258 | for (id object in array) { do something with object } |
8259 | which is completely equivalent to |
8260 | { |
8261 | id object; |
8262 | for (object in array) { do something with object } |
8263 | } |
8264 | Note that initizializing 'object' in some way (eg, "for ((object = |
8265 | xxx) in array) { do something with object }") is possibly |
8266 | technically valid, but completely pointless as 'object' will be |
8267 | assigned to something else as soon as the loop starts. We should |
8268 | most likely reject it (TODO). |
8269 | |
8270 | The beginning of the Objective-C foreach-statement looks exactly |
8271 | like the beginning of the for-statement, and we can tell it is a |
8272 | foreach-statement only because the initial declaration or |
8273 | expression is terminated by 'in' instead of ';'. |
8274 | |
8275 | IF_P is used to track whether there's a (possibly labeled) if statement |
8276 | which is not enclosed in braces and has an else clause. This is used to |
8277 | implement -Wparentheses. */ |
8278 | |
8279 | static void |
8280 | c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, |
8281 | bool novector, bool *if_p) |
8282 | { |
8283 | tree block, cond, incr, body; |
8284 | unsigned char save_in_statement; |
8285 | tree save_objc_foreach_break_label, save_objc_foreach_continue_label; |
8286 | /* The following are only used when parsing an ObjC foreach statement. */ |
8287 | tree object_expression; |
8288 | /* Silence the bogus uninitialized warning. */ |
8289 | tree collection_expression = NULL; |
8290 | location_t loc = c_parser_peek_token (parser)->location; |
8291 | location_t for_loc = loc; |
8292 | bool is_foreach_statement = false; |
8293 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); |
8294 | token_indent_info for_tinfo |
8295 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8296 | |
8297 | if (parser->omp_for_parse_state) |
8298 | { |
8299 | error_at (for_loc, |
8300 | "loop not permitted in intervening code in OpenMP loop body" ); |
8301 | parser->omp_for_parse_state->fail = true; |
8302 | } |
8303 | |
8304 | c_parser_consume_token (parser); |
8305 | /* Open a compound statement in Objective-C as well, just in case this is |
8306 | as foreach expression. */ |
8307 | block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); |
8308 | cond = error_mark_node; |
8309 | incr = error_mark_node; |
8310 | matching_parens parens; |
8311 | if (parens.require_open (parser)) |
8312 | { |
8313 | /* Parse the initialization declaration or expression. */ |
8314 | object_expression = error_mark_node; |
8315 | parser->objc_could_be_foreach_context = c_dialect_objc (); |
8316 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
8317 | { |
8318 | parser->objc_could_be_foreach_context = false; |
8319 | c_parser_consume_token (parser); |
8320 | c_finish_expr_stmt (loc, NULL_TREE); |
8321 | } |
8322 | else if (c_parser_next_tokens_start_declaration (parser) |
8323 | || c_parser_nth_token_starts_std_attributes (parser, n: 1)) |
8324 | { |
8325 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, start_attr_ok: true, |
8326 | objc_foreach_object_declaration: &object_expression); |
8327 | parser->objc_could_be_foreach_context = false; |
8328 | |
8329 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
8330 | { |
8331 | c_parser_consume_token (parser); |
8332 | is_foreach_statement = true; |
8333 | if (check_for_loop_decls (for_loc, true) == NULL_TREE) |
8334 | c_parser_error (parser, gmsgid: "multiple iterating variables in " |
8335 | "fast enumeration" ); |
8336 | } |
8337 | else |
8338 | check_for_loop_decls (for_loc, flag_isoc99); |
8339 | } |
8340 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
8341 | { |
8342 | /* __extension__ can start a declaration, but is also an |
8343 | unary operator that can start an expression. Consume all |
8344 | but the last of a possible series of __extension__ to |
8345 | determine which. */ |
8346 | while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD |
8347 | && (c_parser_peek_2nd_token (parser)->keyword |
8348 | == RID_EXTENSION)) |
8349 | c_parser_consume_token (parser); |
8350 | if (c_token_starts_declaration (token: c_parser_peek_2nd_token (parser)) |
8351 | || c_parser_nth_token_starts_std_attributes (parser, n: 2)) |
8352 | { |
8353 | int ext; |
8354 | ext = disable_extension_diagnostics (); |
8355 | c_parser_consume_token (parser); |
8356 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, |
8357 | start_attr_ok: true, objc_foreach_object_declaration: &object_expression); |
8358 | parser->objc_could_be_foreach_context = false; |
8359 | |
8360 | restore_extension_diagnostics (flags: ext); |
8361 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
8362 | { |
8363 | c_parser_consume_token (parser); |
8364 | is_foreach_statement = true; |
8365 | if (check_for_loop_decls (for_loc, true) == NULL_TREE) |
8366 | c_parser_error (parser, gmsgid: "multiple iterating variables in " |
8367 | "fast enumeration" ); |
8368 | } |
8369 | else |
8370 | check_for_loop_decls (for_loc, flag_isoc99); |
8371 | } |
8372 | else |
8373 | goto init_expr; |
8374 | } |
8375 | else |
8376 | { |
8377 | init_expr: |
8378 | { |
8379 | struct c_expr ce; |
8380 | tree init_expression; |
8381 | ce = c_parser_expression (parser); |
8382 | init_expression = ce.value; |
8383 | parser->objc_could_be_foreach_context = false; |
8384 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
8385 | { |
8386 | c_parser_consume_token (parser); |
8387 | is_foreach_statement = true; |
8388 | if (! lvalue_p (init_expression)) |
8389 | c_parser_error (parser, gmsgid: "invalid iterating variable in " |
8390 | "fast enumeration" ); |
8391 | object_expression |
8392 | = c_fully_fold (init_expression, false, NULL); |
8393 | } |
8394 | else |
8395 | { |
8396 | ce = convert_lvalue_to_rvalue (loc, ce, true, false); |
8397 | init_expression = ce.value; |
8398 | c_finish_expr_stmt (loc, init_expression); |
8399 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, |
8400 | msgid: "expected %<;%>" ); |
8401 | } |
8402 | } |
8403 | } |
8404 | /* Parse the loop condition. In the case of a foreach |
8405 | statement, there is no loop condition. */ |
8406 | gcc_assert (!parser->objc_could_be_foreach_context); |
8407 | if (!is_foreach_statement) |
8408 | { |
8409 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
8410 | { |
8411 | if (ivdep) |
8412 | { |
8413 | c_parser_error (parser, gmsgid: "missing loop condition in loop " |
8414 | "with %<GCC ivdep%> pragma" ); |
8415 | cond = error_mark_node; |
8416 | } |
8417 | else if (unroll) |
8418 | { |
8419 | c_parser_error (parser, gmsgid: "missing loop condition in loop " |
8420 | "with %<GCC unroll%> pragma" ); |
8421 | cond = error_mark_node; |
8422 | } |
8423 | else |
8424 | { |
8425 | c_parser_consume_token (parser); |
8426 | cond = NULL_TREE; |
8427 | } |
8428 | } |
8429 | else |
8430 | { |
8431 | cond = c_parser_condition (parser); |
8432 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, |
8433 | msgid: "expected %<;%>" ); |
8434 | } |
8435 | if (ivdep && cond != error_mark_node) |
8436 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8437 | build_int_cst (integer_type_node, |
8438 | annot_expr_ivdep_kind), |
8439 | integer_zero_node); |
8440 | if (unroll && cond != error_mark_node) |
8441 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8442 | build_int_cst (integer_type_node, |
8443 | annot_expr_unroll_kind), |
8444 | build_int_cst (integer_type_node, unroll)); |
8445 | if (novector && cond != error_mark_node) |
8446 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8447 | build_int_cst (integer_type_node, |
8448 | annot_expr_no_vector_kind), |
8449 | integer_zero_node); |
8450 | } |
8451 | /* Parse the increment expression (the third expression in a |
8452 | for-statement). In the case of a foreach-statement, this is |
8453 | the expression that follows the 'in'. */ |
8454 | loc = c_parser_peek_token (parser)->location; |
8455 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
8456 | { |
8457 | if (is_foreach_statement) |
8458 | { |
8459 | c_parser_error (parser, |
8460 | gmsgid: "missing collection in fast enumeration" ); |
8461 | collection_expression = error_mark_node; |
8462 | } |
8463 | else |
8464 | incr = c_process_expr_stmt (loc, NULL_TREE); |
8465 | } |
8466 | else |
8467 | { |
8468 | if (is_foreach_statement) |
8469 | collection_expression |
8470 | = c_fully_fold (c_parser_expression (parser).value, false, NULL); |
8471 | else |
8472 | { |
8473 | struct c_expr ce = c_parser_expression (parser); |
8474 | ce = convert_lvalue_to_rvalue (loc, ce, true, false); |
8475 | incr = c_process_expr_stmt (loc, ce.value); |
8476 | } |
8477 | } |
8478 | parens.skip_until_found_close (parser); |
8479 | } |
8480 | save_in_statement = in_statement; |
8481 | if (is_foreach_statement) |
8482 | { |
8483 | in_statement = IN_OBJC_FOREACH; |
8484 | save_objc_foreach_break_label = objc_foreach_break_label; |
8485 | save_objc_foreach_continue_label = objc_foreach_continue_label; |
8486 | objc_foreach_break_label = create_artificial_label (loc); |
8487 | objc_foreach_continue_label = create_artificial_label (loc); |
8488 | } |
8489 | else |
8490 | in_statement = IN_ITERATION_STMT; |
8491 | |
8492 | token_indent_info body_tinfo |
8493 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8494 | |
8495 | location_t loc_after_labels; |
8496 | bool open_brace = c_parser_next_token_is (parser, type: CPP_OPEN_BRACE); |
8497 | body = c_parser_c99_block_statement (parser, if_p, loc_after_labels: &loc_after_labels); |
8498 | |
8499 | if (is_foreach_statement) |
8500 | objc_finish_foreach_loop (for_loc, object_expression, |
8501 | collection_expression, body, |
8502 | objc_foreach_break_label, |
8503 | objc_foreach_continue_label); |
8504 | else |
8505 | add_stmt (build_stmt (for_loc, FOR_STMT, NULL_TREE, cond, incr, |
8506 | body, NULL_TREE)); |
8507 | add_stmt (c_end_compound_stmt (for_loc, block, |
8508 | flag_isoc99 || c_dialect_objc ())); |
8509 | c_parser_maybe_reclassify_token (parser); |
8510 | |
8511 | token_indent_info next_tinfo |
8512 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8513 | warn_for_misleading_indentation (guard_tinfo: for_tinfo, body_tinfo, next_tinfo); |
8514 | |
8515 | if (next_tinfo.type != CPP_SEMICOLON && !open_brace) |
8516 | warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, |
8517 | for_tinfo.location, RID_FOR); |
8518 | |
8519 | in_statement = save_in_statement; |
8520 | if (is_foreach_statement) |
8521 | { |
8522 | objc_foreach_break_label = save_objc_foreach_break_label; |
8523 | objc_foreach_continue_label = save_objc_foreach_continue_label; |
8524 | } |
8525 | } |
8526 | |
8527 | /* Parse an asm statement, a GNU extension. This is a full-blown asm |
8528 | statement with inputs, outputs, clobbers, and volatile, inline, and goto |
8529 | tags allowed. |
8530 | |
8531 | asm-qualifier: |
8532 | volatile |
8533 | inline |
8534 | goto |
8535 | |
8536 | asm-qualifier-list: |
8537 | asm-qualifier-list asm-qualifier |
8538 | asm-qualifier |
8539 | |
8540 | asm-statement: |
8541 | asm asm-qualifier-list[opt] ( asm-argument ) ; |
8542 | |
8543 | asm-argument: |
8544 | asm-string-literal |
8545 | asm-string-literal : asm-operands[opt] |
8546 | asm-string-literal : asm-operands[opt] : asm-operands[opt] |
8547 | asm-string-literal : asm-operands[opt] : asm-operands[opt] \ |
8548 | : asm-clobbers[opt] |
8549 | asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \ |
8550 | : asm-goto-operands |
8551 | |
8552 | The form with asm-goto-operands is valid if and only if the |
8553 | asm-qualifier-list contains goto, and is the only allowed form in that case. |
8554 | Duplicate asm-qualifiers are not allowed. |
8555 | |
8556 | The :: token is considered equivalent to two consecutive : tokens. */ |
8557 | |
8558 | static tree |
8559 | c_parser_asm_statement (c_parser *parser) |
8560 | { |
8561 | tree str, outputs, inputs, clobbers, labels, ret; |
8562 | bool simple; |
8563 | location_t asm_loc = c_parser_peek_token (parser)->location; |
8564 | int section, nsections; |
8565 | |
8566 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); |
8567 | c_parser_consume_token (parser); |
8568 | |
8569 | /* Handle the asm-qualifier-list. */ |
8570 | location_t volatile_loc = UNKNOWN_LOCATION; |
8571 | location_t inline_loc = UNKNOWN_LOCATION; |
8572 | location_t goto_loc = UNKNOWN_LOCATION; |
8573 | for (;;) |
8574 | { |
8575 | c_token *token = c_parser_peek_token (parser); |
8576 | location_t loc = token->location; |
8577 | switch (token->keyword) |
8578 | { |
8579 | case RID_VOLATILE: |
8580 | if (volatile_loc) |
8581 | { |
8582 | error_at (loc, "duplicate %<asm%> qualifier %qE" , token->value); |
8583 | inform (volatile_loc, "first seen here" ); |
8584 | } |
8585 | else |
8586 | volatile_loc = loc; |
8587 | c_parser_consume_token (parser); |
8588 | continue; |
8589 | |
8590 | case RID_INLINE: |
8591 | if (inline_loc) |
8592 | { |
8593 | error_at (loc, "duplicate %<asm%> qualifier %qE" , token->value); |
8594 | inform (inline_loc, "first seen here" ); |
8595 | } |
8596 | else |
8597 | inline_loc = loc; |
8598 | c_parser_consume_token (parser); |
8599 | continue; |
8600 | |
8601 | case RID_GOTO: |
8602 | if (goto_loc) |
8603 | { |
8604 | error_at (loc, "duplicate %<asm%> qualifier %qE" , token->value); |
8605 | inform (goto_loc, "first seen here" ); |
8606 | } |
8607 | else |
8608 | goto_loc = loc; |
8609 | c_parser_consume_token (parser); |
8610 | continue; |
8611 | |
8612 | case RID_CONST: |
8613 | case RID_RESTRICT: |
8614 | error_at (loc, "%qE is not a valid %<asm%> qualifier" , token->value); |
8615 | c_parser_consume_token (parser); |
8616 | continue; |
8617 | |
8618 | default: |
8619 | break; |
8620 | } |
8621 | break; |
8622 | } |
8623 | |
8624 | bool is_volatile = (volatile_loc != UNKNOWN_LOCATION); |
8625 | bool is_inline = (inline_loc != UNKNOWN_LOCATION); |
8626 | bool is_goto = (goto_loc != UNKNOWN_LOCATION); |
8627 | |
8628 | ret = NULL; |
8629 | |
8630 | matching_parens parens; |
8631 | if (!parens.require_open (parser)) |
8632 | goto error; |
8633 | |
8634 | str = c_parser_asm_string_literal (parser); |
8635 | if (str == NULL_TREE) |
8636 | goto error_close_paren; |
8637 | |
8638 | simple = true; |
8639 | outputs = NULL_TREE; |
8640 | inputs = NULL_TREE; |
8641 | clobbers = NULL_TREE; |
8642 | labels = NULL_TREE; |
8643 | |
8644 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN) && !is_goto) |
8645 | goto done_asm; |
8646 | |
8647 | /* Parse each colon-delimited section of operands. */ |
8648 | nsections = 3 + is_goto; |
8649 | for (section = 0; section < nsections; ++section) |
8650 | { |
8651 | if (c_parser_next_token_is (parser, type: CPP_SCOPE)) |
8652 | { |
8653 | ++section; |
8654 | if (section == nsections) |
8655 | { |
8656 | c_parser_error (parser, gmsgid: "expected %<)%>" ); |
8657 | goto error_close_paren; |
8658 | } |
8659 | c_parser_consume_token (parser); |
8660 | } |
8661 | else if (!c_parser_require (parser, type: CPP_COLON, |
8662 | msgid: is_goto |
8663 | ? G_("expected %<:%>" ) |
8664 | : G_("expected %<:%> or %<)%>" ), |
8665 | UNKNOWN_LOCATION, type_is_unique: is_goto)) |
8666 | goto error_close_paren; |
8667 | |
8668 | /* Once past any colon, we're no longer a simple asm. */ |
8669 | simple = false; |
8670 | |
8671 | if ((!c_parser_next_token_is (parser, type: CPP_COLON) |
8672 | && !c_parser_next_token_is (parser, type: CPP_SCOPE) |
8673 | && !c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
8674 | || section == 3) |
8675 | switch (section) |
8676 | { |
8677 | case 0: |
8678 | outputs = c_parser_asm_operands (parser); |
8679 | break; |
8680 | case 1: |
8681 | inputs = c_parser_asm_operands (parser); |
8682 | break; |
8683 | case 2: |
8684 | clobbers = c_parser_asm_clobbers (parser); |
8685 | break; |
8686 | case 3: |
8687 | labels = c_parser_asm_goto_operands (parser); |
8688 | break; |
8689 | default: |
8690 | gcc_unreachable (); |
8691 | } |
8692 | |
8693 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN) && !is_goto) |
8694 | goto done_asm; |
8695 | } |
8696 | |
8697 | done_asm: |
8698 | if (!parens.require_close (parser)) |
8699 | { |
8700 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
8701 | goto error; |
8702 | } |
8703 | |
8704 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
8705 | c_parser_skip_to_end_of_block_or_statement (parser); |
8706 | |
8707 | ret = build_asm_stmt (is_volatile, |
8708 | build_asm_expr (asm_loc, str, outputs, inputs, |
8709 | clobbers, labels, simple, is_inline)); |
8710 | |
8711 | error: |
8712 | return ret; |
8713 | |
8714 | error_close_paren: |
8715 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
8716 | goto error; |
8717 | } |
8718 | |
8719 | /* Parse asm operands, a GNU extension. |
8720 | |
8721 | asm-operands: |
8722 | asm-operand |
8723 | asm-operands , asm-operand |
8724 | |
8725 | asm-operand: |
8726 | asm-string-literal ( expression ) |
8727 | [ identifier ] asm-string-literal ( expression ) |
8728 | */ |
8729 | |
8730 | static tree |
8731 | c_parser_asm_operands (c_parser *parser) |
8732 | { |
8733 | tree list = NULL_TREE; |
8734 | while (true) |
8735 | { |
8736 | tree name, str; |
8737 | struct c_expr expr; |
8738 | if (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE)) |
8739 | { |
8740 | c_parser_consume_token (parser); |
8741 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
8742 | { |
8743 | tree id = c_parser_peek_token (parser)->value; |
8744 | c_parser_consume_token (parser); |
8745 | name = build_string (IDENTIFIER_LENGTH (id), |
8746 | IDENTIFIER_POINTER (id)); |
8747 | } |
8748 | else |
8749 | { |
8750 | c_parser_error (parser, gmsgid: "expected identifier" ); |
8751 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, NULL); |
8752 | return NULL_TREE; |
8753 | } |
8754 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
8755 | msgid: "expected %<]%>" ); |
8756 | } |
8757 | else |
8758 | name = NULL_TREE; |
8759 | str = c_parser_asm_string_literal (parser); |
8760 | if (str == NULL_TREE) |
8761 | return NULL_TREE; |
8762 | matching_parens parens; |
8763 | if (!parens.require_open (parser)) |
8764 | return NULL_TREE; |
8765 | expr = c_parser_expression (parser); |
8766 | mark_exp_read (expr.value); |
8767 | if (!parens.require_close (parser)) |
8768 | { |
8769 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
8770 | return NULL_TREE; |
8771 | } |
8772 | list = chainon (list, build_tree_list (build_tree_list (name, str), |
8773 | expr.value)); |
8774 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
8775 | c_parser_consume_token (parser); |
8776 | else |
8777 | break; |
8778 | } |
8779 | return list; |
8780 | } |
8781 | |
8782 | /* Parse asm clobbers, a GNU extension. |
8783 | |
8784 | asm-clobbers: |
8785 | asm-string-literal |
8786 | asm-clobbers , asm-string-literal |
8787 | */ |
8788 | |
8789 | static tree |
8790 | c_parser_asm_clobbers (c_parser *parser) |
8791 | { |
8792 | tree list = NULL_TREE; |
8793 | while (true) |
8794 | { |
8795 | tree str = c_parser_asm_string_literal (parser); |
8796 | if (str) |
8797 | list = tree_cons (NULL_TREE, str, list); |
8798 | else |
8799 | return NULL_TREE; |
8800 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
8801 | c_parser_consume_token (parser); |
8802 | else |
8803 | break; |
8804 | } |
8805 | return list; |
8806 | } |
8807 | |
8808 | /* Parse asm goto labels, a GNU extension. |
8809 | |
8810 | asm-goto-operands: |
8811 | identifier |
8812 | asm-goto-operands , identifier |
8813 | */ |
8814 | |
8815 | static tree |
8816 | c_parser_asm_goto_operands (c_parser *parser) |
8817 | { |
8818 | tree list = NULL_TREE; |
8819 | while (true) |
8820 | { |
8821 | tree name, label; |
8822 | |
8823 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
8824 | { |
8825 | c_token *tok = c_parser_peek_token (parser); |
8826 | name = tok->value; |
8827 | label = lookup_label_for_goto (tok->location, name); |
8828 | c_parser_consume_token (parser); |
8829 | TREE_USED (label) = 1; |
8830 | } |
8831 | else |
8832 | { |
8833 | c_parser_error (parser, gmsgid: "expected identifier" ); |
8834 | return NULL_TREE; |
8835 | } |
8836 | |
8837 | name = build_string (IDENTIFIER_LENGTH (name), |
8838 | IDENTIFIER_POINTER (name)); |
8839 | list = tree_cons (name, label, list); |
8840 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
8841 | c_parser_consume_token (parser); |
8842 | else |
8843 | return nreverse (list); |
8844 | } |
8845 | } |
8846 | |
8847 | /* Parse a possibly concatenated sequence of string literals. |
8848 | TRANSLATE says whether to translate them to the execution character |
8849 | set; WIDE_OK says whether any kind of prefixed string literal is |
8850 | permitted in this context. This code is based on that in |
8851 | lex_string. */ |
8852 | |
8853 | struct c_expr |
8854 | c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) |
8855 | { |
8856 | struct c_expr ret; |
8857 | size_t count; |
8858 | struct obstack str_ob; |
8859 | struct obstack loc_ob; |
8860 | cpp_string str, istr, *strs; |
8861 | c_token *tok; |
8862 | location_t loc, last_tok_loc; |
8863 | enum cpp_ttype type; |
8864 | tree value, string_tree; |
8865 | |
8866 | tok = c_parser_peek_token (parser); |
8867 | loc = tok->location; |
8868 | last_tok_loc = linemap_resolve_location (line_table, loc, |
8869 | lrk: LRK_MACRO_DEFINITION_LOCATION, |
8870 | NULL); |
8871 | type = tok->type; |
8872 | switch (type) |
8873 | { |
8874 | case CPP_STRING: |
8875 | case CPP_WSTRING: |
8876 | case CPP_STRING16: |
8877 | case CPP_STRING32: |
8878 | case CPP_UTF8STRING: |
8879 | string_tree = tok->value; |
8880 | break; |
8881 | |
8882 | default: |
8883 | c_parser_error (parser, gmsgid: "expected string literal" ); |
8884 | ret.set_error (); |
8885 | ret.value = NULL_TREE; |
8886 | ret.original_code = ERROR_MARK; |
8887 | ret.original_type = NULL_TREE; |
8888 | return ret; |
8889 | } |
8890 | |
8891 | /* Try to avoid the overhead of creating and destroying an obstack |
8892 | for the common case of just one string. */ |
8893 | switch (c_parser_peek_2nd_token (parser)->type) |
8894 | { |
8895 | default: |
8896 | c_parser_consume_token (parser); |
8897 | str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); |
8898 | str.len = TREE_STRING_LENGTH (string_tree); |
8899 | count = 1; |
8900 | strs = &str; |
8901 | break; |
8902 | |
8903 | case CPP_STRING: |
8904 | case CPP_WSTRING: |
8905 | case CPP_STRING16: |
8906 | case CPP_STRING32: |
8907 | case CPP_UTF8STRING: |
8908 | gcc_obstack_init (&str_ob); |
8909 | gcc_obstack_init (&loc_ob); |
8910 | count = 0; |
8911 | do |
8912 | { |
8913 | c_parser_consume_token (parser); |
8914 | count++; |
8915 | str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); |
8916 | str.len = TREE_STRING_LENGTH (string_tree); |
8917 | if (type != tok->type) |
8918 | { |
8919 | if (type == CPP_STRING) |
8920 | type = tok->type; |
8921 | else if (tok->type != CPP_STRING) |
8922 | error ("unsupported non-standard concatenation " |
8923 | "of string literals" ); |
8924 | } |
8925 | obstack_grow (&str_ob, &str, sizeof (cpp_string)); |
8926 | obstack_grow (&loc_ob, &last_tok_loc, sizeof (location_t)); |
8927 | tok = c_parser_peek_token (parser); |
8928 | string_tree = tok->value; |
8929 | last_tok_loc |
8930 | = linemap_resolve_location (line_table, loc: tok->location, |
8931 | lrk: LRK_MACRO_DEFINITION_LOCATION, NULL); |
8932 | } |
8933 | while (tok->type == CPP_STRING |
8934 | || tok->type == CPP_WSTRING |
8935 | || tok->type == CPP_STRING16 |
8936 | || tok->type == CPP_STRING32 |
8937 | || tok->type == CPP_UTF8STRING); |
8938 | strs = (cpp_string *) obstack_finish (&str_ob); |
8939 | } |
8940 | |
8941 | if (count > 1 && !in_system_header_at (loc: input_location)) |
8942 | warning (OPT_Wtraditional, |
8943 | "traditional C rejects string constant concatenation" ); |
8944 | |
8945 | if ((type == CPP_STRING || wide_ok) |
8946 | && ((translate |
8947 | ? cpp_interpret_string : cpp_interpret_string_notranslate) |
8948 | (parse_in, strs, count, &istr, type))) |
8949 | { |
8950 | value = build_string (istr.len, (const char *) istr.text); |
8951 | free (CONST_CAST (unsigned char *, istr.text)); |
8952 | if (count > 1) |
8953 | { |
8954 | location_t *locs = (location_t *) obstack_finish (&loc_ob); |
8955 | gcc_assert (g_string_concat_db); |
8956 | g_string_concat_db->record_string_concatenation (num: count, locs); |
8957 | } |
8958 | } |
8959 | else |
8960 | { |
8961 | if (type != CPP_STRING && !wide_ok) |
8962 | { |
8963 | error_at (loc, "a wide string is invalid in this context" ); |
8964 | type = CPP_STRING; |
8965 | } |
8966 | /* Callers cannot generally handle error_mark_node in this |
8967 | context, so return the empty string instead. An error has |
8968 | been issued, either above or from cpp_interpret_string. */ |
8969 | switch (type) |
8970 | { |
8971 | default: |
8972 | case CPP_STRING: |
8973 | case CPP_UTF8STRING: |
8974 | if (type == CPP_UTF8STRING && flag_char8_t) |
8975 | { |
8976 | value = build_string (TYPE_PRECISION (char8_type_node) |
8977 | / TYPE_PRECISION (char_type_node), |
8978 | "" ); /* char8_t is 8 bits */ |
8979 | } |
8980 | else |
8981 | value = build_string (1, "" ); |
8982 | break; |
8983 | case CPP_STRING16: |
8984 | value = build_string (TYPE_PRECISION (char16_type_node) |
8985 | / TYPE_PRECISION (char_type_node), |
8986 | "\0" ); /* char16_t is 16 bits */ |
8987 | break; |
8988 | case CPP_STRING32: |
8989 | value = build_string (TYPE_PRECISION (char32_type_node) |
8990 | / TYPE_PRECISION (char_type_node), |
8991 | "\0\0\0" ); /* char32_t is 32 bits */ |
8992 | break; |
8993 | case CPP_WSTRING: |
8994 | value = build_string (TYPE_PRECISION (wchar_type_node) |
8995 | / TYPE_PRECISION (char_type_node), |
8996 | "\0\0\0" ); /* widest supported wchar_t |
8997 | is 32 bits */ |
8998 | break; |
8999 | } |
9000 | } |
9001 | |
9002 | switch (type) |
9003 | { |
9004 | default: |
9005 | case CPP_STRING: |
9006 | TREE_TYPE (value) = char_array_type_node; |
9007 | break; |
9008 | case CPP_UTF8STRING: |
9009 | if (flag_char8_t) |
9010 | TREE_TYPE (value) = char8_array_type_node; |
9011 | else |
9012 | TREE_TYPE (value) = char_array_type_node; |
9013 | break; |
9014 | case CPP_STRING16: |
9015 | TREE_TYPE (value) = char16_array_type_node; |
9016 | break; |
9017 | case CPP_STRING32: |
9018 | TREE_TYPE (value) = char32_array_type_node; |
9019 | break; |
9020 | case CPP_WSTRING: |
9021 | TREE_TYPE (value) = wchar_array_type_node; |
9022 | } |
9023 | value = fix_string_type (value); |
9024 | |
9025 | if (count > 1) |
9026 | { |
9027 | obstack_free (&str_ob, 0); |
9028 | obstack_free (&loc_ob, 0); |
9029 | } |
9030 | |
9031 | ret.value = value; |
9032 | ret.original_code = STRING_CST; |
9033 | ret.original_type = NULL_TREE; |
9034 | set_c_expr_source_range (expr: &ret, src_range: get_range_from_loc (set: line_table, loc)); |
9035 | ret.m_decimal = 0; |
9036 | parser->seen_string_literal = true; |
9037 | return ret; |
9038 | } |
9039 | |
9040 | /* Parse an expression other than a compound expression; that is, an |
9041 | assignment expression (C90 6.3.16, C99 6.5.16, C11 6.5.16). If |
9042 | AFTER is not NULL then it is an Objective-C message expression which |
9043 | is the primary-expression starting the expression as an initializer. |
9044 | |
9045 | assignment-expression: |
9046 | conditional-expression |
9047 | unary-expression assignment-operator assignment-expression |
9048 | |
9049 | assignment-operator: one of |
9050 | = *= /= %= += -= <<= >>= &= ^= |= |
9051 | |
9052 | In GNU C we accept any conditional expression on the LHS and |
9053 | diagnose the invalid lvalue rather than producing a syntax |
9054 | error. */ |
9055 | |
9056 | static struct c_expr |
9057 | c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, |
9058 | tree omp_atomic_lhs) |
9059 | { |
9060 | struct c_expr lhs, rhs, ret; |
9061 | enum tree_code code; |
9062 | location_t op_location, exp_location; |
9063 | bool save_in_omp_for = c_in_omp_for; |
9064 | c_in_omp_for = false; |
9065 | gcc_assert (!after || c_dialect_objc ()); |
9066 | lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); |
9067 | op_location = c_parser_peek_token (parser)->location; |
9068 | switch (c_parser_peek_token (parser)->type) |
9069 | { |
9070 | case CPP_EQ: |
9071 | code = NOP_EXPR; |
9072 | break; |
9073 | case CPP_MULT_EQ: |
9074 | code = MULT_EXPR; |
9075 | break; |
9076 | case CPP_DIV_EQ: |
9077 | code = TRUNC_DIV_EXPR; |
9078 | break; |
9079 | case CPP_MOD_EQ: |
9080 | code = TRUNC_MOD_EXPR; |
9081 | break; |
9082 | case CPP_PLUS_EQ: |
9083 | code = PLUS_EXPR; |
9084 | break; |
9085 | case CPP_MINUS_EQ: |
9086 | code = MINUS_EXPR; |
9087 | break; |
9088 | case CPP_LSHIFT_EQ: |
9089 | code = LSHIFT_EXPR; |
9090 | break; |
9091 | case CPP_RSHIFT_EQ: |
9092 | code = RSHIFT_EXPR; |
9093 | break; |
9094 | case CPP_AND_EQ: |
9095 | code = BIT_AND_EXPR; |
9096 | break; |
9097 | case CPP_XOR_EQ: |
9098 | code = BIT_XOR_EXPR; |
9099 | break; |
9100 | case CPP_OR_EQ: |
9101 | code = BIT_IOR_EXPR; |
9102 | break; |
9103 | default: |
9104 | c_in_omp_for = save_in_omp_for; |
9105 | return lhs; |
9106 | } |
9107 | c_parser_consume_token (parser); |
9108 | exp_location = c_parser_peek_token (parser)->location; |
9109 | rhs = c_parser_expr_no_commas (parser, NULL); |
9110 | rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true); |
9111 | |
9112 | ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, |
9113 | code, exp_location, rhs.value, |
9114 | rhs.original_type); |
9115 | ret.m_decimal = 0; |
9116 | set_c_expr_source_range (expr: &ret, start: lhs.get_start (), finish: rhs.get_finish ()); |
9117 | if (code == NOP_EXPR) |
9118 | ret.original_code = MODIFY_EXPR; |
9119 | else |
9120 | { |
9121 | suppress_warning (ret.value, OPT_Wparentheses); |
9122 | ret.original_code = ERROR_MARK; |
9123 | } |
9124 | ret.original_type = NULL; |
9125 | c_in_omp_for = save_in_omp_for; |
9126 | return ret; |
9127 | } |
9128 | |
9129 | /* Parse a conditional expression (C90 6.3.15, C99 6.5.15, C11 6.5.15). If |
9130 | AFTER is not NULL then it is an Objective-C message expression which is |
9131 | the primary-expression starting the expression as an initializer. |
9132 | |
9133 | conditional-expression: |
9134 | logical-OR-expression |
9135 | logical-OR-expression ? expression : conditional-expression |
9136 | |
9137 | GNU extensions: |
9138 | |
9139 | conditional-expression: |
9140 | logical-OR-expression ? : conditional-expression |
9141 | */ |
9142 | |
9143 | static struct c_expr |
9144 | c_parser_conditional_expression (c_parser *parser, struct c_expr *after, |
9145 | tree omp_atomic_lhs) |
9146 | { |
9147 | struct c_expr cond, exp1, exp2, ret; |
9148 | location_t start, cond_loc, colon_loc; |
9149 | |
9150 | gcc_assert (!after || c_dialect_objc ()); |
9151 | |
9152 | cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); |
9153 | |
9154 | if (c_parser_next_token_is_not (parser, type: CPP_QUERY)) |
9155 | return cond; |
9156 | if (cond.value != error_mark_node) |
9157 | start = cond.get_start (); |
9158 | else |
9159 | start = UNKNOWN_LOCATION; |
9160 | cond_loc = c_parser_peek_token (parser)->location; |
9161 | cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true); |
9162 | c_parser_consume_token (parser); |
9163 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
9164 | { |
9165 | tree eptype = NULL_TREE; |
9166 | |
9167 | location_t middle_loc = c_parser_peek_token (parser)->location; |
9168 | pedwarn (middle_loc, OPT_Wpedantic, |
9169 | "ISO C forbids omitting the middle term of a %<?:%> expression" ); |
9170 | if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) |
9171 | { |
9172 | eptype = TREE_TYPE (cond.value); |
9173 | cond.value = TREE_OPERAND (cond.value, 0); |
9174 | } |
9175 | tree e = cond.value; |
9176 | while (TREE_CODE (e) == COMPOUND_EXPR) |
9177 | e = TREE_OPERAND (e, 1); |
9178 | warn_for_omitted_condop (middle_loc, e); |
9179 | /* Make sure first operand is calculated only once. */ |
9180 | exp1.value = save_expr (default_conversion (cond.value)); |
9181 | if (eptype) |
9182 | exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); |
9183 | exp1.original_type = NULL; |
9184 | exp1.src_range = cond.src_range; |
9185 | cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); |
9186 | c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node; |
9187 | } |
9188 | else |
9189 | { |
9190 | cond.value |
9191 | = c_objc_common_truthvalue_conversion |
9192 | (cond_loc, default_conversion (cond.value)); |
9193 | c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; |
9194 | exp1 = c_parser_expression_conv (parser); |
9195 | mark_exp_read (exp1.value); |
9196 | c_inhibit_evaluation_warnings += |
9197 | ((cond.value == truthvalue_true_node) |
9198 | - (cond.value == truthvalue_false_node)); |
9199 | } |
9200 | |
9201 | colon_loc = c_parser_peek_token (parser)->location; |
9202 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
9203 | { |
9204 | c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; |
9205 | ret.set_error (); |
9206 | ret.original_code = ERROR_MARK; |
9207 | ret.original_type = NULL; |
9208 | return ret; |
9209 | } |
9210 | { |
9211 | location_t exp2_loc = c_parser_peek_token (parser)->location; |
9212 | exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); |
9213 | exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true); |
9214 | } |
9215 | c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; |
9216 | location_t loc1 = make_location (caret: exp1.get_start (), src_range: exp1.src_range); |
9217 | location_t loc2 = make_location (caret: exp2.get_start (), src_range: exp2.src_range); |
9218 | if (UNLIKELY (omp_atomic_lhs != NULL) |
9219 | && (TREE_CODE (cond.value) == GT_EXPR |
9220 | || TREE_CODE (cond.value) == LT_EXPR |
9221 | || TREE_CODE (cond.value) == EQ_EXPR) |
9222 | && c_tree_equal (exp2.value, omp_atomic_lhs) |
9223 | && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs) |
9224 | || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs))) |
9225 | ret.value = build3_loc (loc: colon_loc, code: COND_EXPR, TREE_TYPE (omp_atomic_lhs), |
9226 | arg0: cond.value, arg1: exp1.value, arg2: exp2.value); |
9227 | else |
9228 | ret.value |
9229 | = build_conditional_expr (colon_loc, cond.value, |
9230 | cond.original_code == C_MAYBE_CONST_EXPR, |
9231 | exp1.value, exp1.original_type, loc1, |
9232 | exp2.value, exp2.original_type, loc2); |
9233 | ret.original_code = ERROR_MARK; |
9234 | if (exp1.value == error_mark_node || exp2.value == error_mark_node) |
9235 | ret.original_type = NULL; |
9236 | else |
9237 | { |
9238 | tree t1, t2; |
9239 | |
9240 | /* If both sides are enum type, the default conversion will have |
9241 | made the type of the result be an integer type. We want to |
9242 | remember the enum types we started with. */ |
9243 | t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); |
9244 | t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); |
9245 | ret.original_type = ((t1 != error_mark_node |
9246 | && t2 != error_mark_node |
9247 | && (TYPE_MAIN_VARIANT (t1) |
9248 | == TYPE_MAIN_VARIANT (t2))) |
9249 | ? t1 |
9250 | : NULL); |
9251 | } |
9252 | set_c_expr_source_range (expr: &ret, start, finish: exp2.get_finish ()); |
9253 | ret.m_decimal = 0; |
9254 | return ret; |
9255 | } |
9256 | |
9257 | /* Parse a binary expression; that is, a logical-OR-expression (C90 |
9258 | 6.3.5-6.3.14, C99 6.5.5-6.5.14, C11 6.5.5-6.5.14). If AFTER is not |
9259 | NULL then it is an Objective-C message expression which is the |
9260 | primary-expression starting the expression as an initializer. |
9261 | |
9262 | OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic, |
9263 | when it should be the unfolded lhs. In a valid OpenMP source, |
9264 | one of the operands of the toplevel binary expression must be equal |
9265 | to it. In that case, just return a build2 created binary operation |
9266 | rather than result of parser_build_binary_op. |
9267 | |
9268 | multiplicative-expression: |
9269 | cast-expression |
9270 | multiplicative-expression * cast-expression |
9271 | multiplicative-expression / cast-expression |
9272 | multiplicative-expression % cast-expression |
9273 | |
9274 | additive-expression: |
9275 | multiplicative-expression |
9276 | additive-expression + multiplicative-expression |
9277 | additive-expression - multiplicative-expression |
9278 | |
9279 | shift-expression: |
9280 | additive-expression |
9281 | shift-expression << additive-expression |
9282 | shift-expression >> additive-expression |
9283 | |
9284 | relational-expression: |
9285 | shift-expression |
9286 | relational-expression < shift-expression |
9287 | relational-expression > shift-expression |
9288 | relational-expression <= shift-expression |
9289 | relational-expression >= shift-expression |
9290 | |
9291 | equality-expression: |
9292 | relational-expression |
9293 | equality-expression == relational-expression |
9294 | equality-expression != relational-expression |
9295 | |
9296 | AND-expression: |
9297 | equality-expression |
9298 | AND-expression & equality-expression |
9299 | |
9300 | exclusive-OR-expression: |
9301 | AND-expression |
9302 | exclusive-OR-expression ^ AND-expression |
9303 | |
9304 | inclusive-OR-expression: |
9305 | exclusive-OR-expression |
9306 | inclusive-OR-expression | exclusive-OR-expression |
9307 | |
9308 | logical-AND-expression: |
9309 | inclusive-OR-expression |
9310 | logical-AND-expression && inclusive-OR-expression |
9311 | |
9312 | logical-OR-expression: |
9313 | logical-AND-expression |
9314 | logical-OR-expression || logical-AND-expression |
9315 | */ |
9316 | |
9317 | static struct c_expr |
9318 | c_parser_binary_expression (c_parser *parser, struct c_expr *after, |
9319 | tree omp_atomic_lhs) |
9320 | { |
9321 | /* A binary expression is parsed using operator-precedence parsing, |
9322 | with the operands being cast expressions. All the binary |
9323 | operators are left-associative. Thus a binary expression is of |
9324 | form: |
9325 | |
9326 | E0 op1 E1 op2 E2 ... |
9327 | |
9328 | which we represent on a stack. On the stack, the precedence |
9329 | levels are strictly increasing. When a new operator is |
9330 | encountered of higher precedence than that at the top of the |
9331 | stack, it is pushed; its LHS is the top expression, and its RHS |
9332 | is everything parsed until it is popped. When a new operator is |
9333 | encountered with precedence less than or equal to that at the top |
9334 | of the stack, triples E[i-1] op[i] E[i] are popped and replaced |
9335 | by the result of the operation until the operator at the top of |
9336 | the stack has lower precedence than the new operator or there is |
9337 | only one element on the stack; then the top expression is the LHS |
9338 | of the new operator. In the case of logical AND and OR |
9339 | expressions, we also need to adjust c_inhibit_evaluation_warnings |
9340 | as appropriate when the operators are pushed and popped. */ |
9341 | |
9342 | struct { |
9343 | /* The expression at this stack level. */ |
9344 | struct c_expr expr; |
9345 | /* The precedence of the operator on its left, PREC_NONE at the |
9346 | bottom of the stack. */ |
9347 | enum c_parser_prec prec; |
9348 | /* The operation on its left. */ |
9349 | enum tree_code op; |
9350 | /* The source location of this operation. */ |
9351 | location_t loc; |
9352 | /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */ |
9353 | tree sizeof_arg; |
9354 | } stack[NUM_PRECS]; |
9355 | int sp; |
9356 | /* Location of the binary operator. */ |
9357 | location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
9358 | #define POP \ |
9359 | do { \ |
9360 | switch (stack[sp].op) \ |
9361 | { \ |
9362 | case TRUTH_ANDIF_EXPR: \ |
9363 | c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ |
9364 | == truthvalue_false_node); \ |
9365 | break; \ |
9366 | case TRUTH_ORIF_EXPR: \ |
9367 | c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ |
9368 | == truthvalue_true_node); \ |
9369 | break; \ |
9370 | case TRUNC_DIV_EXPR: \ |
9371 | if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \ |
9372 | || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \ |
9373 | && (stack[sp].expr.original_code == SIZEOF_EXPR \ |
9374 | || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \ |
9375 | { \ |
9376 | tree type0 = stack[sp - 1].sizeof_arg; \ |
9377 | tree type1 = stack[sp].sizeof_arg; \ |
9378 | tree first_arg = type0; \ |
9379 | if (!TYPE_P (type0)) \ |
9380 | type0 = TREE_TYPE (type0); \ |
9381 | if (!TYPE_P (type1)) \ |
9382 | type1 = TREE_TYPE (type1); \ |
9383 | if (POINTER_TYPE_P (type0) \ |
9384 | && comptypes (TREE_TYPE (type0), type1) \ |
9385 | && !(TREE_CODE (first_arg) == PARM_DECL \ |
9386 | && C_ARRAY_PARAMETER (first_arg) \ |
9387 | && warn_sizeof_array_argument)) \ |
9388 | { \ |
9389 | auto_diagnostic_group d; \ |
9390 | if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ |
9391 | "division %<sizeof (%T) / sizeof (%T)%> " \ |
9392 | "does not compute the number of array " \ |
9393 | "elements", \ |
9394 | type0, type1)) \ |
9395 | if (DECL_P (first_arg)) \ |
9396 | inform (DECL_SOURCE_LOCATION (first_arg), \ |
9397 | "first %<sizeof%> operand was declared here"); \ |
9398 | } \ |
9399 | else if (TREE_CODE (type0) == ARRAY_TYPE \ |
9400 | && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \ |
9401 | && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \ |
9402 | maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \ |
9403 | stack[sp].sizeof_arg, type1); \ |
9404 | } \ |
9405 | break; \ |
9406 | default: \ |
9407 | break; \ |
9408 | } \ |
9409 | stack[sp - 1].expr \ |
9410 | = convert_lvalue_to_rvalue (stack[sp - 1].loc, \ |
9411 | stack[sp - 1].expr, true, true); \ |
9412 | stack[sp].expr \ |
9413 | = convert_lvalue_to_rvalue (stack[sp].loc, \ |
9414 | stack[sp].expr, true, true); \ |
9415 | if (UNLIKELY (omp_atomic_lhs != NULL_TREE) && sp == 1 \ |
9416 | && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \ |
9417 | && ((1 << stack[sp].prec) \ |
9418 | & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \ |
9419 | | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \ |
9420 | | (1 << PREC_ADD) | (1 << PREC_MULT) \ |
9421 | | (1 << PREC_EQ)))) \ |
9422 | || ((c_parser_next_token_is (parser, CPP_QUERY) \ |
9423 | || (omp_atomic_lhs == void_list_node \ |
9424 | && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \ |
9425 | && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\ |
9426 | && stack[sp].op != TRUNC_MOD_EXPR \ |
9427 | && stack[sp].op != GE_EXPR \ |
9428 | && stack[sp].op != LE_EXPR \ |
9429 | && stack[sp].op != NE_EXPR \ |
9430 | && stack[0].expr.value != error_mark_node \ |
9431 | && stack[1].expr.value != error_mark_node \ |
9432 | && (omp_atomic_lhs == void_list_node \ |
9433 | || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ |
9434 | || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \ |
9435 | || (stack[sp].op == EQ_EXPR \ |
9436 | && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \ |
9437 | { \ |
9438 | tree t = make_node (stack[1].op); \ |
9439 | TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \ |
9440 | TREE_OPERAND (t, 0) = stack[0].expr.value; \ |
9441 | TREE_OPERAND (t, 1) = stack[1].expr.value; \ |
9442 | stack[0].expr.value = t; \ |
9443 | stack[0].expr.m_decimal = 0; \ |
9444 | } \ |
9445 | else \ |
9446 | stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ |
9447 | stack[sp].op, \ |
9448 | stack[sp - 1].expr, \ |
9449 | stack[sp].expr); \ |
9450 | sp--; \ |
9451 | } while (0) |
9452 | gcc_assert (!after || c_dialect_objc ()); |
9453 | stack[0].loc = c_parser_peek_token (parser)->location; |
9454 | stack[0].expr = c_parser_cast_expression (parser, after); |
9455 | stack[0].prec = PREC_NONE; |
9456 | stack[0].sizeof_arg = c_last_sizeof_arg; |
9457 | sp = 0; |
9458 | while (true) |
9459 | { |
9460 | enum c_parser_prec oprec; |
9461 | enum tree_code ocode; |
9462 | source_range src_range; |
9463 | if (parser->error) |
9464 | goto out; |
9465 | switch (c_parser_peek_token (parser)->type) |
9466 | { |
9467 | case CPP_MULT: |
9468 | oprec = PREC_MULT; |
9469 | ocode = MULT_EXPR; |
9470 | break; |
9471 | case CPP_DIV: |
9472 | oprec = PREC_MULT; |
9473 | ocode = TRUNC_DIV_EXPR; |
9474 | break; |
9475 | case CPP_MOD: |
9476 | oprec = PREC_MULT; |
9477 | ocode = TRUNC_MOD_EXPR; |
9478 | break; |
9479 | case CPP_PLUS: |
9480 | oprec = PREC_ADD; |
9481 | ocode = PLUS_EXPR; |
9482 | break; |
9483 | case CPP_MINUS: |
9484 | oprec = PREC_ADD; |
9485 | ocode = MINUS_EXPR; |
9486 | break; |
9487 | case CPP_LSHIFT: |
9488 | oprec = PREC_SHIFT; |
9489 | ocode = LSHIFT_EXPR; |
9490 | break; |
9491 | case CPP_RSHIFT: |
9492 | oprec = PREC_SHIFT; |
9493 | ocode = RSHIFT_EXPR; |
9494 | break; |
9495 | case CPP_LESS: |
9496 | oprec = PREC_REL; |
9497 | ocode = LT_EXPR; |
9498 | break; |
9499 | case CPP_GREATER: |
9500 | oprec = PREC_REL; |
9501 | ocode = GT_EXPR; |
9502 | break; |
9503 | case CPP_LESS_EQ: |
9504 | oprec = PREC_REL; |
9505 | ocode = LE_EXPR; |
9506 | break; |
9507 | case CPP_GREATER_EQ: |
9508 | oprec = PREC_REL; |
9509 | ocode = GE_EXPR; |
9510 | break; |
9511 | case CPP_EQ_EQ: |
9512 | oprec = PREC_EQ; |
9513 | ocode = EQ_EXPR; |
9514 | break; |
9515 | case CPP_NOT_EQ: |
9516 | oprec = PREC_EQ; |
9517 | ocode = NE_EXPR; |
9518 | break; |
9519 | case CPP_AND: |
9520 | oprec = PREC_BITAND; |
9521 | ocode = BIT_AND_EXPR; |
9522 | break; |
9523 | case CPP_XOR: |
9524 | oprec = PREC_BITXOR; |
9525 | ocode = BIT_XOR_EXPR; |
9526 | break; |
9527 | case CPP_OR: |
9528 | oprec = PREC_BITOR; |
9529 | ocode = BIT_IOR_EXPR; |
9530 | break; |
9531 | case CPP_AND_AND: |
9532 | oprec = PREC_LOGAND; |
9533 | ocode = TRUTH_ANDIF_EXPR; |
9534 | break; |
9535 | case CPP_OR_OR: |
9536 | oprec = PREC_LOGOR; |
9537 | ocode = TRUTH_ORIF_EXPR; |
9538 | break; |
9539 | default: |
9540 | /* Not a binary operator, so end of the binary |
9541 | expression. */ |
9542 | goto out; |
9543 | } |
9544 | binary_loc = c_parser_peek_token (parser)->location; |
9545 | while (oprec <= stack[sp].prec) |
9546 | POP; |
9547 | c_parser_consume_token (parser); |
9548 | switch (ocode) |
9549 | { |
9550 | case TRUTH_ANDIF_EXPR: |
9551 | src_range = stack[sp].expr.src_range; |
9552 | stack[sp].expr |
9553 | = convert_lvalue_to_rvalue (stack[sp].loc, |
9554 | stack[sp].expr, true, true); |
9555 | stack[sp].expr.value = c_objc_common_truthvalue_conversion |
9556 | (stack[sp].loc, default_conversion (stack[sp].expr.value)); |
9557 | c_inhibit_evaluation_warnings += (stack[sp].expr.value |
9558 | == truthvalue_false_node); |
9559 | set_c_expr_source_range (expr: &stack[sp].expr, src_range); |
9560 | break; |
9561 | case TRUTH_ORIF_EXPR: |
9562 | src_range = stack[sp].expr.src_range; |
9563 | stack[sp].expr |
9564 | = convert_lvalue_to_rvalue (stack[sp].loc, |
9565 | stack[sp].expr, true, true); |
9566 | stack[sp].expr.value = c_objc_common_truthvalue_conversion |
9567 | (stack[sp].loc, default_conversion (stack[sp].expr.value)); |
9568 | c_inhibit_evaluation_warnings += (stack[sp].expr.value |
9569 | == truthvalue_true_node); |
9570 | set_c_expr_source_range (expr: &stack[sp].expr, src_range); |
9571 | break; |
9572 | default: |
9573 | break; |
9574 | } |
9575 | sp++; |
9576 | stack[sp].loc = binary_loc; |
9577 | stack[sp].expr = c_parser_cast_expression (parser, NULL); |
9578 | stack[sp].prec = oprec; |
9579 | stack[sp].op = ocode; |
9580 | stack[sp].sizeof_arg = c_last_sizeof_arg; |
9581 | } |
9582 | out: |
9583 | while (sp > 0) |
9584 | POP; |
9585 | return stack[0].expr; |
9586 | #undef POP |
9587 | } |
9588 | |
9589 | /* Parse any storage class specifiers after an open parenthesis in a |
9590 | context where a compound literal is permitted. */ |
9591 | |
9592 | static struct c_declspecs * |
9593 | c_parser_compound_literal_scspecs (c_parser *parser) |
9594 | { |
9595 | bool seen_scspec = false; |
9596 | struct c_declspecs *specs = build_null_declspecs (); |
9597 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD)) |
9598 | { |
9599 | switch (c_parser_peek_token (parser)->keyword) |
9600 | { |
9601 | case RID_CONSTEXPR: |
9602 | case RID_REGISTER: |
9603 | case RID_STATIC: |
9604 | case RID_THREAD: |
9605 | seen_scspec = true; |
9606 | declspecs_add_scspec (c_parser_peek_token (parser)->location, |
9607 | specs, c_parser_peek_token (parser)->value); |
9608 | c_parser_consume_token (parser); |
9609 | break; |
9610 | default: |
9611 | goto out; |
9612 | } |
9613 | } |
9614 | out: |
9615 | return seen_scspec ? specs : NULL; |
9616 | } |
9617 | |
9618 | /* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4). If AFTER |
9619 | is not NULL then it is an Objective-C message expression which is the |
9620 | primary-expression starting the expression as an initializer. |
9621 | |
9622 | cast-expression: |
9623 | unary-expression |
9624 | ( type-name ) unary-expression |
9625 | */ |
9626 | |
9627 | static struct c_expr |
9628 | c_parser_cast_expression (c_parser *parser, struct c_expr *after) |
9629 | { |
9630 | location_t cast_loc = c_parser_peek_token (parser)->location; |
9631 | gcc_assert (!after || c_dialect_objc ()); |
9632 | if (after) |
9633 | return c_parser_postfix_expression_after_primary (parser, |
9634 | loc: cast_loc, *after); |
9635 | /* If the expression begins with a parenthesized type name, it may |
9636 | be either a cast or a compound literal; we need to see whether |
9637 | the next character is '{' to tell the difference. If not, it is |
9638 | an unary expression. Full detection of unknown typenames here |
9639 | would require a 3-token lookahead. */ |
9640 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
9641 | && c_token_starts_compound_literal (token: c_parser_peek_2nd_token (parser))) |
9642 | { |
9643 | struct c_declspecs *scspecs; |
9644 | struct c_type_name *type_name; |
9645 | struct c_expr ret; |
9646 | struct c_expr expr; |
9647 | matching_parens parens; |
9648 | parens.consume_open (parser); |
9649 | scspecs = c_parser_compound_literal_scspecs (parser); |
9650 | type_name = c_parser_type_name (parser, alignas_ok: true); |
9651 | parens.skip_until_found_close (parser); |
9652 | if (type_name == NULL) |
9653 | { |
9654 | ret.set_error (); |
9655 | ret.original_code = ERROR_MARK; |
9656 | ret.original_type = NULL; |
9657 | return ret; |
9658 | } |
9659 | |
9660 | /* Save casted types in the function's used types hash table. */ |
9661 | used_types_insert (type_name->specs->type); |
9662 | |
9663 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
9664 | return c_parser_postfix_expression_after_paren_type (parser, scspecs, |
9665 | type_name, |
9666 | cast_loc); |
9667 | if (scspecs) |
9668 | error_at (cast_loc, "storage class specifier in cast" ); |
9669 | if (type_name->specs->alignas_p) |
9670 | error_at (type_name->specs->locations[cdw_alignas], |
9671 | "alignment specified for type name in cast" ); |
9672 | { |
9673 | location_t expr_loc = c_parser_peek_token (parser)->location; |
9674 | expr = c_parser_cast_expression (parser, NULL); |
9675 | expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); |
9676 | } |
9677 | ret.value = c_cast_expr (cast_loc, type_name, expr.value); |
9678 | if (ret.value && expr.value) |
9679 | set_c_expr_source_range (expr: &ret, start: cast_loc, finish: expr.get_finish ()); |
9680 | ret.original_code = ERROR_MARK; |
9681 | ret.original_type = NULL; |
9682 | ret.m_decimal = 0; |
9683 | return ret; |
9684 | } |
9685 | else |
9686 | return c_parser_unary_expression (parser); |
9687 | } |
9688 | |
9689 | /* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3). |
9690 | |
9691 | unary-expression: |
9692 | postfix-expression |
9693 | ++ unary-expression |
9694 | -- unary-expression |
9695 | unary-operator cast-expression |
9696 | sizeof unary-expression |
9697 | sizeof ( type-name ) |
9698 | |
9699 | unary-operator: one of |
9700 | & * + - ~ ! |
9701 | |
9702 | GNU extensions: |
9703 | |
9704 | unary-expression: |
9705 | __alignof__ unary-expression |
9706 | __alignof__ ( type-name ) |
9707 | && identifier |
9708 | |
9709 | (C11 permits _Alignof with type names only.) |
9710 | |
9711 | unary-operator: one of |
9712 | __extension__ __real__ __imag__ |
9713 | |
9714 | Transactional Memory: |
9715 | |
9716 | unary-expression: |
9717 | transaction-expression |
9718 | |
9719 | In addition, the GNU syntax treats ++ and -- as unary operators, so |
9720 | they may be applied to cast expressions with errors for non-lvalues |
9721 | given later. */ |
9722 | |
9723 | static struct c_expr |
9724 | c_parser_unary_expression (c_parser *parser) |
9725 | { |
9726 | int ext; |
9727 | struct c_expr ret, op; |
9728 | location_t op_loc = c_parser_peek_token (parser)->location; |
9729 | location_t exp_loc; |
9730 | location_t finish; |
9731 | ret.original_code = ERROR_MARK; |
9732 | ret.original_type = NULL; |
9733 | switch (c_parser_peek_token (parser)->type) |
9734 | { |
9735 | case CPP_PLUS_PLUS: |
9736 | c_parser_consume_token (parser); |
9737 | exp_loc = c_parser_peek_token (parser)->location; |
9738 | op = c_parser_cast_expression (parser, NULL); |
9739 | |
9740 | op = default_function_array_read_conversion (exp_loc, op); |
9741 | return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); |
9742 | case CPP_MINUS_MINUS: |
9743 | c_parser_consume_token (parser); |
9744 | exp_loc = c_parser_peek_token (parser)->location; |
9745 | op = c_parser_cast_expression (parser, NULL); |
9746 | |
9747 | op = default_function_array_read_conversion (exp_loc, op); |
9748 | return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); |
9749 | case CPP_AND: |
9750 | c_parser_consume_token (parser); |
9751 | op = c_parser_cast_expression (parser, NULL); |
9752 | mark_exp_read (op.value); |
9753 | return parser_build_unary_op (op_loc, ADDR_EXPR, op); |
9754 | case CPP_MULT: |
9755 | { |
9756 | c_parser_consume_token (parser); |
9757 | exp_loc = c_parser_peek_token (parser)->location; |
9758 | op = c_parser_cast_expression (parser, NULL); |
9759 | finish = op.get_finish (); |
9760 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9761 | location_t combined_loc = make_location (caret: op_loc, start: op_loc, finish); |
9762 | ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR); |
9763 | ret.src_range.m_start = op_loc; |
9764 | ret.src_range.m_finish = finish; |
9765 | ret.m_decimal = 0; |
9766 | return ret; |
9767 | } |
9768 | case CPP_PLUS: |
9769 | if (!c_dialect_objc () && !in_system_header_at (loc: input_location)) |
9770 | warning_at (op_loc, |
9771 | OPT_Wtraditional, |
9772 | "traditional C rejects the unary plus operator" ); |
9773 | c_parser_consume_token (parser); |
9774 | exp_loc = c_parser_peek_token (parser)->location; |
9775 | op = c_parser_cast_expression (parser, NULL); |
9776 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9777 | return parser_build_unary_op (op_loc, CONVERT_EXPR, op); |
9778 | case CPP_MINUS: |
9779 | c_parser_consume_token (parser); |
9780 | exp_loc = c_parser_peek_token (parser)->location; |
9781 | op = c_parser_cast_expression (parser, NULL); |
9782 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9783 | return parser_build_unary_op (op_loc, NEGATE_EXPR, op); |
9784 | case CPP_COMPL: |
9785 | c_parser_consume_token (parser); |
9786 | exp_loc = c_parser_peek_token (parser)->location; |
9787 | op = c_parser_cast_expression (parser, NULL); |
9788 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9789 | return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); |
9790 | case CPP_NOT: |
9791 | c_parser_consume_token (parser); |
9792 | exp_loc = c_parser_peek_token (parser)->location; |
9793 | op = c_parser_cast_expression (parser, NULL); |
9794 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9795 | return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); |
9796 | case CPP_AND_AND: |
9797 | /* Refer to the address of a label as a pointer. */ |
9798 | c_parser_consume_token (parser); |
9799 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
9800 | { |
9801 | ret.value = finish_label_address_expr |
9802 | (c_parser_peek_token (parser)->value, op_loc); |
9803 | set_c_expr_source_range (expr: &ret, start: op_loc, |
9804 | finish: c_parser_peek_token (parser)->get_finish ()); |
9805 | c_parser_consume_token (parser); |
9806 | } |
9807 | else |
9808 | { |
9809 | c_parser_error (parser, gmsgid: "expected identifier" ); |
9810 | ret.set_error (); |
9811 | } |
9812 | return ret; |
9813 | case CPP_KEYWORD: |
9814 | switch (c_parser_peek_token (parser)->keyword) |
9815 | { |
9816 | case RID_SIZEOF: |
9817 | return c_parser_sizeof_expression (parser); |
9818 | case RID_ALIGNOF: |
9819 | return c_parser_alignof_expression (parser); |
9820 | case RID_BUILTIN_HAS_ATTRIBUTE: |
9821 | return c_parser_has_attribute_expression (parser); |
9822 | case RID_EXTENSION: |
9823 | c_parser_consume_token (parser); |
9824 | ext = disable_extension_diagnostics (); |
9825 | ret = c_parser_cast_expression (parser, NULL); |
9826 | restore_extension_diagnostics (flags: ext); |
9827 | return ret; |
9828 | case RID_REALPART: |
9829 | c_parser_consume_token (parser); |
9830 | exp_loc = c_parser_peek_token (parser)->location; |
9831 | op = c_parser_cast_expression (parser, NULL); |
9832 | op = default_function_array_conversion (exp_loc, op); |
9833 | return parser_build_unary_op (op_loc, REALPART_EXPR, op); |
9834 | case RID_IMAGPART: |
9835 | c_parser_consume_token (parser); |
9836 | exp_loc = c_parser_peek_token (parser)->location; |
9837 | op = c_parser_cast_expression (parser, NULL); |
9838 | op = default_function_array_conversion (exp_loc, op); |
9839 | return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); |
9840 | case RID_TRANSACTION_ATOMIC: |
9841 | case RID_TRANSACTION_RELAXED: |
9842 | return c_parser_transaction_expression (parser, |
9843 | c_parser_peek_token (parser)->keyword); |
9844 | default: |
9845 | return c_parser_postfix_expression (parser); |
9846 | } |
9847 | default: |
9848 | return c_parser_postfix_expression (parser); |
9849 | } |
9850 | } |
9851 | |
9852 | /* Parse a sizeof expression. */ |
9853 | |
9854 | static struct c_expr |
9855 | c_parser_sizeof_expression (c_parser *parser) |
9856 | { |
9857 | struct c_expr expr; |
9858 | struct c_expr result; |
9859 | location_t expr_loc; |
9860 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); |
9861 | |
9862 | location_t start; |
9863 | location_t finish = UNKNOWN_LOCATION; |
9864 | |
9865 | start = c_parser_peek_token (parser)->location; |
9866 | |
9867 | c_parser_consume_token (parser); |
9868 | c_inhibit_evaluation_warnings++; |
9869 | in_sizeof++; |
9870 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
9871 | && c_token_starts_compound_literal (token: c_parser_peek_2nd_token (parser))) |
9872 | { |
9873 | /* Either sizeof ( type-name ) or sizeof unary-expression |
9874 | starting with a compound literal. */ |
9875 | struct c_declspecs *scspecs; |
9876 | struct c_type_name *type_name; |
9877 | matching_parens parens; |
9878 | parens.consume_open (parser); |
9879 | expr_loc = c_parser_peek_token (parser)->location; |
9880 | scspecs = c_parser_compound_literal_scspecs (parser); |
9881 | type_name = c_parser_type_name (parser, alignas_ok: true); |
9882 | parens.skip_until_found_close (parser); |
9883 | finish = parser->tokens_buf[0].location; |
9884 | if (type_name == NULL) |
9885 | { |
9886 | struct c_expr ret; |
9887 | c_inhibit_evaluation_warnings--; |
9888 | in_sizeof--; |
9889 | ret.set_error (); |
9890 | ret.original_code = ERROR_MARK; |
9891 | ret.original_type = NULL; |
9892 | return ret; |
9893 | } |
9894 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
9895 | { |
9896 | expr = c_parser_postfix_expression_after_paren_type (parser, scspecs, |
9897 | type_name, |
9898 | expr_loc); |
9899 | finish = expr.get_finish (); |
9900 | goto sizeof_expr; |
9901 | } |
9902 | /* sizeof ( type-name ). */ |
9903 | if (scspecs) |
9904 | error_at (expr_loc, "storage class specifier in %<sizeof%>" ); |
9905 | if (type_name->specs->alignas_p) |
9906 | error_at (type_name->specs->locations[cdw_alignas], |
9907 | "alignment specified for type name in %<sizeof%>" ); |
9908 | c_inhibit_evaluation_warnings--; |
9909 | in_sizeof--; |
9910 | result = c_expr_sizeof_type (expr_loc, type_name); |
9911 | } |
9912 | else |
9913 | { |
9914 | expr_loc = c_parser_peek_token (parser)->location; |
9915 | expr = c_parser_unary_expression (parser); |
9916 | finish = expr.get_finish (); |
9917 | sizeof_expr: |
9918 | c_inhibit_evaluation_warnings--; |
9919 | in_sizeof--; |
9920 | mark_exp_read (expr.value); |
9921 | if (TREE_CODE (expr.value) == COMPONENT_REF |
9922 | && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) |
9923 | error_at (expr_loc, "%<sizeof%> applied to a bit-field" ); |
9924 | result = c_expr_sizeof_expr (expr_loc, expr); |
9925 | } |
9926 | if (finish == UNKNOWN_LOCATION) |
9927 | finish = start; |
9928 | set_c_expr_source_range (expr: &result, start, finish); |
9929 | return result; |
9930 | } |
9931 | |
9932 | /* Parse an alignof expression. */ |
9933 | |
9934 | static struct c_expr |
9935 | c_parser_alignof_expression (c_parser *parser) |
9936 | { |
9937 | struct c_expr expr; |
9938 | location_t start_loc = c_parser_peek_token (parser)->location; |
9939 | location_t end_loc; |
9940 | tree alignof_spelling = c_parser_peek_token (parser)->value; |
9941 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); |
9942 | bool is_c11_alignof = (strcmp (IDENTIFIER_POINTER (alignof_spelling), |
9943 | s2: "_Alignof" ) == 0 |
9944 | || strcmp (IDENTIFIER_POINTER (alignof_spelling), |
9945 | s2: "alignof" ) == 0); |
9946 | /* A diagnostic is not required for the use of this identifier in |
9947 | the implementation namespace; only diagnose it for the C11 or C23 |
9948 | spelling because of existing code using the other spellings. */ |
9949 | if (is_c11_alignof) |
9950 | { |
9951 | if (flag_isoc99) |
9952 | pedwarn_c99 (start_loc, opt: OPT_Wpedantic, "ISO C99 does not support %qE" , |
9953 | alignof_spelling); |
9954 | else |
9955 | pedwarn_c99 (start_loc, opt: OPT_Wpedantic, "ISO C90 does not support %qE" , |
9956 | alignof_spelling); |
9957 | } |
9958 | c_parser_consume_token (parser); |
9959 | c_inhibit_evaluation_warnings++; |
9960 | in_alignof++; |
9961 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
9962 | && c_token_starts_compound_literal (token: c_parser_peek_2nd_token (parser))) |
9963 | { |
9964 | /* Either __alignof__ ( type-name ) or __alignof__ |
9965 | unary-expression starting with a compound literal. */ |
9966 | location_t loc; |
9967 | struct c_declspecs *scspecs; |
9968 | struct c_type_name *type_name; |
9969 | struct c_expr ret; |
9970 | matching_parens parens; |
9971 | parens.consume_open (parser); |
9972 | loc = c_parser_peek_token (parser)->location; |
9973 | scspecs = c_parser_compound_literal_scspecs (parser); |
9974 | type_name = c_parser_type_name (parser, alignas_ok: true); |
9975 | end_loc = c_parser_peek_token (parser)->location; |
9976 | parens.skip_until_found_close (parser); |
9977 | if (type_name == NULL) |
9978 | { |
9979 | struct c_expr ret; |
9980 | c_inhibit_evaluation_warnings--; |
9981 | in_alignof--; |
9982 | ret.set_error (); |
9983 | ret.original_code = ERROR_MARK; |
9984 | ret.original_type = NULL; |
9985 | return ret; |
9986 | } |
9987 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
9988 | { |
9989 | expr = c_parser_postfix_expression_after_paren_type (parser, scspecs, |
9990 | type_name, |
9991 | loc); |
9992 | goto alignof_expr; |
9993 | } |
9994 | /* alignof ( type-name ). */ |
9995 | if (scspecs) |
9996 | error_at (loc, "storage class specifier in %qE" , alignof_spelling); |
9997 | if (type_name->specs->alignas_p) |
9998 | error_at (type_name->specs->locations[cdw_alignas], |
9999 | "alignment specified for type name in %qE" , |
10000 | alignof_spelling); |
10001 | c_inhibit_evaluation_warnings--; |
10002 | in_alignof--; |
10003 | ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name, |
10004 | NULL, NULL), |
10005 | false, is_c11_alignof, 1); |
10006 | ret.original_code = ERROR_MARK; |
10007 | ret.original_type = NULL; |
10008 | set_c_expr_source_range (expr: &ret, start: start_loc, finish: end_loc); |
10009 | ret.m_decimal = 0; |
10010 | return ret; |
10011 | } |
10012 | else |
10013 | { |
10014 | struct c_expr ret; |
10015 | expr = c_parser_unary_expression (parser); |
10016 | end_loc = expr.src_range.m_finish; |
10017 | alignof_expr: |
10018 | mark_exp_read (expr.value); |
10019 | c_inhibit_evaluation_warnings--; |
10020 | in_alignof--; |
10021 | if (is_c11_alignof) |
10022 | pedwarn (start_loc, |
10023 | OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>" , |
10024 | alignof_spelling); |
10025 | ret.value = c_alignof_expr (start_loc, expr.value); |
10026 | ret.original_code = ERROR_MARK; |
10027 | ret.original_type = NULL; |
10028 | set_c_expr_source_range (expr: &ret, start: start_loc, finish: end_loc); |
10029 | ret.m_decimal = 0; |
10030 | return ret; |
10031 | } |
10032 | } |
10033 | |
10034 | /* Parse the __builtin_has_attribute ([expr|type], attribute-spec) |
10035 | expression. */ |
10036 | |
10037 | static struct c_expr |
10038 | c_parser_has_attribute_expression (c_parser *parser) |
10039 | { |
10040 | gcc_assert (c_parser_next_token_is_keyword (parser, |
10041 | RID_BUILTIN_HAS_ATTRIBUTE)); |
10042 | location_t start = c_parser_peek_token (parser)->location; |
10043 | c_parser_consume_token (parser); |
10044 | |
10045 | c_inhibit_evaluation_warnings++; |
10046 | |
10047 | matching_parens parens; |
10048 | if (!parens.require_open (parser)) |
10049 | { |
10050 | c_inhibit_evaluation_warnings--; |
10051 | in_typeof--; |
10052 | |
10053 | struct c_expr result; |
10054 | result.set_error (); |
10055 | result.original_code = ERROR_MARK; |
10056 | result.original_type = NULL; |
10057 | return result; |
10058 | } |
10059 | |
10060 | /* Treat the type argument the same way as in typeof for the purposes |
10061 | of warnings. FIXME: Generalize this so the warning refers to |
10062 | __builtin_has_attribute rather than typeof. */ |
10063 | in_typeof++; |
10064 | |
10065 | /* The first operand: one of DECL, EXPR, or TYPE. */ |
10066 | tree oper = NULL_TREE; |
10067 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
10068 | { |
10069 | struct c_type_name *tname = c_parser_type_name (parser); |
10070 | in_typeof--; |
10071 | if (tname) |
10072 | { |
10073 | oper = groktypename (tname, NULL, NULL); |
10074 | pop_maybe_used (c_type_variably_modified_p (t: oper)); |
10075 | } |
10076 | } |
10077 | else |
10078 | { |
10079 | struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL); |
10080 | c_inhibit_evaluation_warnings--; |
10081 | in_typeof--; |
10082 | if (cexpr.value != error_mark_node) |
10083 | { |
10084 | mark_exp_read (cexpr.value); |
10085 | oper = cexpr.value; |
10086 | tree etype = TREE_TYPE (oper); |
10087 | bool was_vm = c_type_variably_modified_p (t: etype); |
10088 | /* This is returned with the type so that when the type is |
10089 | evaluated, this can be evaluated. */ |
10090 | if (was_vm) |
10091 | oper = c_fully_fold (oper, false, NULL); |
10092 | pop_maybe_used (was_vm); |
10093 | } |
10094 | } |
10095 | |
10096 | struct c_expr result; |
10097 | result.original_code = ERROR_MARK; |
10098 | result.original_type = NULL; |
10099 | |
10100 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10101 | { |
10102 | /* Consume the closing parenthesis if that's the next token |
10103 | in the likely case the built-in was invoked with fewer |
10104 | than two arguments. */ |
10105 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
10106 | c_parser_consume_token (parser); |
10107 | c_inhibit_evaluation_warnings--; |
10108 | result.set_error (); |
10109 | return result; |
10110 | } |
10111 | |
10112 | bool save_translate_strings_p = parser->translate_strings_p; |
10113 | |
10114 | location_t atloc = c_parser_peek_token (parser)->location; |
10115 | /* Parse a single attribute. Require no leading comma and do not |
10116 | allow empty attributes. */ |
10117 | tree attr = c_parser_gnu_attribute (parser, NULL_TREE, expect_comma: false, empty_ok: false); |
10118 | |
10119 | parser->translate_strings_p = save_translate_strings_p; |
10120 | |
10121 | location_t finish = c_parser_peek_token (parser)->location; |
10122 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
10123 | c_parser_consume_token (parser); |
10124 | else |
10125 | { |
10126 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10127 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10128 | |
10129 | result.set_error (); |
10130 | return result; |
10131 | } |
10132 | |
10133 | if (!attr) |
10134 | { |
10135 | error_at (atloc, "expected identifier" ); |
10136 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10137 | msgid: "expected %<)%>" ); |
10138 | result.set_error (); |
10139 | return result; |
10140 | } |
10141 | |
10142 | result.original_code = INTEGER_CST; |
10143 | result.original_type = boolean_type_node; |
10144 | |
10145 | if (has_attribute (atloc, oper, attr, default_conversion)) |
10146 | result.value = boolean_true_node; |
10147 | else |
10148 | result.value = boolean_false_node; |
10149 | |
10150 | set_c_expr_source_range (expr: &result, start, finish); |
10151 | result.m_decimal = 0; |
10152 | return result; |
10153 | } |
10154 | |
10155 | /* Helper function to read arguments of builtins which are interfaces |
10156 | for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and |
10157 | others. The name of the builtin is passed using BNAME parameter. |
10158 | Function returns true if there were no errors while parsing and |
10159 | stores the arguments in CEXPR_LIST. If it returns true, |
10160 | *OUT_CLOSE_PAREN_LOC is written to with the location of the closing |
10161 | parenthesis. */ |
10162 | static bool |
10163 | c_parser_get_builtin_args (c_parser *parser, const char *bname, |
10164 | vec<c_expr_t, va_gc> **ret_cexpr_list, |
10165 | bool choose_expr_p, |
10166 | location_t *out_close_paren_loc) |
10167 | { |
10168 | location_t loc = c_parser_peek_token (parser)->location; |
10169 | vec<c_expr_t, va_gc> *cexpr_list; |
10170 | c_expr_t expr; |
10171 | bool saved_force_folding_builtin_constant_p; |
10172 | |
10173 | *ret_cexpr_list = NULL; |
10174 | if (c_parser_next_token_is_not (parser, type: CPP_OPEN_PAREN)) |
10175 | { |
10176 | error_at (loc, "cannot take address of %qs" , bname); |
10177 | return false; |
10178 | } |
10179 | |
10180 | c_parser_consume_token (parser); |
10181 | |
10182 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
10183 | { |
10184 | *out_close_paren_loc = c_parser_peek_token (parser)->location; |
10185 | c_parser_consume_token (parser); |
10186 | return true; |
10187 | } |
10188 | |
10189 | saved_force_folding_builtin_constant_p |
10190 | = force_folding_builtin_constant_p; |
10191 | force_folding_builtin_constant_p |= choose_expr_p; |
10192 | expr = c_parser_expr_no_commas (parser, NULL); |
10193 | force_folding_builtin_constant_p |
10194 | = saved_force_folding_builtin_constant_p; |
10195 | vec_alloc (v&: cexpr_list, nelems: 1); |
10196 | vec_safe_push (v&: cexpr_list, obj: expr); |
10197 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
10198 | { |
10199 | c_parser_consume_token (parser); |
10200 | expr = c_parser_expr_no_commas (parser, NULL); |
10201 | vec_safe_push (v&: cexpr_list, obj: expr); |
10202 | } |
10203 | |
10204 | *out_close_paren_loc = c_parser_peek_token (parser)->location; |
10205 | if (!c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
10206 | return false; |
10207 | |
10208 | *ret_cexpr_list = cexpr_list; |
10209 | return true; |
10210 | } |
10211 | |
10212 | /* This represents a single generic-association. */ |
10213 | |
10214 | struct c_generic_association |
10215 | { |
10216 | /* The location of the starting token of the type. */ |
10217 | location_t type_location; |
10218 | /* The association's type, or NULL_TREE for 'default'. */ |
10219 | tree type; |
10220 | /* The association's expression. */ |
10221 | struct c_expr expression; |
10222 | }; |
10223 | |
10224 | /* Parse a generic-selection. (C11 6.5.1.1). |
10225 | |
10226 | generic-selection: |
10227 | _Generic ( assignment-expression , generic-assoc-list ) |
10228 | |
10229 | generic-assoc-list: |
10230 | generic-association |
10231 | generic-assoc-list , generic-association |
10232 | |
10233 | generic-association: |
10234 | type-name : assignment-expression |
10235 | default : assignment-expression |
10236 | */ |
10237 | |
10238 | static struct c_expr |
10239 | c_parser_generic_selection (c_parser *parser) |
10240 | { |
10241 | struct c_expr selector, error_expr; |
10242 | tree selector_type; |
10243 | struct c_generic_association matched_assoc; |
10244 | int match_found = -1; |
10245 | location_t generic_loc, selector_loc; |
10246 | |
10247 | error_expr.original_code = ERROR_MARK; |
10248 | error_expr.original_type = NULL; |
10249 | error_expr.set_error (); |
10250 | matched_assoc.type_location = UNKNOWN_LOCATION; |
10251 | matched_assoc.type = NULL_TREE; |
10252 | matched_assoc.expression = error_expr; |
10253 | |
10254 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC)); |
10255 | generic_loc = c_parser_peek_token (parser)->location; |
10256 | c_parser_consume_token (parser); |
10257 | if (flag_isoc99) |
10258 | pedwarn_c99 (generic_loc, opt: OPT_Wpedantic, |
10259 | "ISO C99 does not support %<_Generic%>" ); |
10260 | else |
10261 | pedwarn_c99 (generic_loc, opt: OPT_Wpedantic, |
10262 | "ISO C90 does not support %<_Generic%>" ); |
10263 | |
10264 | matching_parens parens; |
10265 | if (!parens.require_open (parser)) |
10266 | return error_expr; |
10267 | |
10268 | c_inhibit_evaluation_warnings++; |
10269 | selector_loc = c_parser_peek_token (parser)->location; |
10270 | selector = c_parser_expr_no_commas (parser, NULL); |
10271 | selector = default_function_array_conversion (selector_loc, selector); |
10272 | c_inhibit_evaluation_warnings--; |
10273 | |
10274 | if (selector.value == error_mark_node) |
10275 | { |
10276 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10277 | return selector; |
10278 | } |
10279 | mark_exp_read (selector.value); |
10280 | selector_type = TREE_TYPE (selector.value); |
10281 | /* In ISO C terms, rvalues (including the controlling expression of |
10282 | _Generic) do not have qualified types. */ |
10283 | if (TREE_CODE (selector_type) != ARRAY_TYPE) |
10284 | selector_type = TYPE_MAIN_VARIANT (selector_type); |
10285 | /* In ISO C terms, _Noreturn is not part of the type of expressions |
10286 | such as &abort, but in GCC it is represented internally as a type |
10287 | qualifier. */ |
10288 | if (FUNCTION_POINTER_TYPE_P (selector_type) |
10289 | && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED) |
10290 | selector_type |
10291 | = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type))); |
10292 | |
10293 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10294 | { |
10295 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10296 | return error_expr; |
10297 | } |
10298 | |
10299 | auto_vec<c_generic_association> associations; |
10300 | while (1) |
10301 | { |
10302 | struct c_generic_association assoc, *iter; |
10303 | unsigned int ix; |
10304 | c_token *token = c_parser_peek_token (parser); |
10305 | |
10306 | assoc.type_location = token->location; |
10307 | if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT) |
10308 | { |
10309 | c_parser_consume_token (parser); |
10310 | assoc.type = NULL_TREE; |
10311 | } |
10312 | else |
10313 | { |
10314 | struct c_type_name *type_name; |
10315 | |
10316 | type_name = c_parser_type_name (parser); |
10317 | if (type_name == NULL) |
10318 | { |
10319 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10320 | return error_expr; |
10321 | } |
10322 | assoc.type = groktypename (type_name, NULL, NULL); |
10323 | if (assoc.type == error_mark_node) |
10324 | { |
10325 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10326 | return error_expr; |
10327 | } |
10328 | |
10329 | if (TREE_CODE (assoc.type) == FUNCTION_TYPE) |
10330 | error_at (assoc.type_location, |
10331 | "%<_Generic%> association has function type" ); |
10332 | else if (!COMPLETE_TYPE_P (assoc.type)) |
10333 | error_at (assoc.type_location, |
10334 | "%<_Generic%> association has incomplete type" ); |
10335 | |
10336 | if (c_type_variably_modified_p (t: assoc.type)) |
10337 | error_at (assoc.type_location, |
10338 | "%<_Generic%> association has " |
10339 | "variable length type" ); |
10340 | } |
10341 | |
10342 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
10343 | { |
10344 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10345 | return error_expr; |
10346 | } |
10347 | |
10348 | bool match = assoc.type == NULL_TREE |
10349 | || comptypes (assoc.type, selector_type); |
10350 | |
10351 | if (!match) |
10352 | c_inhibit_evaluation_warnings++; |
10353 | |
10354 | assoc.expression = c_parser_expr_no_commas (parser, NULL); |
10355 | |
10356 | if (!match) |
10357 | c_inhibit_evaluation_warnings--; |
10358 | |
10359 | if (assoc.expression.value == error_mark_node) |
10360 | { |
10361 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10362 | return error_expr; |
10363 | } |
10364 | |
10365 | for (ix = 0; associations.iterate (ix, ptr: &iter); ++ix) |
10366 | { |
10367 | if (assoc.type == NULL_TREE) |
10368 | { |
10369 | if (iter->type == NULL_TREE) |
10370 | { |
10371 | error_at (assoc.type_location, |
10372 | "duplicate %<default%> case in %<_Generic%>" ); |
10373 | inform (iter->type_location, "original %<default%> is here" ); |
10374 | } |
10375 | } |
10376 | else if (iter->type != NULL_TREE) |
10377 | { |
10378 | if (comptypes (assoc.type, iter->type)) |
10379 | { |
10380 | error_at (assoc.type_location, |
10381 | "%<_Generic%> specifies two compatible types" ); |
10382 | inform (iter->type_location, "compatible type is here" ); |
10383 | } |
10384 | } |
10385 | } |
10386 | |
10387 | if (assoc.type == NULL_TREE) |
10388 | { |
10389 | if (match_found < 0) |
10390 | { |
10391 | matched_assoc = assoc; |
10392 | match_found = associations.length (); |
10393 | } |
10394 | } |
10395 | else if (match) |
10396 | { |
10397 | if (match_found < 0 || matched_assoc.type == NULL_TREE) |
10398 | { |
10399 | matched_assoc = assoc; |
10400 | match_found = associations.length (); |
10401 | } |
10402 | else |
10403 | { |
10404 | error_at (assoc.type_location, |
10405 | "%<_Generic%> selector matches multiple associations" ); |
10406 | inform (matched_assoc.type_location, |
10407 | "other match is here" ); |
10408 | } |
10409 | } |
10410 | |
10411 | associations.safe_push (obj: assoc); |
10412 | |
10413 | if (c_parser_peek_token (parser)->type != CPP_COMMA) |
10414 | break; |
10415 | c_parser_consume_token (parser); |
10416 | } |
10417 | |
10418 | unsigned int ix; |
10419 | struct c_generic_association *iter; |
10420 | FOR_EACH_VEC_ELT (associations, ix, iter) |
10421 | if (ix != (unsigned) match_found) |
10422 | mark_exp_read (iter->expression.value); |
10423 | |
10424 | if (!parens.require_close (parser)) |
10425 | { |
10426 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10427 | return error_expr; |
10428 | } |
10429 | |
10430 | if (match_found < 0) |
10431 | { |
10432 | error_at (selector_loc, "%<_Generic%> selector of type %qT is not " |
10433 | "compatible with any association" , |
10434 | selector_type); |
10435 | return error_expr; |
10436 | } |
10437 | |
10438 | return matched_assoc.expression; |
10439 | } |
10440 | |
10441 | /* Check the validity of a function pointer argument *EXPR (argument |
10442 | position POS) to __builtin_tgmath. Return the number of function |
10443 | arguments if possibly valid; return 0 having reported an error if |
10444 | not valid. */ |
10445 | |
10446 | static unsigned int |
10447 | check_tgmath_function (c_expr *expr, unsigned int pos) |
10448 | { |
10449 | tree type = TREE_TYPE (expr->value); |
10450 | if (!FUNCTION_POINTER_TYPE_P (type)) |
10451 | { |
10452 | error_at (expr->get_location (), |
10453 | "argument %u of %<__builtin_tgmath%> is not a function pointer" , |
10454 | pos); |
10455 | return 0; |
10456 | } |
10457 | type = TREE_TYPE (type); |
10458 | if (!prototype_p (type)) |
10459 | { |
10460 | error_at (expr->get_location (), |
10461 | "argument %u of %<__builtin_tgmath%> is unprototyped" , pos); |
10462 | return 0; |
10463 | } |
10464 | if (stdarg_p (type)) |
10465 | { |
10466 | error_at (expr->get_location (), |
10467 | "argument %u of %<__builtin_tgmath%> has variable arguments" , |
10468 | pos); |
10469 | return 0; |
10470 | } |
10471 | unsigned int nargs = 0; |
10472 | function_args_iterator iter; |
10473 | tree t; |
10474 | FOREACH_FUNCTION_ARGS (type, t, iter) |
10475 | { |
10476 | if (t == void_type_node) |
10477 | break; |
10478 | nargs++; |
10479 | } |
10480 | if (nargs == 0) |
10481 | { |
10482 | error_at (expr->get_location (), |
10483 | "argument %u of %<__builtin_tgmath%> has no arguments" , pos); |
10484 | return 0; |
10485 | } |
10486 | return nargs; |
10487 | } |
10488 | |
10489 | /* Ways in which a parameter or return value of a type-generic macro |
10490 | may vary between the different functions the macro may call. */ |
10491 | enum tgmath_parm_kind |
10492 | { |
10493 | tgmath_fixed, tgmath_real, tgmath_complex |
10494 | }; |
10495 | |
10496 | /* Helper function for c_parser_postfix_expression. Parse predefined |
10497 | identifiers. */ |
10498 | |
10499 | static struct c_expr |
10500 | c_parser_predefined_identifier (c_parser *parser) |
10501 | { |
10502 | location_t loc = c_parser_peek_token (parser)->location; |
10503 | switch (c_parser_peek_token (parser)->keyword) |
10504 | { |
10505 | case RID_FUNCTION_NAME: |
10506 | pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " |
10507 | "identifier" , "__FUNCTION__" ); |
10508 | break; |
10509 | case RID_PRETTY_FUNCTION_NAME: |
10510 | pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " |
10511 | "identifier" , "__PRETTY_FUNCTION__" ); |
10512 | break; |
10513 | case RID_C99_FUNCTION_NAME: |
10514 | pedwarn_c90 (loc, opt: OPT_Wpedantic, "ISO C90 does not support " |
10515 | "%<__func__%> predefined identifier" ); |
10516 | break; |
10517 | default: |
10518 | gcc_unreachable (); |
10519 | } |
10520 | |
10521 | struct c_expr expr; |
10522 | expr.original_code = ERROR_MARK; |
10523 | expr.original_type = NULL; |
10524 | expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, |
10525 | c_parser_peek_token (parser)->value); |
10526 | set_c_expr_source_range (expr: &expr, start: loc, finish: loc); |
10527 | expr.m_decimal = 0; |
10528 | c_parser_consume_token (parser); |
10529 | return expr; |
10530 | } |
10531 | |
10532 | /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2, |
10533 | C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to |
10534 | call c_parser_postfix_expression_after_paren_type on encountering them. |
10535 | |
10536 | postfix-expression: |
10537 | primary-expression |
10538 | postfix-expression [ expression ] |
10539 | postfix-expression ( argument-expression-list[opt] ) |
10540 | postfix-expression . identifier |
10541 | postfix-expression -> identifier |
10542 | postfix-expression ++ |
10543 | postfix-expression -- |
10544 | ( storage-class-specifiers[opt] type-name ) { initializer-list[opt] } |
10545 | ( storage-class-specifiers[opt] type-name ) { initializer-list , } |
10546 | |
10547 | argument-expression-list: |
10548 | argument-expression |
10549 | argument-expression-list , argument-expression |
10550 | |
10551 | primary-expression: |
10552 | identifier |
10553 | constant |
10554 | string-literal |
10555 | ( expression ) |
10556 | generic-selection |
10557 | |
10558 | GNU extensions: |
10559 | |
10560 | primary-expression: |
10561 | __func__ |
10562 | (treated as a keyword in GNU C) |
10563 | __FUNCTION__ |
10564 | __PRETTY_FUNCTION__ |
10565 | ( compound-statement ) |
10566 | __builtin_va_arg ( assignment-expression , type-name ) |
10567 | __builtin_offsetof ( type-name , offsetof-member-designator ) |
10568 | __builtin_choose_expr ( assignment-expression , |
10569 | assignment-expression , |
10570 | assignment-expression ) |
10571 | __builtin_types_compatible_p ( type-name , type-name ) |
10572 | __builtin_tgmath ( expr-list ) |
10573 | __builtin_complex ( assignment-expression , assignment-expression ) |
10574 | __builtin_shuffle ( assignment-expression , assignment-expression ) |
10575 | __builtin_shuffle ( assignment-expression , |
10576 | assignment-expression , |
10577 | assignment-expression, ) |
10578 | __builtin_convertvector ( assignment-expression , type-name ) |
10579 | __builtin_assoc_barrier ( assignment-expression ) |
10580 | |
10581 | offsetof-member-designator: |
10582 | identifier |
10583 | offsetof-member-designator . identifier |
10584 | offsetof-member-designator [ expression ] |
10585 | |
10586 | Objective-C: |
10587 | |
10588 | primary-expression: |
10589 | [ objc-receiver objc-message-args ] |
10590 | @selector ( objc-selector-arg ) |
10591 | @protocol ( identifier ) |
10592 | @encode ( type-name ) |
10593 | objc-string-literal |
10594 | Classname . identifier |
10595 | */ |
10596 | |
10597 | static struct c_expr |
10598 | c_parser_postfix_expression (c_parser *parser) |
10599 | { |
10600 | struct c_expr expr, e1; |
10601 | struct c_type_name *t1, *t2; |
10602 | location_t loc = c_parser_peek_token (parser)->location; |
10603 | source_range tok_range = c_parser_peek_token (parser)->get_range (); |
10604 | expr.original_code = ERROR_MARK; |
10605 | expr.original_type = NULL; |
10606 | expr.m_decimal = 0; |
10607 | switch (c_parser_peek_token (parser)->type) |
10608 | { |
10609 | case CPP_NUMBER: |
10610 | expr.value = c_parser_peek_token (parser)->value; |
10611 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10612 | loc = c_parser_peek_token (parser)->location; |
10613 | expr.m_decimal = c_parser_peek_token (parser)->flags & DECIMAL_INT; |
10614 | c_parser_consume_token (parser); |
10615 | if (TREE_CODE (expr.value) == FIXED_CST |
10616 | && !targetm.fixed_point_supported_p ()) |
10617 | { |
10618 | error_at (loc, "fixed-point types not supported for this target" ); |
10619 | expr.set_error (); |
10620 | } |
10621 | break; |
10622 | case CPP_CHAR: |
10623 | case CPP_CHAR16: |
10624 | case CPP_CHAR32: |
10625 | case CPP_UTF8CHAR: |
10626 | case CPP_WCHAR: |
10627 | expr.value = c_parser_peek_token (parser)->value; |
10628 | /* For the purpose of warning when a pointer is compared with |
10629 | a zero character constant. */ |
10630 | expr.original_type = char_type_node; |
10631 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10632 | c_parser_consume_token (parser); |
10633 | break; |
10634 | case CPP_STRING: |
10635 | case CPP_STRING16: |
10636 | case CPP_STRING32: |
10637 | case CPP_WSTRING: |
10638 | case CPP_UTF8STRING: |
10639 | expr = c_parser_string_literal (parser, translate: parser->translate_strings_p, |
10640 | wide_ok: true); |
10641 | break; |
10642 | case CPP_OBJC_STRING: |
10643 | gcc_assert (c_dialect_objc ()); |
10644 | expr.value |
10645 | = objc_build_string_object (c_parser_peek_token (parser)->value); |
10646 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10647 | c_parser_consume_token (parser); |
10648 | break; |
10649 | case CPP_NAME: |
10650 | switch (c_parser_peek_token (parser)->id_kind) |
10651 | { |
10652 | case C_ID_ID: |
10653 | { |
10654 | tree id = c_parser_peek_token (parser)->value; |
10655 | c_parser_consume_token (parser); |
10656 | expr.value = build_external_ref (loc, id, |
10657 | (c_parser_peek_token (parser)->type |
10658 | == CPP_OPEN_PAREN), |
10659 | &expr.original_type); |
10660 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10661 | break; |
10662 | } |
10663 | case C_ID_CLASSNAME: |
10664 | { |
10665 | /* Here we parse the Objective-C 2.0 Class.name dot |
10666 | syntax. */ |
10667 | tree class_name = c_parser_peek_token (parser)->value; |
10668 | tree component; |
10669 | c_parser_consume_token (parser); |
10670 | gcc_assert (c_dialect_objc ()); |
10671 | if (!c_parser_require (parser, type: CPP_DOT, msgid: "expected %<.%>" )) |
10672 | { |
10673 | expr.set_error (); |
10674 | break; |
10675 | } |
10676 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
10677 | { |
10678 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10679 | expr.set_error (); |
10680 | break; |
10681 | } |
10682 | c_token *component_tok = c_parser_peek_token (parser); |
10683 | component = component_tok->value; |
10684 | location_t end_loc = component_tok->get_finish (); |
10685 | c_parser_consume_token (parser); |
10686 | expr.value = objc_build_class_component_ref (class_name, |
10687 | component); |
10688 | set_c_expr_source_range (expr: &expr, start: loc, finish: end_loc); |
10689 | break; |
10690 | } |
10691 | default: |
10692 | c_parser_error (parser, gmsgid: "expected expression" ); |
10693 | expr.set_error (); |
10694 | break; |
10695 | } |
10696 | break; |
10697 | case CPP_OPEN_PAREN: |
10698 | /* A parenthesized expression, statement expression or compound |
10699 | literal. */ |
10700 | if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) |
10701 | { |
10702 | /* A statement expression. */ |
10703 | tree stmt; |
10704 | location_t brace_loc; |
10705 | c_parser_consume_token (parser); |
10706 | brace_loc = c_parser_peek_token (parser)->location; |
10707 | c_parser_consume_token (parser); |
10708 | /* If we've not yet started the current function's statement list, |
10709 | or we're in the parameter scope of an old-style function |
10710 | declaration, statement expressions are not allowed. */ |
10711 | if (!building_stmt_list_p () || old_style_parameter_scope ()) |
10712 | { |
10713 | error_at (loc, "braced-group within expression allowed " |
10714 | "only inside a function" ); |
10715 | parser->error = true; |
10716 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
10717 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10718 | expr.set_error (); |
10719 | break; |
10720 | } |
10721 | stmt = c_begin_stmt_expr (); |
10722 | c_parser_compound_statement_nostart (parser); |
10723 | location_t close_loc = c_parser_peek_token (parser)->location; |
10724 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10725 | msgid: "expected %<)%>" ); |
10726 | pedwarn (loc, OPT_Wpedantic, |
10727 | "ISO C forbids braced-groups within expressions" ); |
10728 | expr.value = c_finish_stmt_expr (brace_loc, stmt); |
10729 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
10730 | mark_exp_read (expr.value); |
10731 | } |
10732 | else |
10733 | { |
10734 | /* A parenthesized expression. */ |
10735 | location_t loc_open_paren = c_parser_peek_token (parser)->location; |
10736 | c_parser_consume_token (parser); |
10737 | expr = c_parser_expression (parser); |
10738 | if (TREE_CODE (expr.value) == MODIFY_EXPR) |
10739 | suppress_warning (expr.value, OPT_Wparentheses); |
10740 | if (expr.original_code != C_MAYBE_CONST_EXPR |
10741 | && expr.original_code != SIZEOF_EXPR) |
10742 | expr.original_code = ERROR_MARK; |
10743 | /* Remember that we saw ( ) around the sizeof. */ |
10744 | if (expr.original_code == SIZEOF_EXPR) |
10745 | expr.original_code = PAREN_SIZEOF_EXPR; |
10746 | /* Don't change EXPR.ORIGINAL_TYPE. */ |
10747 | location_t loc_close_paren = c_parser_peek_token (parser)->location; |
10748 | set_c_expr_source_range (expr: &expr, start: loc_open_paren, finish: loc_close_paren); |
10749 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10750 | msgid: "expected %<)%>" , matching_location: loc_open_paren); |
10751 | } |
10752 | break; |
10753 | case CPP_KEYWORD: |
10754 | switch (c_parser_peek_token (parser)->keyword) |
10755 | { |
10756 | case RID_FUNCTION_NAME: |
10757 | case RID_PRETTY_FUNCTION_NAME: |
10758 | case RID_C99_FUNCTION_NAME: |
10759 | expr = c_parser_predefined_identifier (parser); |
10760 | break; |
10761 | case RID_VA_ARG: |
10762 | { |
10763 | location_t start_loc = loc; |
10764 | c_parser_consume_token (parser); |
10765 | matching_parens parens; |
10766 | if (!parens.require_open (parser)) |
10767 | { |
10768 | expr.set_error (); |
10769 | break; |
10770 | } |
10771 | e1 = c_parser_expr_no_commas (parser, NULL); |
10772 | mark_exp_read (e1.value); |
10773 | e1.value = c_fully_fold (e1.value, false, NULL); |
10774 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10775 | { |
10776 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10777 | expr.set_error (); |
10778 | break; |
10779 | } |
10780 | loc = c_parser_peek_token (parser)->location; |
10781 | t1 = c_parser_type_name (parser); |
10782 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
10783 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10784 | msgid: "expected %<)%>" ); |
10785 | if (t1 == NULL) |
10786 | { |
10787 | expr.set_error (); |
10788 | } |
10789 | else |
10790 | { |
10791 | tree type_expr = NULL_TREE; |
10792 | expr.value = c_build_va_arg (start_loc, e1.value, loc, |
10793 | groktypename (t1, &type_expr, NULL)); |
10794 | if (type_expr) |
10795 | { |
10796 | expr.value = build2 (C_MAYBE_CONST_EXPR, |
10797 | TREE_TYPE (expr.value), type_expr, |
10798 | expr.value); |
10799 | C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; |
10800 | } |
10801 | set_c_expr_source_range (expr: &expr, start: start_loc, finish: end_loc); |
10802 | } |
10803 | } |
10804 | break; |
10805 | case RID_OFFSETOF: |
10806 | { |
10807 | c_parser_consume_token (parser); |
10808 | matching_parens parens; |
10809 | if (!parens.require_open (parser)) |
10810 | { |
10811 | expr.set_error (); |
10812 | break; |
10813 | } |
10814 | t1 = c_parser_type_name (parser); |
10815 | if (t1 == NULL) |
10816 | parser->error = true; |
10817 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10818 | gcc_assert (parser->error); |
10819 | if (parser->error) |
10820 | { |
10821 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10822 | expr.set_error (); |
10823 | break; |
10824 | } |
10825 | tree type = groktypename (t1, NULL, NULL); |
10826 | tree offsetof_ref; |
10827 | if (type == error_mark_node) |
10828 | offsetof_ref = error_mark_node; |
10829 | else |
10830 | { |
10831 | offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); |
10832 | SET_EXPR_LOCATION (offsetof_ref, loc); |
10833 | } |
10834 | /* Parse the second argument to __builtin_offsetof. We |
10835 | must have one identifier, and beyond that we want to |
10836 | accept sub structure and sub array references. */ |
10837 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
10838 | { |
10839 | c_token *comp_tok = c_parser_peek_token (parser); |
10840 | offsetof_ref |
10841 | = build_component_ref (loc, offsetof_ref, comp_tok->value, |
10842 | comp_tok->location, UNKNOWN_LOCATION); |
10843 | c_parser_consume_token (parser); |
10844 | while (c_parser_next_token_is (parser, type: CPP_DOT) |
10845 | || c_parser_next_token_is (parser, |
10846 | type: CPP_OPEN_SQUARE) |
10847 | || c_parser_next_token_is (parser, |
10848 | type: CPP_DEREF)) |
10849 | { |
10850 | if (c_parser_next_token_is (parser, type: CPP_DEREF)) |
10851 | { |
10852 | loc = c_parser_peek_token (parser)->location; |
10853 | offsetof_ref = build_array_ref (loc, |
10854 | offsetof_ref, |
10855 | integer_zero_node); |
10856 | goto do_dot; |
10857 | } |
10858 | else if (c_parser_next_token_is (parser, type: CPP_DOT)) |
10859 | { |
10860 | do_dot: |
10861 | c_parser_consume_token (parser); |
10862 | if (c_parser_next_token_is_not (parser, |
10863 | type: CPP_NAME)) |
10864 | { |
10865 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10866 | break; |
10867 | } |
10868 | c_token *comp_tok = c_parser_peek_token (parser); |
10869 | offsetof_ref |
10870 | = build_component_ref (loc, offsetof_ref, |
10871 | comp_tok->value, |
10872 | comp_tok->location, |
10873 | UNKNOWN_LOCATION); |
10874 | c_parser_consume_token (parser); |
10875 | } |
10876 | else |
10877 | { |
10878 | struct c_expr ce; |
10879 | tree idx; |
10880 | loc = c_parser_peek_token (parser)->location; |
10881 | c_parser_consume_token (parser); |
10882 | ce = c_parser_expression (parser); |
10883 | ce = convert_lvalue_to_rvalue (loc, ce, false, false); |
10884 | idx = ce.value; |
10885 | idx = c_fully_fold (idx, false, NULL); |
10886 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
10887 | msgid: "expected %<]%>" ); |
10888 | offsetof_ref = build_array_ref (loc, offsetof_ref, idx); |
10889 | } |
10890 | } |
10891 | } |
10892 | else |
10893 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10894 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
10895 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10896 | msgid: "expected %<)%>" ); |
10897 | expr.value = fold_offsetof (offsetof_ref); |
10898 | set_c_expr_source_range (expr: &expr, start: loc, finish: end_loc); |
10899 | } |
10900 | break; |
10901 | case RID_CHOOSE_EXPR: |
10902 | { |
10903 | vec<c_expr_t, va_gc> *cexpr_list; |
10904 | c_expr_t *e1_p, *e2_p, *e3_p; |
10905 | tree c; |
10906 | location_t close_paren_loc; |
10907 | |
10908 | c_parser_consume_token (parser); |
10909 | if (!c_parser_get_builtin_args (parser, |
10910 | bname: "__builtin_choose_expr" , |
10911 | ret_cexpr_list: &cexpr_list, choose_expr_p: true, |
10912 | out_close_paren_loc: &close_paren_loc)) |
10913 | { |
10914 | expr.set_error (); |
10915 | break; |
10916 | } |
10917 | |
10918 | if (vec_safe_length (v: cexpr_list) != 3) |
10919 | { |
10920 | error_at (loc, "wrong number of arguments to " |
10921 | "%<__builtin_choose_expr%>" ); |
10922 | expr.set_error (); |
10923 | break; |
10924 | } |
10925 | |
10926 | e1_p = &(*cexpr_list)[0]; |
10927 | e2_p = &(*cexpr_list)[1]; |
10928 | e3_p = &(*cexpr_list)[2]; |
10929 | |
10930 | c = e1_p->value; |
10931 | mark_exp_read (e2_p->value); |
10932 | mark_exp_read (e3_p->value); |
10933 | if (TREE_CODE (c) != INTEGER_CST |
10934 | || !INTEGRAL_TYPE_P (TREE_TYPE (c))) |
10935 | error_at (loc, |
10936 | "first argument to %<__builtin_choose_expr%> not" |
10937 | " a constant" ); |
10938 | constant_expression_warning (c); |
10939 | expr = integer_zerop (c) ? *e3_p : *e2_p; |
10940 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
10941 | break; |
10942 | } |
10943 | case RID_TYPES_COMPATIBLE_P: |
10944 | { |
10945 | c_parser_consume_token (parser); |
10946 | matching_parens parens; |
10947 | if (!parens.require_open (parser)) |
10948 | { |
10949 | expr.set_error (); |
10950 | break; |
10951 | } |
10952 | t1 = c_parser_type_name (parser); |
10953 | if (t1 == NULL) |
10954 | { |
10955 | expr.set_error (); |
10956 | break; |
10957 | } |
10958 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10959 | { |
10960 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10961 | expr.set_error (); |
10962 | break; |
10963 | } |
10964 | t2 = c_parser_type_name (parser); |
10965 | if (t2 == NULL) |
10966 | { |
10967 | expr.set_error (); |
10968 | break; |
10969 | } |
10970 | location_t close_paren_loc = c_parser_peek_token (parser)->location; |
10971 | parens.skip_until_found_close (parser); |
10972 | tree e1, e2; |
10973 | e1 = groktypename (t1, NULL, NULL); |
10974 | e2 = groktypename (t2, NULL, NULL); |
10975 | if (e1 == error_mark_node || e2 == error_mark_node) |
10976 | { |
10977 | expr.set_error (); |
10978 | break; |
10979 | } |
10980 | |
10981 | e1 = TYPE_MAIN_VARIANT (e1); |
10982 | e2 = TYPE_MAIN_VARIANT (e2); |
10983 | |
10984 | expr.value |
10985 | = comptypes (e1, e2) ? integer_one_node : integer_zero_node; |
10986 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
10987 | } |
10988 | break; |
10989 | case RID_BUILTIN_TGMATH: |
10990 | { |
10991 | vec<c_expr_t, va_gc> *cexpr_list; |
10992 | location_t close_paren_loc; |
10993 | |
10994 | c_parser_consume_token (parser); |
10995 | if (!c_parser_get_builtin_args (parser, |
10996 | bname: "__builtin_tgmath" , |
10997 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
10998 | out_close_paren_loc: &close_paren_loc)) |
10999 | { |
11000 | expr.set_error (); |
11001 | break; |
11002 | } |
11003 | |
11004 | if (vec_safe_length (v: cexpr_list) < 3) |
11005 | { |
11006 | error_at (loc, "too few arguments to %<__builtin_tgmath%>" ); |
11007 | expr.set_error (); |
11008 | break; |
11009 | } |
11010 | |
11011 | unsigned int i; |
11012 | c_expr_t *p; |
11013 | FOR_EACH_VEC_ELT (*cexpr_list, i, p) |
11014 | *p = convert_lvalue_to_rvalue (loc, *p, true, true); |
11015 | unsigned int nargs = check_tgmath_function (expr: &(*cexpr_list)[0], pos: 1); |
11016 | if (nargs == 0) |
11017 | { |
11018 | expr.set_error (); |
11019 | break; |
11020 | } |
11021 | if (vec_safe_length (v: cexpr_list) < nargs) |
11022 | { |
11023 | error_at (loc, "too few arguments to %<__builtin_tgmath%>" ); |
11024 | expr.set_error (); |
11025 | break; |
11026 | } |
11027 | unsigned int num_functions = vec_safe_length (v: cexpr_list) - nargs; |
11028 | if (num_functions < 2) |
11029 | { |
11030 | error_at (loc, "too few arguments to %<__builtin_tgmath%>" ); |
11031 | expr.set_error (); |
11032 | break; |
11033 | } |
11034 | |
11035 | /* The first NUM_FUNCTIONS expressions are the function |
11036 | pointers. The remaining NARGS expressions are the |
11037 | arguments that are to be passed to one of those |
11038 | functions, chosen following <tgmath.h> rules. */ |
11039 | for (unsigned int j = 1; j < num_functions; j++) |
11040 | { |
11041 | unsigned int this_nargs |
11042 | = check_tgmath_function (expr: &(*cexpr_list)[j], pos: j + 1); |
11043 | if (this_nargs == 0) |
11044 | { |
11045 | expr.set_error (); |
11046 | goto out; |
11047 | } |
11048 | if (this_nargs != nargs) |
11049 | { |
11050 | error_at ((*cexpr_list)[j].get_location (), |
11051 | "argument %u of %<__builtin_tgmath%> has " |
11052 | "wrong number of arguments" , j + 1); |
11053 | expr.set_error (); |
11054 | goto out; |
11055 | } |
11056 | } |
11057 | |
11058 | /* The functions all have the same number of arguments. |
11059 | Determine whether arguments and return types vary in |
11060 | ways permitted for <tgmath.h> functions. */ |
11061 | /* The first entry in each of these vectors is for the |
11062 | return type, subsequent entries for parameter |
11063 | types. */ |
11064 | auto_vec<enum tgmath_parm_kind> parm_kind (nargs + 1); |
11065 | auto_vec<tree> parm_first (nargs + 1); |
11066 | auto_vec<bool> parm_complex (nargs + 1); |
11067 | auto_vec<bool> parm_varies (nargs + 1); |
11068 | tree first_type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[0].value)); |
11069 | tree first_ret = TYPE_MAIN_VARIANT (TREE_TYPE (first_type)); |
11070 | parm_first.quick_push (obj: first_ret); |
11071 | parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE); |
11072 | parm_varies.quick_push (obj: false); |
11073 | function_args_iterator iter; |
11074 | tree t; |
11075 | unsigned int argpos; |
11076 | FOREACH_FUNCTION_ARGS (first_type, t, iter) |
11077 | { |
11078 | if (t == void_type_node) |
11079 | break; |
11080 | parm_first.quick_push (TYPE_MAIN_VARIANT (t)); |
11081 | parm_complex.quick_push (TREE_CODE (t) == COMPLEX_TYPE); |
11082 | parm_varies.quick_push (obj: false); |
11083 | } |
11084 | for (unsigned int j = 1; j < num_functions; j++) |
11085 | { |
11086 | tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); |
11087 | tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); |
11088 | if (ret != parm_first[0]) |
11089 | { |
11090 | parm_varies[0] = true; |
11091 | if (!SCALAR_FLOAT_TYPE_P (parm_first[0]) |
11092 | && !COMPLEX_FLOAT_TYPE_P (parm_first[0])) |
11093 | { |
11094 | error_at ((*cexpr_list)[0].get_location (), |
11095 | "invalid type-generic return type for " |
11096 | "argument %u of %<__builtin_tgmath%>" , |
11097 | 1); |
11098 | expr.set_error (); |
11099 | goto out; |
11100 | } |
11101 | if (!SCALAR_FLOAT_TYPE_P (ret) |
11102 | && !COMPLEX_FLOAT_TYPE_P (ret)) |
11103 | { |
11104 | error_at ((*cexpr_list)[j].get_location (), |
11105 | "invalid type-generic return type for " |
11106 | "argument %u of %<__builtin_tgmath%>" , |
11107 | j + 1); |
11108 | expr.set_error (); |
11109 | goto out; |
11110 | } |
11111 | } |
11112 | if (TREE_CODE (ret) == COMPLEX_TYPE) |
11113 | parm_complex[0] = true; |
11114 | argpos = 1; |
11115 | FOREACH_FUNCTION_ARGS (type, t, iter) |
11116 | { |
11117 | if (t == void_type_node) |
11118 | break; |
11119 | t = TYPE_MAIN_VARIANT (t); |
11120 | if (t != parm_first[argpos]) |
11121 | { |
11122 | parm_varies[argpos] = true; |
11123 | if (!SCALAR_FLOAT_TYPE_P (parm_first[argpos]) |
11124 | && !COMPLEX_FLOAT_TYPE_P (parm_first[argpos])) |
11125 | { |
11126 | error_at ((*cexpr_list)[0].get_location (), |
11127 | "invalid type-generic type for " |
11128 | "argument %u of argument %u of " |
11129 | "%<__builtin_tgmath%>" , argpos, 1); |
11130 | expr.set_error (); |
11131 | goto out; |
11132 | } |
11133 | if (!SCALAR_FLOAT_TYPE_P (t) |
11134 | && !COMPLEX_FLOAT_TYPE_P (t)) |
11135 | { |
11136 | error_at ((*cexpr_list)[j].get_location (), |
11137 | "invalid type-generic type for " |
11138 | "argument %u of argument %u of " |
11139 | "%<__builtin_tgmath%>" , argpos, j + 1); |
11140 | expr.set_error (); |
11141 | goto out; |
11142 | } |
11143 | } |
11144 | if (TREE_CODE (t) == COMPLEX_TYPE) |
11145 | parm_complex[argpos] = true; |
11146 | argpos++; |
11147 | } |
11148 | } |
11149 | enum tgmath_parm_kind max_variation = tgmath_fixed; |
11150 | for (unsigned int j = 0; j <= nargs; j++) |
11151 | { |
11152 | enum tgmath_parm_kind this_kind; |
11153 | if (parm_varies[j]) |
11154 | { |
11155 | if (parm_complex[j]) |
11156 | max_variation = this_kind = tgmath_complex; |
11157 | else |
11158 | { |
11159 | this_kind = tgmath_real; |
11160 | if (max_variation != tgmath_complex) |
11161 | max_variation = tgmath_real; |
11162 | } |
11163 | } |
11164 | else |
11165 | this_kind = tgmath_fixed; |
11166 | parm_kind.quick_push (obj: this_kind); |
11167 | } |
11168 | if (max_variation == tgmath_fixed) |
11169 | { |
11170 | error_at (loc, "function arguments of %<__builtin_tgmath%> " |
11171 | "all have the same type" ); |
11172 | expr.set_error (); |
11173 | break; |
11174 | } |
11175 | |
11176 | /* Identify a parameter (not the return type) that varies, |
11177 | including with complex types if any variation includes |
11178 | complex types; there must be at least one such |
11179 | parameter. */ |
11180 | unsigned int tgarg = 0; |
11181 | for (unsigned int j = 1; j <= nargs; j++) |
11182 | if (parm_kind[j] == max_variation) |
11183 | { |
11184 | tgarg = j; |
11185 | break; |
11186 | } |
11187 | if (tgarg == 0) |
11188 | { |
11189 | error_at (loc, "function arguments of %<__builtin_tgmath%> " |
11190 | "lack type-generic parameter" ); |
11191 | expr.set_error (); |
11192 | break; |
11193 | } |
11194 | |
11195 | /* Determine the type of the relevant parameter for each |
11196 | function. */ |
11197 | auto_vec<tree> tg_type (num_functions); |
11198 | for (unsigned int j = 0; j < num_functions; j++) |
11199 | { |
11200 | tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); |
11201 | argpos = 1; |
11202 | FOREACH_FUNCTION_ARGS (type, t, iter) |
11203 | { |
11204 | if (argpos == tgarg) |
11205 | { |
11206 | tg_type.quick_push (TYPE_MAIN_VARIANT (t)); |
11207 | break; |
11208 | } |
11209 | argpos++; |
11210 | } |
11211 | } |
11212 | |
11213 | /* Verify that the corresponding types are different for |
11214 | all the listed functions. Also determine whether all |
11215 | the types are complex, whether all the types are |
11216 | standard or binary, and whether all the types are |
11217 | decimal. */ |
11218 | bool all_complex = true; |
11219 | bool all_binary = true; |
11220 | bool all_decimal = true; |
11221 | hash_set<tree> tg_types; |
11222 | FOR_EACH_VEC_ELT (tg_type, i, t) |
11223 | { |
11224 | if (TREE_CODE (t) == COMPLEX_TYPE) |
11225 | all_decimal = false; |
11226 | else |
11227 | { |
11228 | all_complex = false; |
11229 | if (DECIMAL_FLOAT_TYPE_P (t)) |
11230 | all_binary = false; |
11231 | else |
11232 | all_decimal = false; |
11233 | } |
11234 | if (tg_types.add (k: t)) |
11235 | { |
11236 | error_at ((*cexpr_list)[i].get_location (), |
11237 | "duplicate type-generic parameter type for " |
11238 | "function argument %u of %<__builtin_tgmath%>" , |
11239 | i + 1); |
11240 | expr.set_error (); |
11241 | goto out; |
11242 | } |
11243 | } |
11244 | |
11245 | /* Verify that other parameters and the return type whose |
11246 | types vary have their types varying in the correct |
11247 | way. */ |
11248 | for (unsigned int j = 0; j < num_functions; j++) |
11249 | { |
11250 | tree exp_type = tg_type[j]; |
11251 | tree exp_real_type = exp_type; |
11252 | if (TREE_CODE (exp_type) == COMPLEX_TYPE) |
11253 | exp_real_type = TREE_TYPE (exp_type); |
11254 | tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); |
11255 | tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); |
11256 | if ((parm_kind[0] == tgmath_complex && ret != exp_type) |
11257 | || (parm_kind[0] == tgmath_real && ret != exp_real_type)) |
11258 | { |
11259 | error_at ((*cexpr_list)[j].get_location (), |
11260 | "bad return type for function argument %u " |
11261 | "of %<__builtin_tgmath%>" , j + 1); |
11262 | expr.set_error (); |
11263 | goto out; |
11264 | } |
11265 | argpos = 1; |
11266 | FOREACH_FUNCTION_ARGS (type, t, iter) |
11267 | { |
11268 | if (t == void_type_node) |
11269 | break; |
11270 | t = TYPE_MAIN_VARIANT (t); |
11271 | if ((parm_kind[argpos] == tgmath_complex |
11272 | && t != exp_type) |
11273 | || (parm_kind[argpos] == tgmath_real |
11274 | && t != exp_real_type)) |
11275 | { |
11276 | error_at ((*cexpr_list)[j].get_location (), |
11277 | "bad type for argument %u of " |
11278 | "function argument %u of " |
11279 | "%<__builtin_tgmath%>" , argpos, j + 1); |
11280 | expr.set_error (); |
11281 | goto out; |
11282 | } |
11283 | argpos++; |
11284 | } |
11285 | } |
11286 | |
11287 | /* The functions listed are a valid set of functions for a |
11288 | <tgmath.h> macro to select between. Identify the |
11289 | matching function, if any. First, the argument types |
11290 | must be combined following <tgmath.h> rules. Integer |
11291 | types are treated as _Decimal64 if any type-generic |
11292 | argument is decimal, or if the only alternatives for |
11293 | type-generic arguments are of decimal types, and are |
11294 | otherwise treated as _Float32x (or _Complex _Float32x |
11295 | for complex integer types) if any type-generic argument |
11296 | has _FloatNx type, otherwise as double (or _Complex |
11297 | double for complex integer types). After that |
11298 | adjustment, types are combined following the usual |
11299 | arithmetic conversions. If the function only accepts |
11300 | complex arguments, a complex type is produced. */ |
11301 | bool arg_complex = all_complex; |
11302 | bool arg_binary = all_binary; |
11303 | bool arg_int_decimal = all_decimal; |
11304 | bool arg_int_floatnx = false; |
11305 | for (unsigned int j = 1; j <= nargs; j++) |
11306 | { |
11307 | if (parm_kind[j] == tgmath_fixed) |
11308 | continue; |
11309 | c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; |
11310 | tree type = TREE_TYPE (ce->value); |
11311 | if (!INTEGRAL_TYPE_P (type) |
11312 | && !SCALAR_FLOAT_TYPE_P (type) |
11313 | && TREE_CODE (type) != COMPLEX_TYPE) |
11314 | { |
11315 | error_at (ce->get_location (), |
11316 | "invalid type of argument %u of type-generic " |
11317 | "function" , j); |
11318 | expr.set_error (); |
11319 | goto out; |
11320 | } |
11321 | if (DECIMAL_FLOAT_TYPE_P (type)) |
11322 | { |
11323 | arg_int_decimal = true; |
11324 | if (all_complex) |
11325 | { |
11326 | error_at (ce->get_location (), |
11327 | "decimal floating-point argument %u to " |
11328 | "complex-only type-generic function" , j); |
11329 | expr.set_error (); |
11330 | goto out; |
11331 | } |
11332 | else if (all_binary) |
11333 | { |
11334 | error_at (ce->get_location (), |
11335 | "decimal floating-point argument %u to " |
11336 | "binary-only type-generic function" , j); |
11337 | expr.set_error (); |
11338 | goto out; |
11339 | } |
11340 | else if (arg_complex) |
11341 | { |
11342 | error_at (ce->get_location (), |
11343 | "both complex and decimal floating-point " |
11344 | "arguments to type-generic function" ); |
11345 | expr.set_error (); |
11346 | goto out; |
11347 | } |
11348 | else if (arg_binary) |
11349 | { |
11350 | error_at (ce->get_location (), |
11351 | "both binary and decimal floating-point " |
11352 | "arguments to type-generic function" ); |
11353 | expr.set_error (); |
11354 | goto out; |
11355 | } |
11356 | } |
11357 | else if (TREE_CODE (type) == COMPLEX_TYPE) |
11358 | { |
11359 | arg_complex = true; |
11360 | if (COMPLEX_FLOAT_TYPE_P (type)) |
11361 | arg_binary = true; |
11362 | if (all_decimal) |
11363 | { |
11364 | error_at (ce->get_location (), |
11365 | "complex argument %u to " |
11366 | "decimal-only type-generic function" , j); |
11367 | expr.set_error (); |
11368 | goto out; |
11369 | } |
11370 | else if (arg_int_decimal) |
11371 | { |
11372 | error_at (ce->get_location (), |
11373 | "both complex and decimal floating-point " |
11374 | "arguments to type-generic function" ); |
11375 | expr.set_error (); |
11376 | goto out; |
11377 | } |
11378 | } |
11379 | else if (SCALAR_FLOAT_TYPE_P (type)) |
11380 | { |
11381 | arg_binary = true; |
11382 | if (all_decimal) |
11383 | { |
11384 | error_at (ce->get_location (), |
11385 | "binary argument %u to " |
11386 | "decimal-only type-generic function" , j); |
11387 | expr.set_error (); |
11388 | goto out; |
11389 | } |
11390 | else if (arg_int_decimal) |
11391 | { |
11392 | error_at (ce->get_location (), |
11393 | "both binary and decimal floating-point " |
11394 | "arguments to type-generic function" ); |
11395 | expr.set_error (); |
11396 | goto out; |
11397 | } |
11398 | } |
11399 | tree rtype = TYPE_MAIN_VARIANT (type); |
11400 | if (TREE_CODE (rtype) == COMPLEX_TYPE) |
11401 | rtype = TREE_TYPE (rtype); |
11402 | if (SCALAR_FLOAT_TYPE_P (rtype)) |
11403 | for (unsigned int j = 0; j < NUM_FLOATNX_TYPES; j++) |
11404 | if (rtype == FLOATNX_TYPE_NODE (j)) |
11405 | { |
11406 | arg_int_floatnx = true; |
11407 | break; |
11408 | } |
11409 | } |
11410 | tree arg_real = NULL_TREE; |
11411 | for (unsigned int j = 1; j <= nargs; j++) |
11412 | { |
11413 | if (parm_kind[j] == tgmath_fixed) |
11414 | continue; |
11415 | c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; |
11416 | tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ce->value)); |
11417 | if (TREE_CODE (type) == COMPLEX_TYPE) |
11418 | type = TREE_TYPE (type); |
11419 | if (INTEGRAL_TYPE_P (type)) |
11420 | type = (arg_int_decimal |
11421 | ? dfloat64_type_node |
11422 | : arg_int_floatnx |
11423 | ? float32x_type_node |
11424 | : double_type_node); |
11425 | if (arg_real == NULL_TREE) |
11426 | arg_real = type; |
11427 | else |
11428 | arg_real = common_type (arg_real, type); |
11429 | if (arg_real == error_mark_node) |
11430 | { |
11431 | expr.set_error (); |
11432 | goto out; |
11433 | } |
11434 | } |
11435 | tree arg_type = (arg_complex |
11436 | ? build_complex_type (arg_real) |
11437 | : arg_real); |
11438 | |
11439 | /* Look for a function to call with type-generic parameter |
11440 | type ARG_TYPE. */ |
11441 | c_expr_t *fn = NULL; |
11442 | for (unsigned int j = 0; j < num_functions; j++) |
11443 | { |
11444 | if (tg_type[j] == arg_type) |
11445 | { |
11446 | fn = &(*cexpr_list)[j]; |
11447 | break; |
11448 | } |
11449 | } |
11450 | if (fn == NULL |
11451 | && parm_kind[0] == tgmath_fixed |
11452 | && SCALAR_FLOAT_TYPE_P (parm_first[0])) |
11453 | { |
11454 | /* Presume this is a macro that rounds its result to a |
11455 | narrower type, and look for the first function with |
11456 | at least the range and precision of the argument |
11457 | type. */ |
11458 | for (unsigned int j = 0; j < num_functions; j++) |
11459 | { |
11460 | if (arg_complex |
11461 | != (TREE_CODE (tg_type[j]) == COMPLEX_TYPE)) |
11462 | continue; |
11463 | tree real_tg_type = (arg_complex |
11464 | ? TREE_TYPE (tg_type[j]) |
11465 | : tg_type[j]); |
11466 | if (DECIMAL_FLOAT_TYPE_P (arg_real) |
11467 | != DECIMAL_FLOAT_TYPE_P (real_tg_type)) |
11468 | continue; |
11469 | scalar_float_mode arg_mode |
11470 | = SCALAR_FLOAT_TYPE_MODE (arg_real); |
11471 | scalar_float_mode tg_mode |
11472 | = SCALAR_FLOAT_TYPE_MODE (real_tg_type); |
11473 | const real_format *arg_fmt = REAL_MODE_FORMAT (arg_mode); |
11474 | const real_format *tg_fmt = REAL_MODE_FORMAT (tg_mode); |
11475 | if (arg_fmt->b == tg_fmt->b |
11476 | && arg_fmt->p <= tg_fmt->p |
11477 | && arg_fmt->emax <= tg_fmt->emax |
11478 | && (arg_fmt->emin - arg_fmt->p |
11479 | >= tg_fmt->emin - tg_fmt->p)) |
11480 | { |
11481 | fn = &(*cexpr_list)[j]; |
11482 | break; |
11483 | } |
11484 | } |
11485 | } |
11486 | if (fn == NULL) |
11487 | { |
11488 | error_at (loc, "no matching function for type-generic call" ); |
11489 | expr.set_error (); |
11490 | break; |
11491 | } |
11492 | |
11493 | /* Construct a call to FN. */ |
11494 | vec<tree, va_gc> *args; |
11495 | vec_alloc (v&: args, nelems: nargs); |
11496 | vec<tree, va_gc> *origtypes; |
11497 | vec_alloc (v&: origtypes, nelems: nargs); |
11498 | auto_vec<location_t> arg_loc (nargs); |
11499 | for (unsigned int j = 0; j < nargs; j++) |
11500 | { |
11501 | c_expr_t *ce = &(*cexpr_list)[num_functions + j]; |
11502 | args->quick_push (obj: ce->value); |
11503 | arg_loc.quick_push (obj: ce->get_location ()); |
11504 | origtypes->quick_push (obj: ce->original_type); |
11505 | } |
11506 | expr.value = c_build_function_call_vec (loc, arg_loc, fn->value, |
11507 | args, origtypes); |
11508 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11509 | break; |
11510 | } |
11511 | case RID_BUILTIN_CALL_WITH_STATIC_CHAIN: |
11512 | { |
11513 | vec<c_expr_t, va_gc> *cexpr_list; |
11514 | c_expr_t *e2_p; |
11515 | tree chain_value; |
11516 | location_t close_paren_loc; |
11517 | |
11518 | c_parser_consume_token (parser); |
11519 | if (!c_parser_get_builtin_args (parser, |
11520 | bname: "__builtin_call_with_static_chain" , |
11521 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11522 | out_close_paren_loc: &close_paren_loc)) |
11523 | { |
11524 | expr.set_error (); |
11525 | break; |
11526 | } |
11527 | if (vec_safe_length (v: cexpr_list) != 2) |
11528 | { |
11529 | error_at (loc, "wrong number of arguments to " |
11530 | "%<__builtin_call_with_static_chain%>" ); |
11531 | expr.set_error (); |
11532 | break; |
11533 | } |
11534 | |
11535 | expr = (*cexpr_list)[0]; |
11536 | e2_p = &(*cexpr_list)[1]; |
11537 | *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); |
11538 | chain_value = e2_p->value; |
11539 | mark_exp_read (chain_value); |
11540 | |
11541 | if (TREE_CODE (expr.value) != CALL_EXPR) |
11542 | error_at (loc, "first argument to " |
11543 | "%<__builtin_call_with_static_chain%> " |
11544 | "must be a call expression" ); |
11545 | else if (TREE_CODE (TREE_TYPE (chain_value)) != POINTER_TYPE) |
11546 | error_at (loc, "second argument to " |
11547 | "%<__builtin_call_with_static_chain%> " |
11548 | "must be a pointer type" ); |
11549 | else |
11550 | CALL_EXPR_STATIC_CHAIN (expr.value) = chain_value; |
11551 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11552 | break; |
11553 | } |
11554 | case RID_BUILTIN_COMPLEX: |
11555 | { |
11556 | vec<c_expr_t, va_gc> *cexpr_list; |
11557 | c_expr_t *e1_p, *e2_p; |
11558 | location_t close_paren_loc; |
11559 | |
11560 | c_parser_consume_token (parser); |
11561 | if (!c_parser_get_builtin_args (parser, |
11562 | bname: "__builtin_complex" , |
11563 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11564 | out_close_paren_loc: &close_paren_loc)) |
11565 | { |
11566 | expr.set_error (); |
11567 | break; |
11568 | } |
11569 | |
11570 | if (vec_safe_length (v: cexpr_list) != 2) |
11571 | { |
11572 | error_at (loc, "wrong number of arguments to " |
11573 | "%<__builtin_complex%>" ); |
11574 | expr.set_error (); |
11575 | break; |
11576 | } |
11577 | |
11578 | e1_p = &(*cexpr_list)[0]; |
11579 | e2_p = &(*cexpr_list)[1]; |
11580 | |
11581 | *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true); |
11582 | if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR) |
11583 | e1_p->value = convert (TREE_TYPE (e1_p->value), |
11584 | TREE_OPERAND (e1_p->value, 0)); |
11585 | *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); |
11586 | if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR) |
11587 | e2_p->value = convert (TREE_TYPE (e2_p->value), |
11588 | TREE_OPERAND (e2_p->value, 0)); |
11589 | if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) |
11590 | || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) |
11591 | || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)) |
11592 | || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))) |
11593 | { |
11594 | error_at (loc, "%<__builtin_complex%> operand " |
11595 | "not of real binary floating-point type" ); |
11596 | expr.set_error (); |
11597 | break; |
11598 | } |
11599 | if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value)) |
11600 | != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value))) |
11601 | { |
11602 | error_at (loc, |
11603 | "%<__builtin_complex%> operands of different types" ); |
11604 | expr.set_error (); |
11605 | break; |
11606 | } |
11607 | pedwarn_c90 (loc, opt: OPT_Wpedantic, |
11608 | "ISO C90 does not support complex types" ); |
11609 | expr.value = build2_loc (loc, code: COMPLEX_EXPR, |
11610 | type: build_complex_type |
11611 | (TYPE_MAIN_VARIANT |
11612 | (TREE_TYPE (e1_p->value))), |
11613 | arg0: e1_p->value, arg1: e2_p->value); |
11614 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11615 | break; |
11616 | } |
11617 | case RID_BUILTIN_SHUFFLE: |
11618 | { |
11619 | vec<c_expr_t, va_gc> *cexpr_list; |
11620 | unsigned int i; |
11621 | c_expr_t *p; |
11622 | location_t close_paren_loc; |
11623 | |
11624 | c_parser_consume_token (parser); |
11625 | if (!c_parser_get_builtin_args (parser, |
11626 | bname: "__builtin_shuffle" , |
11627 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11628 | out_close_paren_loc: &close_paren_loc)) |
11629 | { |
11630 | expr.set_error (); |
11631 | break; |
11632 | } |
11633 | |
11634 | FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) |
11635 | *p = convert_lvalue_to_rvalue (loc, *p, true, true); |
11636 | |
11637 | if (vec_safe_length (v: cexpr_list) == 2) |
11638 | expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, |
11639 | NULL_TREE, |
11640 | (*cexpr_list)[1].value); |
11641 | |
11642 | else if (vec_safe_length (v: cexpr_list) == 3) |
11643 | expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, |
11644 | (*cexpr_list)[1].value, |
11645 | (*cexpr_list)[2].value); |
11646 | else |
11647 | { |
11648 | error_at (loc, "wrong number of arguments to " |
11649 | "%<__builtin_shuffle%>" ); |
11650 | expr.set_error (); |
11651 | } |
11652 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11653 | break; |
11654 | } |
11655 | case RID_BUILTIN_SHUFFLEVECTOR: |
11656 | { |
11657 | vec<c_expr_t, va_gc> *cexpr_list; |
11658 | unsigned int i; |
11659 | c_expr_t *p; |
11660 | location_t close_paren_loc; |
11661 | |
11662 | c_parser_consume_token (parser); |
11663 | if (!c_parser_get_builtin_args (parser, |
11664 | bname: "__builtin_shufflevector" , |
11665 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11666 | out_close_paren_loc: &close_paren_loc)) |
11667 | { |
11668 | expr.set_error (); |
11669 | break; |
11670 | } |
11671 | |
11672 | FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) |
11673 | *p = convert_lvalue_to_rvalue (loc, *p, true, true); |
11674 | |
11675 | if (vec_safe_length (v: cexpr_list) < 3) |
11676 | { |
11677 | error_at (loc, "wrong number of arguments to " |
11678 | "%<__builtin_shuffle%>" ); |
11679 | expr.set_error (); |
11680 | } |
11681 | else |
11682 | { |
11683 | auto_vec<tree, 16> mask; |
11684 | for (i = 2; i < cexpr_list->length (); ++i) |
11685 | mask.safe_push (obj: (*cexpr_list)[i].value); |
11686 | expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value, |
11687 | (*cexpr_list)[1].value, |
11688 | mask); |
11689 | } |
11690 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11691 | break; |
11692 | } |
11693 | case RID_BUILTIN_CONVERTVECTOR: |
11694 | { |
11695 | location_t start_loc = loc; |
11696 | c_parser_consume_token (parser); |
11697 | matching_parens parens; |
11698 | if (!parens.require_open (parser)) |
11699 | { |
11700 | expr.set_error (); |
11701 | break; |
11702 | } |
11703 | e1 = c_parser_expr_no_commas (parser, NULL); |
11704 | mark_exp_read (e1.value); |
11705 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
11706 | { |
11707 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
11708 | expr.set_error (); |
11709 | break; |
11710 | } |
11711 | loc = c_parser_peek_token (parser)->location; |
11712 | t1 = c_parser_type_name (parser); |
11713 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
11714 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
11715 | msgid: "expected %<)%>" ); |
11716 | if (t1 == NULL) |
11717 | expr.set_error (); |
11718 | else |
11719 | { |
11720 | tree type_expr = NULL_TREE; |
11721 | expr.value = c_build_vec_convert (start_loc, e1.value, loc, |
11722 | groktypename (t1, &type_expr, |
11723 | NULL)); |
11724 | set_c_expr_source_range (expr: &expr, start: start_loc, finish: end_loc); |
11725 | } |
11726 | } |
11727 | break; |
11728 | case RID_BUILTIN_ASSOC_BARRIER: |
11729 | { |
11730 | location_t start_loc = loc; |
11731 | c_parser_consume_token (parser); |
11732 | matching_parens parens; |
11733 | if (!parens.require_open (parser)) |
11734 | { |
11735 | expr.set_error (); |
11736 | break; |
11737 | } |
11738 | e1 = c_parser_expr_no_commas (parser, NULL); |
11739 | mark_exp_read (e1.value); |
11740 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
11741 | parens.skip_until_found_close (parser); |
11742 | expr = parser_build_unary_op (loc, PAREN_EXPR, e1); |
11743 | set_c_expr_source_range (expr: &expr, start: start_loc, finish: end_loc); |
11744 | } |
11745 | break; |
11746 | case RID_AT_SELECTOR: |
11747 | { |
11748 | gcc_assert (c_dialect_objc ()); |
11749 | c_parser_consume_token (parser); |
11750 | matching_parens parens; |
11751 | if (!parens.require_open (parser)) |
11752 | { |
11753 | expr.set_error (); |
11754 | break; |
11755 | } |
11756 | tree sel = c_parser_objc_selector_arg (parser); |
11757 | location_t close_loc = c_parser_peek_token (parser)->location; |
11758 | parens.skip_until_found_close (parser); |
11759 | expr.value = objc_build_selector_expr (loc, sel); |
11760 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
11761 | } |
11762 | break; |
11763 | case RID_AT_PROTOCOL: |
11764 | { |
11765 | gcc_assert (c_dialect_objc ()); |
11766 | c_parser_consume_token (parser); |
11767 | matching_parens parens; |
11768 | if (!parens.require_open (parser)) |
11769 | { |
11770 | expr.set_error (); |
11771 | break; |
11772 | } |
11773 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
11774 | { |
11775 | c_parser_error (parser, gmsgid: "expected identifier" ); |
11776 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
11777 | expr.set_error (); |
11778 | break; |
11779 | } |
11780 | tree id = c_parser_peek_token (parser)->value; |
11781 | c_parser_consume_token (parser); |
11782 | location_t close_loc = c_parser_peek_token (parser)->location; |
11783 | parens.skip_until_found_close (parser); |
11784 | expr.value = objc_build_protocol_expr (id); |
11785 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
11786 | } |
11787 | break; |
11788 | case RID_AT_ENCODE: |
11789 | { |
11790 | /* Extension to support C-structures in the archiver. */ |
11791 | gcc_assert (c_dialect_objc ()); |
11792 | c_parser_consume_token (parser); |
11793 | matching_parens parens; |
11794 | if (!parens.require_open (parser)) |
11795 | { |
11796 | expr.set_error (); |
11797 | break; |
11798 | } |
11799 | t1 = c_parser_type_name (parser); |
11800 | if (t1 == NULL) |
11801 | { |
11802 | expr.set_error (); |
11803 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
11804 | break; |
11805 | } |
11806 | location_t close_loc = c_parser_peek_token (parser)->location; |
11807 | parens.skip_until_found_close (parser); |
11808 | tree type = groktypename (t1, NULL, NULL); |
11809 | expr.value = objc_build_encode_expr (type); |
11810 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
11811 | } |
11812 | break; |
11813 | case RID_GENERIC: |
11814 | expr = c_parser_generic_selection (parser); |
11815 | break; |
11816 | case RID_OMP_ALL_MEMORY: |
11817 | gcc_assert (flag_openmp); |
11818 | c_parser_consume_token (parser); |
11819 | error_at (loc, "%<omp_all_memory%> may only be used in OpenMP " |
11820 | "%<depend%> clause" ); |
11821 | expr.set_error (); |
11822 | break; |
11823 | /* C23 'nullptr' literal. */ |
11824 | case RID_NULLPTR: |
11825 | c_parser_consume_token (parser); |
11826 | expr.value = nullptr_node; |
11827 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
11828 | pedwarn_c11 (loc, opt: OPT_Wpedantic, |
11829 | "ISO C does not support %qs before C23" , "nullptr" ); |
11830 | break; |
11831 | case RID_TRUE: |
11832 | c_parser_consume_token (parser); |
11833 | expr.value = boolean_true_node; |
11834 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
11835 | break; |
11836 | case RID_FALSE: |
11837 | c_parser_consume_token (parser); |
11838 | expr.value = boolean_false_node; |
11839 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
11840 | break; |
11841 | default: |
11842 | c_parser_error (parser, gmsgid: "expected expression" ); |
11843 | expr.set_error (); |
11844 | break; |
11845 | } |
11846 | break; |
11847 | case CPP_OPEN_SQUARE: |
11848 | if (c_dialect_objc ()) |
11849 | { |
11850 | tree receiver, args; |
11851 | c_parser_consume_token (parser); |
11852 | receiver = c_parser_objc_receiver (parser); |
11853 | args = c_parser_objc_message_args (parser); |
11854 | location_t close_loc = c_parser_peek_token (parser)->location; |
11855 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
11856 | msgid: "expected %<]%>" ); |
11857 | expr.value = objc_build_message_expr (receiver, args); |
11858 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
11859 | break; |
11860 | } |
11861 | /* Else fall through to report error. */ |
11862 | /* FALLTHRU */ |
11863 | default: |
11864 | c_parser_error (parser, gmsgid: "expected expression" ); |
11865 | expr.set_error (); |
11866 | break; |
11867 | } |
11868 | out: |
11869 | return c_parser_postfix_expression_after_primary |
11870 | (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); |
11871 | } |
11872 | |
11873 | /* Parse a postfix expression after a parenthesized type name: the |
11874 | brace-enclosed initializer of a compound literal, possibly followed |
11875 | by some postfix operators. This is separate because it is not |
11876 | possible to tell until after the type name whether a cast |
11877 | expression has a cast or a compound literal, or whether the operand |
11878 | of sizeof is a parenthesized type name or starts with a compound |
11879 | literal. TYPE_LOC is the location where TYPE_NAME starts--the |
11880 | location of the first token after the parentheses around the type |
11881 | name. */ |
11882 | |
11883 | static struct c_expr |
11884 | c_parser_postfix_expression_after_paren_type (c_parser *parser, |
11885 | struct c_declspecs *scspecs, |
11886 | struct c_type_name *type_name, |
11887 | location_t type_loc) |
11888 | { |
11889 | tree type; |
11890 | struct c_expr init; |
11891 | bool non_const; |
11892 | struct c_expr expr; |
11893 | location_t start_loc; |
11894 | tree type_expr = NULL_TREE; |
11895 | bool type_expr_const = true; |
11896 | bool constexpr_p = scspecs ? scspecs->constexpr_p : false; |
11897 | unsigned int underspec_state = 0; |
11898 | check_compound_literal_type (type_loc, type_name); |
11899 | rich_location richloc (line_table, type_loc); |
11900 | start_loc = c_parser_peek_token (parser)->location; |
11901 | if (constexpr_p) |
11902 | { |
11903 | underspec_state = start_underspecified_init (start_loc, NULL_TREE); |
11904 | /* A constexpr compound literal is subject to the constraints on |
11905 | underspecified declarations, which may not declare tags or |
11906 | members or structures or unions; it is undefined behavior to |
11907 | declare the members of an enumeration. Where the structure, |
11908 | union or enumeration type is declared within the compound |
11909 | literal initializer, this is diagnosed elsewhere as a result |
11910 | of the above call to start_underspecified_init. Diagnose |
11911 | here the case of declaring such a type in the type specifiers |
11912 | of the compound literal. */ |
11913 | switch (type_name->specs->typespec_kind) |
11914 | { |
11915 | case ctsk_tagfirstref: |
11916 | case ctsk_tagfirstref_attrs: |
11917 | error_at (type_loc, "%qT declared in %<constexpr%> compound literal" , |
11918 | type_name->specs->type); |
11919 | break; |
11920 | |
11921 | case ctsk_tagdef: |
11922 | error_at (type_loc, "%qT defined in %<constexpr%> compound literal" , |
11923 | type_name->specs->type); |
11924 | break; |
11925 | |
11926 | default: |
11927 | break; |
11928 | } |
11929 | } |
11930 | start_init (NULL_TREE, NULL, |
11931 | (global_bindings_p () |
11932 | || (scspecs && scspecs->storage_class == csc_static) |
11933 | || constexpr_p), constexpr_p, &richloc); |
11934 | type = groktypename (type_name, &type_expr, &type_expr_const); |
11935 | if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) |
11936 | { |
11937 | error_at (type_loc, "compound literal has variable size" ); |
11938 | type = error_mark_node; |
11939 | } |
11940 | else if (TREE_CODE (type) == FUNCTION_TYPE) |
11941 | { |
11942 | error_at (type_loc, "compound literal has function type" ); |
11943 | type = error_mark_node; |
11944 | } |
11945 | if (constexpr_p && type != error_mark_node) |
11946 | { |
11947 | tree type_no_array = strip_array_types (type); |
11948 | /* The type of a constexpr object must not be variably modified |
11949 | (which applies to all compound literals), volatile, atomic or |
11950 | restrict qualified or have a member with such a qualifier. |
11951 | const qualification is implicitly added. */ |
11952 | if (TYPE_QUALS (type_no_array) |
11953 | & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC)) |
11954 | error_at (type_loc, "invalid qualifiers for %<constexpr%> object" ); |
11955 | else if (RECORD_OR_UNION_TYPE_P (type_no_array) |
11956 | && C_TYPE_FIELDS_NON_CONSTEXPR (type_no_array)) |
11957 | error_at (type_loc, "invalid qualifiers for field of " |
11958 | "%<constexpr%> object" ); |
11959 | type = c_build_qualified_type (type, |
11960 | (TYPE_QUALS (type_no_array) |
11961 | | TYPE_QUAL_CONST)); |
11962 | } |
11963 | init = c_parser_braced_init (parser, type, nested_p: false, NULL, NULL_TREE); |
11964 | if (constexpr_p) |
11965 | finish_underspecified_init (NULL_TREE, underspec_state); |
11966 | finish_init (); |
11967 | maybe_warn_string_init (type_loc, type, init); |
11968 | |
11969 | if (type != error_mark_node |
11970 | && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) |
11971 | && current_function_decl) |
11972 | { |
11973 | error ("compound literal qualified by address-space qualifier" ); |
11974 | type = error_mark_node; |
11975 | } |
11976 | |
11977 | if (!pedwarn_c90 (start_loc, opt: OPT_Wpedantic, |
11978 | "ISO C90 forbids compound literals" ) && scspecs) |
11979 | pedwarn_c11 (start_loc, opt: OPT_Wpedantic, |
11980 | "ISO C forbids storage class specifiers in compound literals " |
11981 | "before C23" ); |
11982 | non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) |
11983 | ? CONSTRUCTOR_NON_CONST (init.value) |
11984 | : init.original_code == C_MAYBE_CONST_EXPR); |
11985 | non_const |= !type_expr_const; |
11986 | unsigned int alignas_align = 0; |
11987 | if (type != error_mark_node |
11988 | && type_name->specs->align_log != -1) |
11989 | { |
11990 | alignas_align = 1U << type_name->specs->align_log; |
11991 | if (alignas_align < min_align_of_type (type)) |
11992 | { |
11993 | error_at (type_name->specs->locations[cdw_alignas], |
11994 | "%<_Alignas%> specifiers cannot reduce " |
11995 | "alignment of compound literal" ); |
11996 | alignas_align = 0; |
11997 | } |
11998 | } |
11999 | expr.value = build_compound_literal (start_loc, type, init.value, non_const, |
12000 | alignas_align, scspecs); |
12001 | set_c_expr_source_range (expr: &expr, src_range: init.src_range); |
12002 | expr.m_decimal = 0; |
12003 | expr.original_code = ERROR_MARK; |
12004 | expr.original_type = NULL; |
12005 | if (type != error_mark_node |
12006 | && expr.value != error_mark_node |
12007 | && type_expr) |
12008 | { |
12009 | if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) |
12010 | { |
12011 | gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE); |
12012 | C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr; |
12013 | } |
12014 | else |
12015 | { |
12016 | gcc_assert (!non_const); |
12017 | expr.value = build2 (C_MAYBE_CONST_EXPR, type, |
12018 | type_expr, expr.value); |
12019 | } |
12020 | } |
12021 | return c_parser_postfix_expression_after_primary (parser, loc: start_loc, expr); |
12022 | } |
12023 | |
12024 | /* Callback function for sizeof_pointer_memaccess_warning to compare |
12025 | types. */ |
12026 | |
12027 | static bool |
12028 | sizeof_ptr_memacc_comptypes (tree type1, tree type2) |
12029 | { |
12030 | return comptypes (type1, type2) == 1; |
12031 | } |
12032 | |
12033 | /* Warn for patterns where abs-like function appears to be used incorrectly, |
12034 | gracefully ignore any non-abs-like function. The warning location should |
12035 | be LOC. FNDECL is the declaration of called function, it must be a |
12036 | BUILT_IN_NORMAL function. ARG is the first and only argument of the |
12037 | call. */ |
12038 | |
12039 | static void |
12040 | warn_for_abs (location_t loc, tree fndecl, tree arg) |
12041 | { |
12042 | /* Avoid warning in unreachable subexpressions. */ |
12043 | if (c_inhibit_evaluation_warnings) |
12044 | return; |
12045 | |
12046 | tree atype = TREE_TYPE (arg); |
12047 | |
12048 | /* Casts from pointers (and thus arrays and fndecls) will generate |
12049 | -Wint-conversion warnings. Most other wrong types hopefully lead to type |
12050 | mismatch errors. TODO: Think about what to do with FIXED_POINT_TYPE_P |
12051 | types and possibly other exotic types. */ |
12052 | if (!INTEGRAL_TYPE_P (atype) |
12053 | && !SCALAR_FLOAT_TYPE_P (atype) |
12054 | && TREE_CODE (atype) != COMPLEX_TYPE) |
12055 | return; |
12056 | |
12057 | enum built_in_function fcode = DECL_FUNCTION_CODE (decl: fndecl); |
12058 | |
12059 | switch (fcode) |
12060 | { |
12061 | case BUILT_IN_ABS: |
12062 | case BUILT_IN_LABS: |
12063 | case BUILT_IN_LLABS: |
12064 | case BUILT_IN_IMAXABS: |
12065 | if (!INTEGRAL_TYPE_P (atype)) |
12066 | { |
12067 | if (SCALAR_FLOAT_TYPE_P (atype)) |
12068 | warning_at (loc, OPT_Wabsolute_value, |
12069 | "using integer absolute value function %qD when " |
12070 | "argument is of floating-point type %qT" , |
12071 | fndecl, atype); |
12072 | else if (TREE_CODE (atype) == COMPLEX_TYPE) |
12073 | warning_at (loc, OPT_Wabsolute_value, |
12074 | "using integer absolute value function %qD when " |
12075 | "argument is of complex type %qT" , fndecl, atype); |
12076 | else |
12077 | gcc_unreachable (); |
12078 | return; |
12079 | } |
12080 | if (TYPE_UNSIGNED (atype)) |
12081 | warning_at (loc, OPT_Wabsolute_value, |
12082 | "taking the absolute value of unsigned type %qT " |
12083 | "has no effect" , atype); |
12084 | break; |
12085 | |
12086 | CASE_FLT_FN (BUILT_IN_FABS): |
12087 | CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS): |
12088 | if (!SCALAR_FLOAT_TYPE_P (atype) |
12089 | || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype))) |
12090 | { |
12091 | if (INTEGRAL_TYPE_P (atype)) |
12092 | warning_at (loc, OPT_Wabsolute_value, |
12093 | "using floating-point absolute value function %qD " |
12094 | "when argument is of integer type %qT" , fndecl, atype); |
12095 | else if (DECIMAL_FLOAT_TYPE_P (atype)) |
12096 | warning_at (loc, OPT_Wabsolute_value, |
12097 | "using floating-point absolute value function %qD " |
12098 | "when argument is of decimal floating-point type %qT" , |
12099 | fndecl, atype); |
12100 | else if (TREE_CODE (atype) == COMPLEX_TYPE) |
12101 | warning_at (loc, OPT_Wabsolute_value, |
12102 | "using floating-point absolute value function %qD when " |
12103 | "argument is of complex type %qT" , fndecl, atype); |
12104 | else |
12105 | gcc_unreachable (); |
12106 | return; |
12107 | } |
12108 | break; |
12109 | |
12110 | CASE_FLT_FN (BUILT_IN_CABS): |
12111 | if (TREE_CODE (atype) != COMPLEX_TYPE) |
12112 | { |
12113 | if (INTEGRAL_TYPE_P (atype)) |
12114 | warning_at (loc, OPT_Wabsolute_value, |
12115 | "using complex absolute value function %qD when " |
12116 | "argument is of integer type %qT" , fndecl, atype); |
12117 | else if (SCALAR_FLOAT_TYPE_P (atype)) |
12118 | warning_at (loc, OPT_Wabsolute_value, |
12119 | "using complex absolute value function %qD when " |
12120 | "argument is of floating-point type %qT" , |
12121 | fndecl, atype); |
12122 | else |
12123 | gcc_unreachable (); |
12124 | |
12125 | return; |
12126 | } |
12127 | break; |
12128 | |
12129 | case BUILT_IN_FABSD32: |
12130 | case BUILT_IN_FABSD64: |
12131 | case BUILT_IN_FABSD128: |
12132 | if (!DECIMAL_FLOAT_TYPE_P (atype)) |
12133 | { |
12134 | if (INTEGRAL_TYPE_P (atype)) |
12135 | warning_at (loc, OPT_Wabsolute_value, |
12136 | "using decimal floating-point absolute value " |
12137 | "function %qD when argument is of integer type %qT" , |
12138 | fndecl, atype); |
12139 | else if (SCALAR_FLOAT_TYPE_P (atype)) |
12140 | warning_at (loc, OPT_Wabsolute_value, |
12141 | "using decimal floating-point absolute value " |
12142 | "function %qD when argument is of floating-point " |
12143 | "type %qT" , fndecl, atype); |
12144 | else if (TREE_CODE (atype) == COMPLEX_TYPE) |
12145 | warning_at (loc, OPT_Wabsolute_value, |
12146 | "using decimal floating-point absolute value " |
12147 | "function %qD when argument is of complex type %qT" , |
12148 | fndecl, atype); |
12149 | else |
12150 | gcc_unreachable (); |
12151 | return; |
12152 | } |
12153 | break; |
12154 | |
12155 | default: |
12156 | return; |
12157 | } |
12158 | |
12159 | if (!TYPE_ARG_TYPES (TREE_TYPE (fndecl))) |
12160 | return; |
12161 | |
12162 | tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); |
12163 | if (TREE_CODE (atype) == COMPLEX_TYPE) |
12164 | { |
12165 | gcc_assert (TREE_CODE (ftype) == COMPLEX_TYPE); |
12166 | atype = TREE_TYPE (atype); |
12167 | ftype = TREE_TYPE (ftype); |
12168 | } |
12169 | |
12170 | if (TYPE_PRECISION (ftype) < TYPE_PRECISION (atype)) |
12171 | warning_at (loc, OPT_Wabsolute_value, |
12172 | "absolute value function %qD given an argument of type %qT " |
12173 | "but has parameter of type %qT which may cause truncation " |
12174 | "of value" , fndecl, atype, ftype); |
12175 | } |
12176 | |
12177 | |
12178 | /* Parse a postfix expression after the initial primary or compound |
12179 | literal; that is, parse a series of postfix operators. |
12180 | |
12181 | EXPR_LOC is the location of the primary expression. */ |
12182 | |
12183 | static struct c_expr |
12184 | c_parser_postfix_expression_after_primary (c_parser *parser, |
12185 | location_t expr_loc, |
12186 | struct c_expr expr) |
12187 | { |
12188 | struct c_expr orig_expr; |
12189 | tree ident, idx; |
12190 | location_t sizeof_arg_loc[3], comp_loc; |
12191 | tree sizeof_arg[3]; |
12192 | unsigned int literal_zero_mask; |
12193 | unsigned int i; |
12194 | vec<tree, va_gc> *exprlist; |
12195 | vec<tree, va_gc> *origtypes = NULL; |
12196 | vec<location_t> arg_loc = vNULL; |
12197 | location_t start; |
12198 | location_t finish; |
12199 | |
12200 | while (true) |
12201 | { |
12202 | location_t op_loc = c_parser_peek_token (parser)->location; |
12203 | switch (c_parser_peek_token (parser)->type) |
12204 | { |
12205 | case CPP_OPEN_SQUARE: |
12206 | /* Array reference. */ |
12207 | c_parser_consume_token (parser); |
12208 | idx = c_parser_expression (parser).value; |
12209 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
12210 | msgid: "expected %<]%>" ); |
12211 | start = expr.get_start (); |
12212 | finish = parser->tokens_buf[0].location; |
12213 | expr.value = build_array_ref (op_loc, expr.value, idx); |
12214 | set_c_expr_source_range (expr: &expr, start, finish); |
12215 | expr.original_code = ERROR_MARK; |
12216 | expr.original_type = NULL; |
12217 | expr.m_decimal = 0; |
12218 | break; |
12219 | case CPP_OPEN_PAREN: |
12220 | /* Function call. */ |
12221 | { |
12222 | matching_parens parens; |
12223 | parens.consume_open (parser); |
12224 | for (i = 0; i < 3; i++) |
12225 | { |
12226 | sizeof_arg[i] = NULL_TREE; |
12227 | sizeof_arg_loc[i] = UNKNOWN_LOCATION; |
12228 | } |
12229 | literal_zero_mask = 0; |
12230 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
12231 | exprlist = NULL; |
12232 | else if (TREE_CODE (expr.value) == FUNCTION_DECL |
12233 | && fndecl_built_in_p (node: expr.value, name1: BUILT_IN_CLASSIFY_TYPE) |
12234 | && c_parser_next_tokens_start_typename (parser, |
12235 | la: cla_prefer_id)) |
12236 | { |
12237 | /* __builtin_classify_type (type) */ |
12238 | c_inhibit_evaluation_warnings++; |
12239 | in_alignof++; |
12240 | struct c_type_name *type = c_parser_type_name (parser); |
12241 | c_inhibit_evaluation_warnings--; |
12242 | in_alignof--; |
12243 | struct c_typespec ret; |
12244 | ret.expr = NULL_TREE; |
12245 | ret.spec = error_mark_node; |
12246 | ret.expr_const_operands = false; |
12247 | if (type != NULL) |
12248 | ret.spec = groktypename (type, &ret.expr, |
12249 | &ret.expr_const_operands); |
12250 | parens.skip_until_found_close (parser); |
12251 | expr.value = build_int_cst (integer_type_node, |
12252 | type_to_class (ret.spec)); |
12253 | break; |
12254 | } |
12255 | else |
12256 | exprlist = c_parser_expr_list (parser, true, false, &origtypes, |
12257 | sizeof_arg_loc, sizeof_arg, |
12258 | &arg_loc, &literal_zero_mask); |
12259 | parens.skip_until_found_close (parser); |
12260 | } |
12261 | orig_expr = expr; |
12262 | mark_exp_read (expr.value); |
12263 | if (warn_sizeof_pointer_memaccess) |
12264 | sizeof_pointer_memaccess_warning (sizeof_arg_loc, |
12265 | expr.value, exprlist, |
12266 | sizeof_arg, |
12267 | sizeof_ptr_memacc_comptypes); |
12268 | if (TREE_CODE (expr.value) == FUNCTION_DECL) |
12269 | { |
12270 | if (fndecl_built_in_p (node: expr.value, name1: BUILT_IN_MEMSET) |
12271 | && vec_safe_length (v: exprlist) == 3) |
12272 | { |
12273 | tree arg0 = (*exprlist)[0]; |
12274 | tree arg2 = (*exprlist)[2]; |
12275 | warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask); |
12276 | } |
12277 | if (warn_absolute_value |
12278 | && fndecl_built_in_p (node: expr.value, klass: BUILT_IN_NORMAL) |
12279 | && vec_safe_length (v: exprlist) == 1) |
12280 | warn_for_abs (loc: expr_loc, fndecl: expr.value, arg: (*exprlist)[0]); |
12281 | if (parser->omp_for_parse_state |
12282 | && parser->omp_for_parse_state->in_intervening_code |
12283 | && omp_runtime_api_call (fndecl: expr.value)) |
12284 | { |
12285 | error_at (expr_loc, "calls to the OpenMP runtime API are " |
12286 | "not permitted in intervening code" ); |
12287 | parser->omp_for_parse_state->fail = true; |
12288 | } |
12289 | } |
12290 | |
12291 | start = expr.get_start (); |
12292 | finish = parser->tokens_buf[0].get_finish (); |
12293 | expr.value |
12294 | = c_build_function_call_vec (expr_loc, arg_loc, expr.value, |
12295 | exprlist, origtypes); |
12296 | set_c_expr_source_range (expr: &expr, start, finish); |
12297 | expr.m_decimal = 0; |
12298 | |
12299 | expr.original_code = ERROR_MARK; |
12300 | if (TREE_CODE (expr.value) == INTEGER_CST |
12301 | && TREE_CODE (orig_expr.value) == FUNCTION_DECL |
12302 | && fndecl_built_in_p (node: orig_expr.value, name1: BUILT_IN_CONSTANT_P)) |
12303 | expr.original_code = C_MAYBE_CONST_EXPR; |
12304 | expr.original_type = NULL; |
12305 | if (exprlist) |
12306 | { |
12307 | release_tree_vector (exprlist); |
12308 | release_tree_vector (origtypes); |
12309 | } |
12310 | arg_loc.release (); |
12311 | break; |
12312 | case CPP_DOT: |
12313 | /* Structure element reference. */ |
12314 | c_parser_consume_token (parser); |
12315 | expr = default_function_array_conversion (expr_loc, expr); |
12316 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
12317 | { |
12318 | c_token *comp_tok = c_parser_peek_token (parser); |
12319 | ident = comp_tok->value; |
12320 | comp_loc = comp_tok->location; |
12321 | } |
12322 | else |
12323 | { |
12324 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12325 | expr.set_error (); |
12326 | expr.original_code = ERROR_MARK; |
12327 | expr.original_type = NULL; |
12328 | return expr; |
12329 | } |
12330 | start = expr.get_start (); |
12331 | finish = c_parser_peek_token (parser)->get_finish (); |
12332 | c_parser_consume_token (parser); |
12333 | expr.value = build_component_ref (op_loc, expr.value, ident, |
12334 | comp_loc, UNKNOWN_LOCATION); |
12335 | set_c_expr_source_range (expr: &expr, start, finish); |
12336 | expr.original_code = ERROR_MARK; |
12337 | if (TREE_CODE (expr.value) != COMPONENT_REF) |
12338 | expr.original_type = NULL; |
12339 | else |
12340 | { |
12341 | /* Remember the original type of a bitfield. */ |
12342 | tree field = TREE_OPERAND (expr.value, 1); |
12343 | if (TREE_CODE (field) != FIELD_DECL) |
12344 | expr.original_type = NULL; |
12345 | else |
12346 | expr.original_type = DECL_BIT_FIELD_TYPE (field); |
12347 | } |
12348 | expr.m_decimal = 0; |
12349 | break; |
12350 | case CPP_DEREF: |
12351 | /* Structure element reference. */ |
12352 | c_parser_consume_token (parser); |
12353 | expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false); |
12354 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
12355 | { |
12356 | c_token *comp_tok = c_parser_peek_token (parser); |
12357 | ident = comp_tok->value; |
12358 | comp_loc = comp_tok->location; |
12359 | } |
12360 | else |
12361 | { |
12362 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12363 | expr.set_error (); |
12364 | expr.original_code = ERROR_MARK; |
12365 | expr.original_type = NULL; |
12366 | return expr; |
12367 | } |
12368 | start = expr.get_start (); |
12369 | finish = c_parser_peek_token (parser)->get_finish (); |
12370 | c_parser_consume_token (parser); |
12371 | expr.value = build_component_ref (op_loc, |
12372 | build_indirect_ref (op_loc, |
12373 | expr.value, |
12374 | RO_ARROW), |
12375 | ident, comp_loc, |
12376 | expr.get_location ()); |
12377 | set_c_expr_source_range (expr: &expr, start, finish); |
12378 | expr.original_code = ERROR_MARK; |
12379 | if (TREE_CODE (expr.value) != COMPONENT_REF) |
12380 | expr.original_type = NULL; |
12381 | else |
12382 | { |
12383 | /* Remember the original type of a bitfield. */ |
12384 | tree field = TREE_OPERAND (expr.value, 1); |
12385 | if (TREE_CODE (field) != FIELD_DECL) |
12386 | expr.original_type = NULL; |
12387 | else |
12388 | expr.original_type = DECL_BIT_FIELD_TYPE (field); |
12389 | } |
12390 | expr.m_decimal = 0; |
12391 | break; |
12392 | case CPP_PLUS_PLUS: |
12393 | /* Postincrement. */ |
12394 | start = expr.get_start (); |
12395 | finish = c_parser_peek_token (parser)->get_finish (); |
12396 | c_parser_consume_token (parser); |
12397 | expr = default_function_array_read_conversion (expr_loc, expr); |
12398 | expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, |
12399 | expr.value, false); |
12400 | set_c_expr_source_range (expr: &expr, start, finish); |
12401 | expr.original_code = ERROR_MARK; |
12402 | expr.original_type = NULL; |
12403 | break; |
12404 | case CPP_MINUS_MINUS: |
12405 | /* Postdecrement. */ |
12406 | start = expr.get_start (); |
12407 | finish = c_parser_peek_token (parser)->get_finish (); |
12408 | c_parser_consume_token (parser); |
12409 | expr = default_function_array_read_conversion (expr_loc, expr); |
12410 | expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, |
12411 | expr.value, false); |
12412 | set_c_expr_source_range (expr: &expr, start, finish); |
12413 | expr.original_code = ERROR_MARK; |
12414 | expr.original_type = NULL; |
12415 | break; |
12416 | default: |
12417 | return expr; |
12418 | } |
12419 | } |
12420 | } |
12421 | |
12422 | /* Parse an expression (C90 6.3.17, C99 6.5.17, C11 6.5.17). |
12423 | |
12424 | expression: |
12425 | assignment-expression |
12426 | expression , assignment-expression |
12427 | */ |
12428 | |
12429 | static struct c_expr |
12430 | c_parser_expression (c_parser *parser) |
12431 | { |
12432 | location_t tloc = c_parser_peek_token (parser)->location; |
12433 | struct c_expr expr; |
12434 | expr = c_parser_expr_no_commas (parser, NULL); |
12435 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12436 | expr = convert_lvalue_to_rvalue (tloc, expr, true, false); |
12437 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12438 | { |
12439 | struct c_expr next; |
12440 | tree lhsval; |
12441 | location_t loc = c_parser_peek_token (parser)->location; |
12442 | location_t expr_loc; |
12443 | c_parser_consume_token (parser); |
12444 | expr_loc = c_parser_peek_token (parser)->location; |
12445 | lhsval = expr.value; |
12446 | while (TREE_CODE (lhsval) == COMPOUND_EXPR |
12447 | || TREE_CODE (lhsval) == NOP_EXPR) |
12448 | { |
12449 | if (TREE_CODE (lhsval) == COMPOUND_EXPR) |
12450 | lhsval = TREE_OPERAND (lhsval, 1); |
12451 | else |
12452 | lhsval = TREE_OPERAND (lhsval, 0); |
12453 | } |
12454 | if (DECL_P (lhsval) || handled_component_p (t: lhsval)) |
12455 | mark_exp_read (lhsval); |
12456 | next = c_parser_expr_no_commas (parser, NULL); |
12457 | next = convert_lvalue_to_rvalue (expr_loc, next, true, false); |
12458 | expr.value = build_compound_expr (loc, expr.value, next.value); |
12459 | expr.original_code = COMPOUND_EXPR; |
12460 | expr.original_type = next.original_type; |
12461 | expr.m_decimal = 0; |
12462 | } |
12463 | return expr; |
12464 | } |
12465 | |
12466 | /* Parse an expression and convert functions or arrays to pointers and |
12467 | lvalues to rvalues. */ |
12468 | |
12469 | static struct c_expr |
12470 | c_parser_expression_conv (c_parser *parser) |
12471 | { |
12472 | struct c_expr expr; |
12473 | location_t loc = c_parser_peek_token (parser)->location; |
12474 | expr = c_parser_expression (parser); |
12475 | expr = convert_lvalue_to_rvalue (loc, expr, true, false); |
12476 | return expr; |
12477 | } |
12478 | |
12479 | /* Helper function of c_parser_expr_list. Check if IDXth (0 based) |
12480 | argument is a literal zero alone and if so, set it in literal_zero_mask. */ |
12481 | |
12482 | static inline void |
12483 | c_parser_check_literal_zero (c_parser *parser, unsigned *literal_zero_mask, |
12484 | unsigned int idx) |
12485 | { |
12486 | if (idx >= HOST_BITS_PER_INT) |
12487 | return; |
12488 | |
12489 | c_token *tok = c_parser_peek_token (parser); |
12490 | switch (tok->type) |
12491 | { |
12492 | case CPP_NUMBER: |
12493 | case CPP_CHAR: |
12494 | case CPP_WCHAR: |
12495 | case CPP_CHAR16: |
12496 | case CPP_CHAR32: |
12497 | case CPP_UTF8CHAR: |
12498 | /* If a parameter is literal zero alone, remember it |
12499 | for -Wmemset-transposed-args warning. */ |
12500 | if (integer_zerop (tok->value) |
12501 | && !TREE_OVERFLOW (tok->value) |
12502 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
12503 | || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) |
12504 | *literal_zero_mask |= 1U << idx; |
12505 | default: |
12506 | break; |
12507 | } |
12508 | } |
12509 | |
12510 | /* Parse a non-empty list of expressions. If CONVERT_P, convert |
12511 | functions and arrays to pointers and lvalues to rvalues. If |
12512 | FOLD_P, fold the expressions. If LOCATIONS is non-NULL, save the |
12513 | locations of function arguments into this vector. |
12514 | |
12515 | nonempty-expr-list: |
12516 | assignment-expression |
12517 | nonempty-expr-list , assignment-expression |
12518 | */ |
12519 | |
12520 | static vec<tree, va_gc> * |
12521 | c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, |
12522 | vec<tree, va_gc> **p_orig_types, |
12523 | location_t *sizeof_arg_loc, tree *sizeof_arg, |
12524 | vec<location_t> *locations, |
12525 | unsigned int *literal_zero_mask) |
12526 | { |
12527 | vec<tree, va_gc> *ret; |
12528 | vec<tree, va_gc> *orig_types; |
12529 | struct c_expr expr; |
12530 | unsigned int idx = 0; |
12531 | |
12532 | ret = make_tree_vector (); |
12533 | if (p_orig_types == NULL) |
12534 | orig_types = NULL; |
12535 | else |
12536 | orig_types = make_tree_vector (); |
12537 | |
12538 | if (literal_zero_mask) |
12539 | c_parser_check_literal_zero (parser, literal_zero_mask, idx: 0); |
12540 | expr = c_parser_expr_no_commas (parser, NULL); |
12541 | if (convert_p) |
12542 | expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, true); |
12543 | if (fold_p) |
12544 | expr.value = c_fully_fold (expr.value, false, NULL); |
12545 | ret->quick_push (obj: expr.value); |
12546 | if (orig_types) |
12547 | orig_types->quick_push (obj: expr.original_type); |
12548 | if (locations) |
12549 | locations->safe_push (obj: expr.get_location ()); |
12550 | if (sizeof_arg != NULL |
12551 | && (expr.original_code == SIZEOF_EXPR |
12552 | || expr.original_code == PAREN_SIZEOF_EXPR)) |
12553 | { |
12554 | sizeof_arg[0] = c_last_sizeof_arg; |
12555 | sizeof_arg_loc[0] = c_last_sizeof_loc; |
12556 | } |
12557 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12558 | { |
12559 | c_parser_consume_token (parser); |
12560 | if (literal_zero_mask) |
12561 | c_parser_check_literal_zero (parser, literal_zero_mask, idx: idx + 1); |
12562 | expr = c_parser_expr_no_commas (parser, NULL); |
12563 | if (convert_p) |
12564 | expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, |
12565 | true); |
12566 | if (fold_p) |
12567 | expr.value = c_fully_fold (expr.value, false, NULL); |
12568 | vec_safe_push (v&: ret, obj: expr.value); |
12569 | if (orig_types) |
12570 | vec_safe_push (v&: orig_types, obj: expr.original_type); |
12571 | if (locations) |
12572 | locations->safe_push (obj: expr.get_location ()); |
12573 | if (++idx < 3 |
12574 | && sizeof_arg != NULL |
12575 | && (expr.original_code == SIZEOF_EXPR |
12576 | || expr.original_code == PAREN_SIZEOF_EXPR)) |
12577 | { |
12578 | sizeof_arg[idx] = c_last_sizeof_arg; |
12579 | sizeof_arg_loc[idx] = c_last_sizeof_loc; |
12580 | } |
12581 | } |
12582 | if (orig_types) |
12583 | *p_orig_types = orig_types; |
12584 | return ret; |
12585 | } |
12586 | |
12587 | /* Parse Objective-C-specific constructs. */ |
12588 | |
12589 | /* Parse an objc-class-definition. |
12590 | |
12591 | objc-class-definition: |
12592 | @interface identifier objc-superclass[opt] objc-protocol-refs[opt] |
12593 | objc-class-instance-variables[opt] objc-methodprotolist @end |
12594 | @implementation identifier objc-superclass[opt] |
12595 | objc-class-instance-variables[opt] |
12596 | @interface identifier ( identifier ) objc-protocol-refs[opt] |
12597 | objc-methodprotolist @end |
12598 | @interface identifier ( ) objc-protocol-refs[opt] |
12599 | objc-methodprotolist @end |
12600 | @implementation identifier ( identifier ) |
12601 | |
12602 | objc-superclass: |
12603 | : identifier |
12604 | |
12605 | "@interface identifier (" must start "@interface identifier ( |
12606 | identifier ) ...": objc-methodprotolist in the first production may |
12607 | not start with a parenthesized identifier as a declarator of a data |
12608 | definition with no declaration specifiers if the objc-superclass, |
12609 | objc-protocol-refs and objc-class-instance-variables are omitted. */ |
12610 | |
12611 | static void |
12612 | c_parser_objc_class_definition (c_parser *parser, tree attributes) |
12613 | { |
12614 | bool iface_p; |
12615 | tree id1; |
12616 | tree superclass; |
12617 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_INTERFACE)) |
12618 | iface_p = true; |
12619 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_IMPLEMENTATION)) |
12620 | iface_p = false; |
12621 | else |
12622 | gcc_unreachable (); |
12623 | |
12624 | c_parser_consume_token (parser); |
12625 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12626 | { |
12627 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12628 | return; |
12629 | } |
12630 | id1 = c_parser_peek_token (parser)->value; |
12631 | location_t loc1 = c_parser_peek_token (parser)->location; |
12632 | c_parser_consume_token (parser); |
12633 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
12634 | { |
12635 | /* We have a category or class extension. */ |
12636 | tree id2; |
12637 | tree proto = NULL_TREE; |
12638 | matching_parens parens; |
12639 | parens.consume_open (parser); |
12640 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12641 | { |
12642 | if (iface_p && c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
12643 | { |
12644 | /* We have a class extension. */ |
12645 | id2 = NULL_TREE; |
12646 | } |
12647 | else |
12648 | { |
12649 | c_parser_error (parser, gmsgid: "expected identifier or %<)%>" ); |
12650 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
12651 | return; |
12652 | } |
12653 | } |
12654 | else |
12655 | { |
12656 | id2 = c_parser_peek_token (parser)->value; |
12657 | c_parser_consume_token (parser); |
12658 | } |
12659 | parens.skip_until_found_close (parser); |
12660 | if (!iface_p) |
12661 | { |
12662 | objc_start_category_implementation (id1, id2); |
12663 | return; |
12664 | } |
12665 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
12666 | proto = c_parser_objc_protocol_refs (parser); |
12667 | objc_start_category_interface (id1, id2, proto, attributes); |
12668 | c_parser_objc_methodprotolist (parser); |
12669 | c_parser_require_keyword (parser, keyword: RID_AT_END, msgid: "expected %<@end%>" ); |
12670 | objc_finish_interface (); |
12671 | return; |
12672 | } |
12673 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
12674 | { |
12675 | c_parser_consume_token (parser); |
12676 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12677 | { |
12678 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12679 | return; |
12680 | } |
12681 | superclass = c_parser_peek_token (parser)->value; |
12682 | c_parser_consume_token (parser); |
12683 | } |
12684 | else |
12685 | superclass = NULL_TREE; |
12686 | if (iface_p) |
12687 | { |
12688 | tree proto = NULL_TREE; |
12689 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
12690 | proto = c_parser_objc_protocol_refs (parser); |
12691 | objc_start_class_interface (id1, loc1, superclass, proto, attributes); |
12692 | } |
12693 | else |
12694 | objc_start_class_implementation (id1, superclass); |
12695 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
12696 | c_parser_objc_class_instance_variables (parser); |
12697 | if (iface_p) |
12698 | { |
12699 | objc_continue_interface (); |
12700 | c_parser_objc_methodprotolist (parser); |
12701 | c_parser_require_keyword (parser, keyword: RID_AT_END, msgid: "expected %<@end%>" ); |
12702 | objc_finish_interface (); |
12703 | } |
12704 | else |
12705 | { |
12706 | objc_continue_implementation (); |
12707 | return; |
12708 | } |
12709 | } |
12710 | |
12711 | /* Parse objc-class-instance-variables. |
12712 | |
12713 | objc-class-instance-variables: |
12714 | { objc-instance-variable-decl-list[opt] } |
12715 | |
12716 | objc-instance-variable-decl-list: |
12717 | objc-visibility-spec |
12718 | objc-instance-variable-decl ; |
12719 | ; |
12720 | objc-instance-variable-decl-list objc-visibility-spec |
12721 | objc-instance-variable-decl-list objc-instance-variable-decl ; |
12722 | objc-instance-variable-decl-list ; |
12723 | |
12724 | objc-visibility-spec: |
12725 | @private |
12726 | @protected |
12727 | @public |
12728 | |
12729 | objc-instance-variable-decl: |
12730 | struct-declaration |
12731 | */ |
12732 | |
12733 | static void |
12734 | c_parser_objc_class_instance_variables (c_parser *parser) |
12735 | { |
12736 | gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); |
12737 | c_parser_consume_token (parser); |
12738 | while (c_parser_next_token_is_not (parser, type: CPP_EOF)) |
12739 | { |
12740 | tree decls; |
12741 | /* Parse any stray semicolon. */ |
12742 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
12743 | { |
12744 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
12745 | "extra semicolon" ); |
12746 | c_parser_consume_token (parser); |
12747 | continue; |
12748 | } |
12749 | /* Stop if at the end of the instance variables. */ |
12750 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
12751 | { |
12752 | c_parser_consume_token (parser); |
12753 | break; |
12754 | } |
12755 | /* Parse any objc-visibility-spec. */ |
12756 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PRIVATE)) |
12757 | { |
12758 | c_parser_consume_token (parser); |
12759 | objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); |
12760 | continue; |
12761 | } |
12762 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PROTECTED)) |
12763 | { |
12764 | c_parser_consume_token (parser); |
12765 | objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); |
12766 | continue; |
12767 | } |
12768 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PUBLIC)) |
12769 | { |
12770 | c_parser_consume_token (parser); |
12771 | objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); |
12772 | continue; |
12773 | } |
12774 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PACKAGE)) |
12775 | { |
12776 | c_parser_consume_token (parser); |
12777 | objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); |
12778 | continue; |
12779 | } |
12780 | else if (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
12781 | { |
12782 | c_parser_pragma (parser, pragma_external, NULL); |
12783 | continue; |
12784 | } |
12785 | |
12786 | /* Parse some comma-separated declarations. */ |
12787 | decls = c_parser_struct_declaration (parser, NULL); |
12788 | if (decls == NULL) |
12789 | { |
12790 | /* There is a syntax error. We want to skip the offending |
12791 | tokens up to the next ';' (included) or '}' |
12792 | (excluded). */ |
12793 | |
12794 | /* First, skip manually a ')' or ']'. This is because they |
12795 | reduce the nesting level, so c_parser_skip_until_found() |
12796 | wouldn't be able to skip past them. */ |
12797 | c_token *token = c_parser_peek_token (parser); |
12798 | if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) |
12799 | c_parser_consume_token (parser); |
12800 | |
12801 | /* Then, do the standard skipping. */ |
12802 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
12803 | |
12804 | /* We hopefully recovered. Start normal parsing again. */ |
12805 | parser->error = false; |
12806 | continue; |
12807 | } |
12808 | else |
12809 | { |
12810 | /* Comma-separated instance variables are chained together |
12811 | in reverse order; add them one by one. */ |
12812 | tree ivar = nreverse (decls); |
12813 | for (; ivar; ivar = DECL_CHAIN (ivar)) |
12814 | objc_add_instance_variable (copy_node (ivar)); |
12815 | } |
12816 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
12817 | } |
12818 | } |
12819 | |
12820 | /* Parse an objc-class-declaration. |
12821 | |
12822 | objc-class-declaration: |
12823 | @class identifier-list ; |
12824 | */ |
12825 | |
12826 | static void |
12827 | c_parser_objc_class_declaration (c_parser *parser) |
12828 | { |
12829 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); |
12830 | c_parser_consume_token (parser); |
12831 | /* Any identifiers, including those declared as type names, are OK |
12832 | here. */ |
12833 | while (true) |
12834 | { |
12835 | tree id; |
12836 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12837 | { |
12838 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12839 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
12840 | parser->error = false; |
12841 | return; |
12842 | } |
12843 | id = c_parser_peek_token (parser)->value; |
12844 | objc_declare_class (id); |
12845 | c_parser_consume_token (parser); |
12846 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12847 | c_parser_consume_token (parser); |
12848 | else |
12849 | break; |
12850 | } |
12851 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
12852 | } |
12853 | |
12854 | /* Parse an objc-alias-declaration. |
12855 | |
12856 | objc-alias-declaration: |
12857 | @compatibility_alias identifier identifier ; |
12858 | */ |
12859 | |
12860 | static void |
12861 | c_parser_objc_alias_declaration (c_parser *parser) |
12862 | { |
12863 | tree id1, id2; |
12864 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); |
12865 | c_parser_consume_token (parser); |
12866 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12867 | { |
12868 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12869 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
12870 | return; |
12871 | } |
12872 | id1 = c_parser_peek_token (parser)->value; |
12873 | c_parser_consume_token (parser); |
12874 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12875 | { |
12876 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12877 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
12878 | return; |
12879 | } |
12880 | id2 = c_parser_peek_token (parser)->value; |
12881 | c_parser_consume_token (parser); |
12882 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
12883 | objc_declare_alias (id1, id2); |
12884 | } |
12885 | |
12886 | /* Parse an objc-protocol-definition. |
12887 | |
12888 | objc-protocol-definition: |
12889 | @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end |
12890 | @protocol identifier-list ; |
12891 | |
12892 | "@protocol identifier ;" should be resolved as "@protocol |
12893 | identifier-list ;": objc-methodprotolist may not start with a |
12894 | semicolon in the first alternative if objc-protocol-refs are |
12895 | omitted. */ |
12896 | |
12897 | static void |
12898 | c_parser_objc_protocol_definition (c_parser *parser, tree attributes) |
12899 | { |
12900 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); |
12901 | |
12902 | c_parser_consume_token (parser); |
12903 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12904 | { |
12905 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12906 | return; |
12907 | } |
12908 | if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
12909 | || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) |
12910 | { |
12911 | /* Any identifiers, including those declared as type names, are |
12912 | OK here. */ |
12913 | while (true) |
12914 | { |
12915 | tree id; |
12916 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12917 | { |
12918 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12919 | break; |
12920 | } |
12921 | id = c_parser_peek_token (parser)->value; |
12922 | objc_declare_protocol (id, attributes); |
12923 | c_parser_consume_token (parser); |
12924 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12925 | c_parser_consume_token (parser); |
12926 | else |
12927 | break; |
12928 | } |
12929 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
12930 | } |
12931 | else |
12932 | { |
12933 | tree id = c_parser_peek_token (parser)->value; |
12934 | tree proto = NULL_TREE; |
12935 | c_parser_consume_token (parser); |
12936 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
12937 | proto = c_parser_objc_protocol_refs (parser); |
12938 | parser->objc_pq_context = true; |
12939 | objc_start_protocol (id, proto, attributes); |
12940 | c_parser_objc_methodprotolist (parser); |
12941 | c_parser_require_keyword (parser, keyword: RID_AT_END, msgid: "expected %<@end%>" ); |
12942 | parser->objc_pq_context = false; |
12943 | objc_finish_interface (); |
12944 | } |
12945 | } |
12946 | |
12947 | /* Parse an objc-method-type. |
12948 | |
12949 | objc-method-type: |
12950 | + |
12951 | - |
12952 | |
12953 | Return true if it is a class method (+) and false if it is |
12954 | an instance method (-). |
12955 | */ |
12956 | static inline bool |
12957 | c_parser_objc_method_type (c_parser *parser) |
12958 | { |
12959 | switch (c_parser_peek_token (parser)->type) |
12960 | { |
12961 | case CPP_PLUS: |
12962 | c_parser_consume_token (parser); |
12963 | return true; |
12964 | case CPP_MINUS: |
12965 | c_parser_consume_token (parser); |
12966 | return false; |
12967 | default: |
12968 | gcc_unreachable (); |
12969 | } |
12970 | } |
12971 | |
12972 | /* Parse an objc-method-definition. |
12973 | |
12974 | objc-method-definition: |
12975 | objc-method-type objc-method-decl ;[opt] compound-statement |
12976 | */ |
12977 | |
12978 | static void |
12979 | c_parser_objc_method_definition (c_parser *parser) |
12980 | { |
12981 | bool is_class_method = c_parser_objc_method_type (parser); |
12982 | tree decl, attributes = NULL_TREE, expr = NULL_TREE; |
12983 | parser->objc_pq_context = true; |
12984 | decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, |
12985 | &expr); |
12986 | if (decl == error_mark_node) |
12987 | return; /* Bail here. */ |
12988 | |
12989 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
12990 | { |
12991 | c_parser_consume_token (parser); |
12992 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
12993 | "extra semicolon in method definition specified" ); |
12994 | } |
12995 | |
12996 | if (!c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
12997 | { |
12998 | c_parser_error (parser, gmsgid: "expected %<{%>" ); |
12999 | return; |
13000 | } |
13001 | |
13002 | parser->objc_pq_context = false; |
13003 | if (objc_start_method_definition (is_class_method, decl, attributes, expr)) |
13004 | { |
13005 | add_stmt (c_parser_compound_statement (parser)); |
13006 | objc_finish_method_definition (current_function_decl); |
13007 | } |
13008 | else |
13009 | { |
13010 | /* This code is executed when we find a method definition |
13011 | outside of an @implementation context (or invalid for other |
13012 | reasons). Parse the method (to keep going) but do not emit |
13013 | any code. |
13014 | */ |
13015 | c_parser_compound_statement (parser); |
13016 | } |
13017 | } |
13018 | |
13019 | /* Parse an objc-methodprotolist. |
13020 | |
13021 | objc-methodprotolist: |
13022 | empty |
13023 | objc-methodprotolist objc-methodproto |
13024 | objc-methodprotolist declaration |
13025 | objc-methodprotolist ; |
13026 | @optional |
13027 | @required |
13028 | |
13029 | The declaration is a data definition, which may be missing |
13030 | declaration specifiers under the same rules and diagnostics as |
13031 | other data definitions outside functions, and the stray semicolon |
13032 | is diagnosed the same way as a stray semicolon outside a |
13033 | function. */ |
13034 | |
13035 | static void |
13036 | c_parser_objc_methodprotolist (c_parser *parser) |
13037 | { |
13038 | while (true) |
13039 | { |
13040 | /* The list is terminated by @end. */ |
13041 | switch (c_parser_peek_token (parser)->type) |
13042 | { |
13043 | case CPP_SEMICOLON: |
13044 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
13045 | "ISO C does not allow extra %<;%> outside of a function" ); |
13046 | c_parser_consume_token (parser); |
13047 | break; |
13048 | case CPP_PLUS: |
13049 | case CPP_MINUS: |
13050 | c_parser_objc_methodproto (parser); |
13051 | break; |
13052 | case CPP_PRAGMA: |
13053 | c_parser_pragma (parser, pragma_external, NULL); |
13054 | break; |
13055 | case CPP_EOF: |
13056 | return; |
13057 | default: |
13058 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_END)) |
13059 | return; |
13060 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PROPERTY)) |
13061 | c_parser_objc_at_property_declaration (parser); |
13062 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_OPTIONAL)) |
13063 | { |
13064 | objc_set_method_opt (true); |
13065 | c_parser_consume_token (parser); |
13066 | } |
13067 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_REQUIRED)) |
13068 | { |
13069 | objc_set_method_opt (false); |
13070 | c_parser_consume_token (parser); |
13071 | } |
13072 | else |
13073 | c_parser_declaration_or_fndef (parser, fndef_ok: false, static_assert_ok: false, empty_ok: true, |
13074 | nested: false, start_attr_ok: true); |
13075 | break; |
13076 | } |
13077 | } |
13078 | } |
13079 | |
13080 | /* Parse an objc-methodproto. |
13081 | |
13082 | objc-methodproto: |
13083 | objc-method-type objc-method-decl ; |
13084 | */ |
13085 | |
13086 | static void |
13087 | c_parser_objc_methodproto (c_parser *parser) |
13088 | { |
13089 | bool is_class_method = c_parser_objc_method_type (parser); |
13090 | tree decl, attributes = NULL_TREE; |
13091 | |
13092 | /* Remember protocol qualifiers in prototypes. */ |
13093 | parser->objc_pq_context = true; |
13094 | decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, |
13095 | NULL); |
13096 | /* Forget protocol qualifiers now. */ |
13097 | parser->objc_pq_context = false; |
13098 | |
13099 | /* Do not allow the presence of attributes to hide an erroneous |
13100 | method implementation in the interface section. */ |
13101 | if (!c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
13102 | { |
13103 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
13104 | return; |
13105 | } |
13106 | |
13107 | if (decl != error_mark_node) |
13108 | objc_add_method_declaration (is_class_method, decl, attributes); |
13109 | |
13110 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13111 | } |
13112 | |
13113 | /* If we are at a position that method attributes may be present, check that |
13114 | there are not any parsed already (a syntax error) and then collect any |
13115 | specified at the current location. Finally, if new attributes were present, |
13116 | check that the next token is legal ( ';' for decls and '{' for defs). */ |
13117 | |
13118 | static bool |
13119 | c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) |
13120 | { |
13121 | bool bad = false; |
13122 | if (*attributes) |
13123 | { |
13124 | c_parser_error (parser, |
13125 | gmsgid: "method attributes must be specified at the end only" ); |
13126 | *attributes = NULL_TREE; |
13127 | bad = true; |
13128 | } |
13129 | |
13130 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
13131 | *attributes = c_parser_gnu_attributes (parser); |
13132 | |
13133 | /* If there were no attributes here, just report any earlier error. */ |
13134 | if (*attributes == NULL_TREE || bad) |
13135 | return bad; |
13136 | |
13137 | /* If the attributes are followed by a ; or {, then just report any earlier |
13138 | error. */ |
13139 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
13140 | || c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
13141 | return bad; |
13142 | |
13143 | /* We've got attributes, but not at the end. */ |
13144 | c_parser_error (parser, |
13145 | gmsgid: "expected %<;%> or %<{%> after method attribute definition" ); |
13146 | return true; |
13147 | } |
13148 | |
13149 | /* Parse an objc-method-decl. |
13150 | |
13151 | objc-method-decl: |
13152 | ( objc-type-name ) objc-selector |
13153 | objc-selector |
13154 | ( objc-type-name ) objc-keyword-selector objc-optparmlist |
13155 | objc-keyword-selector objc-optparmlist |
13156 | gnu-attributes |
13157 | |
13158 | objc-keyword-selector: |
13159 | objc-keyword-decl |
13160 | objc-keyword-selector objc-keyword-decl |
13161 | |
13162 | objc-keyword-decl: |
13163 | objc-selector : ( objc-type-name ) identifier |
13164 | objc-selector : identifier |
13165 | : ( objc-type-name ) identifier |
13166 | : identifier |
13167 | |
13168 | objc-optparmlist: |
13169 | objc-optparms objc-optellipsis |
13170 | |
13171 | objc-optparms: |
13172 | empty |
13173 | objc-opt-parms , parameter-declaration |
13174 | |
13175 | objc-optellipsis: |
13176 | empty |
13177 | , ... |
13178 | */ |
13179 | |
13180 | static tree |
13181 | c_parser_objc_method_decl (c_parser *parser, bool is_class_method, |
13182 | tree *attributes, tree *expr) |
13183 | { |
13184 | tree type = NULL_TREE; |
13185 | tree sel; |
13186 | tree parms = NULL_TREE; |
13187 | bool ellipsis = false; |
13188 | bool attr_err = false; |
13189 | |
13190 | *attributes = NULL_TREE; |
13191 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
13192 | { |
13193 | matching_parens parens; |
13194 | parens.consume_open (parser); |
13195 | type = c_parser_objc_type_name (parser); |
13196 | parens.skip_until_found_close (parser); |
13197 | } |
13198 | sel = c_parser_objc_selector (parser); |
13199 | /* If there is no selector, or a colon follows, we have an |
13200 | objc-keyword-selector. If there is a selector, and a colon does |
13201 | not follow, that selector ends the objc-method-decl. */ |
13202 | if (!sel || c_parser_next_token_is (parser, type: CPP_COLON)) |
13203 | { |
13204 | tree tsel = sel; |
13205 | tree list = NULL_TREE; |
13206 | while (true) |
13207 | { |
13208 | tree atype = NULL_TREE, id, keyworddecl; |
13209 | tree param_attr = NULL_TREE; |
13210 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
13211 | break; |
13212 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
13213 | { |
13214 | c_parser_consume_token (parser); |
13215 | atype = c_parser_objc_type_name (parser); |
13216 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
13217 | msgid: "expected %<)%>" ); |
13218 | } |
13219 | /* New ObjC allows attributes on method parameters. */ |
13220 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
13221 | param_attr = c_parser_gnu_attributes (parser); |
13222 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13223 | { |
13224 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13225 | return error_mark_node; |
13226 | } |
13227 | id = c_parser_peek_token (parser)->value; |
13228 | c_parser_consume_token (parser); |
13229 | keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); |
13230 | list = chainon (list, keyworddecl); |
13231 | tsel = c_parser_objc_selector (parser); |
13232 | if (!tsel && c_parser_next_token_is_not (parser, type: CPP_COLON)) |
13233 | break; |
13234 | } |
13235 | |
13236 | attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; |
13237 | |
13238 | /* Parse the optional parameter list. Optional Objective-C |
13239 | method parameters follow the C syntax, and may include '...' |
13240 | to denote a variable number of arguments. */ |
13241 | parms = make_node (TREE_LIST); |
13242 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13243 | { |
13244 | struct c_parm *parm; |
13245 | c_parser_consume_token (parser); |
13246 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
13247 | { |
13248 | ellipsis = true; |
13249 | c_parser_consume_token (parser); |
13250 | attr_err |= c_parser_objc_maybe_method_attributes |
13251 | (parser, attributes) ; |
13252 | break; |
13253 | } |
13254 | parm = c_parser_parameter_declaration (parser, NULL_TREE, have_gnu_attrs: false); |
13255 | if (parm == NULL) |
13256 | break; |
13257 | parms = chainon (parms, |
13258 | build_tree_list (NULL_TREE, grokparm (parm, expr))); |
13259 | } |
13260 | sel = list; |
13261 | } |
13262 | else |
13263 | attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; |
13264 | |
13265 | if (sel == NULL) |
13266 | { |
13267 | c_parser_error (parser, gmsgid: "objective-c method declaration is expected" ); |
13268 | return error_mark_node; |
13269 | } |
13270 | |
13271 | if (attr_err) |
13272 | return error_mark_node; |
13273 | |
13274 | return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); |
13275 | } |
13276 | |
13277 | /* Parse an objc-type-name. |
13278 | |
13279 | objc-type-name: |
13280 | objc-type-qualifiers[opt] type-name |
13281 | objc-type-qualifiers[opt] |
13282 | |
13283 | objc-type-qualifiers: |
13284 | objc-type-qualifier |
13285 | objc-type-qualifiers objc-type-qualifier |
13286 | |
13287 | objc-type-qualifier: one of |
13288 | in out inout bycopy byref oneway |
13289 | */ |
13290 | |
13291 | static tree |
13292 | c_parser_objc_type_name (c_parser *parser) |
13293 | { |
13294 | tree quals = NULL_TREE; |
13295 | struct c_type_name *type_name = NULL; |
13296 | tree type = NULL_TREE; |
13297 | while (true) |
13298 | { |
13299 | c_token *token = c_parser_peek_token (parser); |
13300 | if (token->type == CPP_KEYWORD |
13301 | && (token->keyword == RID_IN |
13302 | || token->keyword == RID_OUT |
13303 | || token->keyword == RID_INOUT |
13304 | || token->keyword == RID_BYCOPY |
13305 | || token->keyword == RID_BYREF |
13306 | || token->keyword == RID_ONEWAY)) |
13307 | { |
13308 | quals = chainon (build_tree_list (NULL_TREE, token->value), quals); |
13309 | c_parser_consume_token (parser); |
13310 | } |
13311 | else |
13312 | break; |
13313 | } |
13314 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_type)) |
13315 | type_name = c_parser_type_name (parser); |
13316 | if (type_name) |
13317 | type = groktypename (type_name, NULL, NULL); |
13318 | |
13319 | /* If the type is unknown, and error has already been produced and |
13320 | we need to recover from the error. In that case, use NULL_TREE |
13321 | for the type, as if no type had been specified; this will use the |
13322 | default type ('id') which is good for error recovery. */ |
13323 | if (type == error_mark_node) |
13324 | type = NULL_TREE; |
13325 | |
13326 | return build_tree_list (quals, type); |
13327 | } |
13328 | |
13329 | /* Parse objc-protocol-refs. |
13330 | |
13331 | objc-protocol-refs: |
13332 | < identifier-list > |
13333 | */ |
13334 | |
13335 | static tree |
13336 | c_parser_objc_protocol_refs (c_parser *parser) |
13337 | { |
13338 | tree list = NULL_TREE; |
13339 | gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); |
13340 | c_parser_consume_token (parser); |
13341 | /* Any identifiers, including those declared as type names, are OK |
13342 | here. */ |
13343 | while (true) |
13344 | { |
13345 | tree id; |
13346 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13347 | { |
13348 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13349 | break; |
13350 | } |
13351 | id = c_parser_peek_token (parser)->value; |
13352 | list = chainon (list, build_tree_list (NULL_TREE, id)); |
13353 | c_parser_consume_token (parser); |
13354 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13355 | c_parser_consume_token (parser); |
13356 | else |
13357 | break; |
13358 | } |
13359 | c_parser_require (parser, type: CPP_GREATER, msgid: "expected %<>%>" ); |
13360 | return list; |
13361 | } |
13362 | |
13363 | /* Parse an objc-try-catch-finally-statement. |
13364 | |
13365 | objc-try-catch-finally-statement: |
13366 | @try compound-statement objc-catch-list[opt] |
13367 | @try compound-statement objc-catch-list[opt] @finally compound-statement |
13368 | |
13369 | objc-catch-list: |
13370 | @catch ( objc-catch-parameter-declaration ) compound-statement |
13371 | objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement |
13372 | |
13373 | objc-catch-parameter-declaration: |
13374 | parameter-declaration |
13375 | '...' |
13376 | |
13377 | where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS. |
13378 | |
13379 | PS: This function is identical to cp_parser_objc_try_catch_finally_statement |
13380 | for C++. Keep them in sync. */ |
13381 | |
13382 | static void |
13383 | c_parser_objc_try_catch_finally_statement (c_parser *parser) |
13384 | { |
13385 | location_t location; |
13386 | tree stmt; |
13387 | |
13388 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); |
13389 | c_parser_consume_token (parser); |
13390 | location = c_parser_peek_token (parser)->location; |
13391 | objc_maybe_warn_exceptions (location); |
13392 | stmt = c_parser_compound_statement (parser); |
13393 | objc_begin_try_stmt (location, stmt); |
13394 | |
13395 | while (c_parser_next_token_is_keyword (parser, keyword: RID_AT_CATCH)) |
13396 | { |
13397 | struct c_parm *parm; |
13398 | tree parameter_declaration = error_mark_node; |
13399 | bool seen_open_paren = false; |
13400 | |
13401 | c_parser_consume_token (parser); |
13402 | matching_parens parens; |
13403 | if (!parens.require_open (parser)) |
13404 | seen_open_paren = true; |
13405 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
13406 | { |
13407 | /* We have "@catch (...)" (where the '...' are literally |
13408 | what is in the code). Skip the '...'. |
13409 | parameter_declaration is set to NULL_TREE, and |
13410 | objc_being_catch_clauses() knows that that means |
13411 | '...'. */ |
13412 | c_parser_consume_token (parser); |
13413 | parameter_declaration = NULL_TREE; |
13414 | } |
13415 | else |
13416 | { |
13417 | /* We have "@catch (NSException *exception)" or something |
13418 | like that. Parse the parameter declaration. */ |
13419 | parm = c_parser_parameter_declaration (parser, NULL_TREE, have_gnu_attrs: false); |
13420 | if (parm == NULL) |
13421 | parameter_declaration = error_mark_node; |
13422 | else |
13423 | parameter_declaration = grokparm (parm, NULL); |
13424 | } |
13425 | if (seen_open_paren) |
13426 | parens.require_close (parser); |
13427 | else |
13428 | { |
13429 | /* If there was no open parenthesis, we are recovering from |
13430 | an error, and we are trying to figure out what mistake |
13431 | the user has made. */ |
13432 | |
13433 | /* If there is an immediate closing parenthesis, the user |
13434 | probably forgot the opening one (ie, they typed "@catch |
13435 | NSException *e)". Parse the closing parenthesis and keep |
13436 | going. */ |
13437 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
13438 | c_parser_consume_token (parser); |
13439 | |
13440 | /* If these is no immediate closing parenthesis, the user |
13441 | probably doesn't know that parenthesis are required at |
13442 | all (ie, they typed "@catch NSException *e"). So, just |
13443 | forget about the closing parenthesis and keep going. */ |
13444 | } |
13445 | objc_begin_catch_clause (parameter_declaration); |
13446 | if (c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
13447 | c_parser_compound_statement_nostart (parser); |
13448 | objc_finish_catch_clause (); |
13449 | } |
13450 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_FINALLY)) |
13451 | { |
13452 | c_parser_consume_token (parser); |
13453 | location = c_parser_peek_token (parser)->location; |
13454 | stmt = c_parser_compound_statement (parser); |
13455 | objc_build_finally_clause (location, stmt); |
13456 | } |
13457 | objc_finish_try_stmt (); |
13458 | } |
13459 | |
13460 | /* Parse an objc-synchronized-statement. |
13461 | |
13462 | objc-synchronized-statement: |
13463 | @synchronized ( expression ) compound-statement |
13464 | */ |
13465 | |
13466 | static void |
13467 | c_parser_objc_synchronized_statement (c_parser *parser) |
13468 | { |
13469 | location_t loc; |
13470 | tree expr, stmt; |
13471 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); |
13472 | c_parser_consume_token (parser); |
13473 | loc = c_parser_peek_token (parser)->location; |
13474 | objc_maybe_warn_exceptions (loc); |
13475 | matching_parens parens; |
13476 | if (parens.require_open (parser)) |
13477 | { |
13478 | struct c_expr ce = c_parser_expression (parser); |
13479 | ce = convert_lvalue_to_rvalue (loc, ce, false, false); |
13480 | expr = ce.value; |
13481 | expr = c_fully_fold (expr, false, NULL); |
13482 | parens.skip_until_found_close (parser); |
13483 | } |
13484 | else |
13485 | expr = error_mark_node; |
13486 | stmt = c_parser_compound_statement (parser); |
13487 | objc_build_synchronized (loc, expr, stmt); |
13488 | } |
13489 | |
13490 | /* Parse an objc-selector; return NULL_TREE without an error if the |
13491 | next token is not an objc-selector. |
13492 | |
13493 | objc-selector: |
13494 | identifier |
13495 | one of |
13496 | enum struct union if else while do for switch case default |
13497 | break continue return goto asm sizeof typeof typeof_unqual __alignof |
13498 | unsigned long const short volatile signed restrict _Complex |
13499 | in out inout bycopy byref oneway int char float double void _Bool |
13500 | _Atomic |
13501 | |
13502 | ??? Why this selection of keywords but not, for example, storage |
13503 | class specifiers? */ |
13504 | |
13505 | static tree |
13506 | c_parser_objc_selector (c_parser *parser) |
13507 | { |
13508 | c_token *token = c_parser_peek_token (parser); |
13509 | tree value = token->value; |
13510 | if (token->type == CPP_NAME) |
13511 | { |
13512 | c_parser_consume_token (parser); |
13513 | return value; |
13514 | } |
13515 | if (token->type != CPP_KEYWORD) |
13516 | return NULL_TREE; |
13517 | switch (token->keyword) |
13518 | { |
13519 | case RID_ENUM: |
13520 | case RID_STRUCT: |
13521 | case RID_UNION: |
13522 | case RID_IF: |
13523 | case RID_ELSE: |
13524 | case RID_WHILE: |
13525 | case RID_DO: |
13526 | case RID_FOR: |
13527 | case RID_SWITCH: |
13528 | case RID_CASE: |
13529 | case RID_DEFAULT: |
13530 | case RID_BREAK: |
13531 | case RID_CONTINUE: |
13532 | case RID_RETURN: |
13533 | case RID_GOTO: |
13534 | case RID_ASM: |
13535 | case RID_SIZEOF: |
13536 | case RID_TYPEOF: |
13537 | case RID_TYPEOF_UNQUAL: |
13538 | case RID_ALIGNOF: |
13539 | case RID_UNSIGNED: |
13540 | case RID_LONG: |
13541 | case RID_CONST: |
13542 | case RID_SHORT: |
13543 | case RID_VOLATILE: |
13544 | case RID_SIGNED: |
13545 | case RID_RESTRICT: |
13546 | case RID_COMPLEX: |
13547 | case RID_IN: |
13548 | case RID_OUT: |
13549 | case RID_INOUT: |
13550 | case RID_BYCOPY: |
13551 | case RID_BYREF: |
13552 | case RID_ONEWAY: |
13553 | case RID_INT: |
13554 | case RID_CHAR: |
13555 | case RID_FLOAT: |
13556 | case RID_DOUBLE: |
13557 | CASE_RID_FLOATN_NX: |
13558 | case RID_VOID: |
13559 | case RID_BOOL: |
13560 | case RID_ATOMIC: |
13561 | case RID_AUTO_TYPE: |
13562 | case RID_INT_N_0: |
13563 | case RID_INT_N_1: |
13564 | case RID_INT_N_2: |
13565 | case RID_INT_N_3: |
13566 | c_parser_consume_token (parser); |
13567 | return value; |
13568 | default: |
13569 | return NULL_TREE; |
13570 | } |
13571 | } |
13572 | |
13573 | /* Parse an objc-selector-arg. |
13574 | |
13575 | objc-selector-arg: |
13576 | objc-selector |
13577 | objc-keywordname-list |
13578 | |
13579 | objc-keywordname-list: |
13580 | objc-keywordname |
13581 | objc-keywordname-list objc-keywordname |
13582 | |
13583 | objc-keywordname: |
13584 | objc-selector : |
13585 | : |
13586 | */ |
13587 | |
13588 | static tree |
13589 | c_parser_objc_selector_arg (c_parser *parser) |
13590 | { |
13591 | tree sel = c_parser_objc_selector (parser); |
13592 | tree list = NULL_TREE; |
13593 | if (sel |
13594 | && c_parser_next_token_is_not (parser, type: CPP_COLON) |
13595 | && c_parser_next_token_is_not (parser, type: CPP_SCOPE)) |
13596 | return sel; |
13597 | while (true) |
13598 | { |
13599 | if (c_parser_next_token_is (parser, type: CPP_SCOPE)) |
13600 | { |
13601 | c_parser_consume_token (parser); |
13602 | list = chainon (list, build_tree_list (sel, NULL_TREE)); |
13603 | list = chainon (list, build_tree_list (NULL_TREE, NULL_TREE)); |
13604 | } |
13605 | else |
13606 | { |
13607 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
13608 | return list; |
13609 | list = chainon (list, build_tree_list (sel, NULL_TREE)); |
13610 | } |
13611 | sel = c_parser_objc_selector (parser); |
13612 | if (!sel |
13613 | && c_parser_next_token_is_not (parser, type: CPP_COLON) |
13614 | && c_parser_next_token_is_not (parser, type: CPP_SCOPE)) |
13615 | break; |
13616 | } |
13617 | return list; |
13618 | } |
13619 | |
13620 | /* Parse an objc-receiver. |
13621 | |
13622 | objc-receiver: |
13623 | expression |
13624 | class-name |
13625 | type-name |
13626 | */ |
13627 | |
13628 | static tree |
13629 | c_parser_objc_receiver (c_parser *parser) |
13630 | { |
13631 | location_t loc = c_parser_peek_token (parser)->location; |
13632 | |
13633 | if (c_parser_peek_token (parser)->type == CPP_NAME |
13634 | && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME |
13635 | || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) |
13636 | { |
13637 | tree id = c_parser_peek_token (parser)->value; |
13638 | c_parser_consume_token (parser); |
13639 | return objc_get_class_reference (id); |
13640 | } |
13641 | struct c_expr ce = c_parser_expression (parser); |
13642 | ce = convert_lvalue_to_rvalue (loc, ce, false, false); |
13643 | return c_fully_fold (ce.value, false, NULL); |
13644 | } |
13645 | |
13646 | /* Parse objc-message-args. |
13647 | |
13648 | objc-message-args: |
13649 | objc-selector |
13650 | objc-keywordarg-list |
13651 | |
13652 | objc-keywordarg-list: |
13653 | objc-keywordarg |
13654 | objc-keywordarg-list objc-keywordarg |
13655 | |
13656 | objc-keywordarg: |
13657 | objc-selector : objc-keywordexpr |
13658 | : objc-keywordexpr |
13659 | */ |
13660 | |
13661 | static tree |
13662 | c_parser_objc_message_args (c_parser *parser) |
13663 | { |
13664 | tree sel = c_parser_objc_selector (parser); |
13665 | tree list = NULL_TREE; |
13666 | if (sel && c_parser_next_token_is_not (parser, type: CPP_COLON)) |
13667 | return sel; |
13668 | while (true) |
13669 | { |
13670 | tree keywordexpr; |
13671 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
13672 | return error_mark_node; |
13673 | keywordexpr = c_parser_objc_keywordexpr (parser); |
13674 | list = chainon (list, build_tree_list (sel, keywordexpr)); |
13675 | sel = c_parser_objc_selector (parser); |
13676 | if (!sel && c_parser_next_token_is_not (parser, type: CPP_COLON)) |
13677 | break; |
13678 | } |
13679 | return list; |
13680 | } |
13681 | |
13682 | /* Parse an objc-keywordexpr. |
13683 | |
13684 | objc-keywordexpr: |
13685 | nonempty-expr-list |
13686 | */ |
13687 | |
13688 | static tree |
13689 | c_parser_objc_keywordexpr (c_parser *parser) |
13690 | { |
13691 | tree ret; |
13692 | vec<tree, va_gc> *expr_list = c_parser_expr_list (parser, convert_p: true, fold_p: true, |
13693 | NULL, NULL, NULL, NULL); |
13694 | if (vec_safe_length (v: expr_list) == 1) |
13695 | { |
13696 | /* Just return the expression, remove a level of |
13697 | indirection. */ |
13698 | ret = (*expr_list)[0]; |
13699 | } |
13700 | else |
13701 | { |
13702 | /* We have a comma expression, we will collapse later. */ |
13703 | ret = build_tree_list_vec (expr_list); |
13704 | } |
13705 | release_tree_vector (expr_list); |
13706 | return ret; |
13707 | } |
13708 | |
13709 | /* A check, needed in several places, that ObjC interface, implementation or |
13710 | method definitions are not prefixed by incorrect items. */ |
13711 | static bool |
13712 | c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, |
13713 | struct c_declspecs *specs) |
13714 | { |
13715 | if (!specs->declspecs_seen_p || specs->non_sc_seen_p |
13716 | || specs->typespec_kind != ctsk_none) |
13717 | { |
13718 | c_parser_error (parser, |
13719 | gmsgid: "no type or storage class may be specified here," ); |
13720 | c_parser_skip_to_end_of_block_or_statement (parser); |
13721 | return true; |
13722 | } |
13723 | return false; |
13724 | } |
13725 | |
13726 | /* Parse an Objective-C @property declaration. The syntax is: |
13727 | |
13728 | objc-property-declaration: |
13729 | '@property' objc-property-attributes[opt] struct-declaration ; |
13730 | |
13731 | objc-property-attributes: |
13732 | '(' objc-property-attribute-list ')' |
13733 | |
13734 | objc-property-attribute-list: |
13735 | objc-property-attribute |
13736 | objc-property-attribute-list, objc-property-attribute |
13737 | |
13738 | objc-property-attribute |
13739 | 'getter' = identifier |
13740 | 'setter' = identifier |
13741 | 'readonly' |
13742 | 'readwrite' |
13743 | 'assign' |
13744 | 'retain' |
13745 | 'copy' |
13746 | 'nonatomic' |
13747 | |
13748 | For example: |
13749 | @property NSString *name; |
13750 | @property (readonly) id object; |
13751 | @property (retain, nonatomic, getter=getTheName) id name; |
13752 | @property int a, b, c; |
13753 | |
13754 | PS: This function is identical to cp_parser_objc_at_propery_declaration |
13755 | for C++. Keep them in sync. */ |
13756 | static void |
13757 | c_parser_objc_at_property_declaration (c_parser *parser) |
13758 | { |
13759 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); |
13760 | location_t loc = c_parser_peek_token (parser)->location; |
13761 | c_parser_consume_token (parser); /* Eat '@property'. */ |
13762 | |
13763 | /* Parse the optional attribute list. |
13764 | |
13765 | A list of parsed, but not verified, attributes. */ |
13766 | vec<property_attribute_info *> prop_attr_list = vNULL; |
13767 | |
13768 | bool syntax_error = false; |
13769 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
13770 | { |
13771 | matching_parens parens; |
13772 | |
13773 | location_t attr_start = c_parser_peek_token (parser)->location; |
13774 | /* Eat the '(' */ |
13775 | parens.consume_open (parser); |
13776 | |
13777 | /* Property attribute keywords are valid now. */ |
13778 | parser->objc_property_attr_context = true; |
13779 | |
13780 | /* Allow @property (), with a warning. */ |
13781 | location_t attr_end = c_parser_peek_token (parser)->location; |
13782 | |
13783 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
13784 | { |
13785 | location_t attr_comb = make_location (caret: attr_end, start: attr_start, finish: attr_end); |
13786 | warning_at (attr_comb, OPT_Wattributes, |
13787 | "empty property attribute list" ); |
13788 | } |
13789 | else |
13790 | while (true) |
13791 | { |
13792 | c_token *token = c_parser_peek_token (parser); |
13793 | attr_start = token->location; |
13794 | attr_end = get_finish (loc: token->location); |
13795 | location_t attr_comb = make_location (caret: attr_start, start: attr_start, |
13796 | finish: attr_end); |
13797 | |
13798 | if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) |
13799 | { |
13800 | warning_at (attr_comb, OPT_Wattributes, |
13801 | "missing property attribute" ); |
13802 | if (token->type == CPP_CLOSE_PAREN) |
13803 | break; |
13804 | c_parser_consume_token (parser); |
13805 | continue; |
13806 | } |
13807 | |
13808 | tree attr_name = NULL_TREE; |
13809 | enum rid keyword = RID_MAX; /* Not a valid property attribute. */ |
13810 | bool add_at = false; |
13811 | if (token->type == CPP_KEYWORD) |
13812 | { |
13813 | keyword = token->keyword; |
13814 | if (OBJC_IS_AT_KEYWORD (keyword)) |
13815 | { |
13816 | /* For '@' keywords the token value has the keyword, |
13817 | prepend the '@' for diagnostics. */ |
13818 | attr_name = token->value; |
13819 | add_at = true; |
13820 | } |
13821 | else |
13822 | attr_name = ridpointers[(int)keyword]; |
13823 | } |
13824 | else if (token->type == CPP_NAME) |
13825 | attr_name = token->value; |
13826 | c_parser_consume_token (parser); |
13827 | |
13828 | enum objc_property_attribute_kind prop_kind |
13829 | = objc_prop_attr_kind_for_rid (keyword); |
13830 | property_attribute_info *prop |
13831 | = new property_attribute_info (attr_name, attr_comb, prop_kind); |
13832 | prop_attr_list.safe_push (obj: prop); |
13833 | |
13834 | tree meth_name; |
13835 | switch (prop->prop_kind) |
13836 | { |
13837 | default: break; |
13838 | case OBJC_PROPERTY_ATTR_UNKNOWN: |
13839 | if (attr_name) |
13840 | error_at (attr_comb, "unknown property attribute %<%s%s%>" , |
13841 | add_at ? "@" : "" , IDENTIFIER_POINTER (attr_name)); |
13842 | else |
13843 | error_at (attr_comb, "unknown property attribute" ); |
13844 | prop->parse_error = syntax_error = true; |
13845 | break; |
13846 | |
13847 | case OBJC_PROPERTY_ATTR_GETTER: |
13848 | case OBJC_PROPERTY_ATTR_SETTER: |
13849 | if (c_parser_next_token_is_not (parser, type: CPP_EQ)) |
13850 | { |
13851 | attr_comb = make_location (caret: attr_end, start: attr_start, finish: attr_end); |
13852 | error_at (attr_comb, "expected %<=%> after Objective-C %qE" , |
13853 | attr_name); |
13854 | prop->parse_error = syntax_error = true; |
13855 | break; |
13856 | } |
13857 | token = c_parser_peek_token (parser); |
13858 | attr_end = token->location; |
13859 | c_parser_consume_token (parser); /* eat the = */ |
13860 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13861 | { |
13862 | attr_comb = make_location (caret: attr_end, start: attr_start, finish: attr_end); |
13863 | error_at (attr_comb, "expected %qE selector name" , |
13864 | attr_name); |
13865 | prop->parse_error = syntax_error = true; |
13866 | break; |
13867 | } |
13868 | /* Get the end of the method name, and consume the name. */ |
13869 | token = c_parser_peek_token (parser); |
13870 | attr_end = get_finish (loc: token->location); |
13871 | meth_name = token->value; |
13872 | c_parser_consume_token (parser); |
13873 | if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) |
13874 | { |
13875 | if (c_parser_next_token_is_not (parser, type: CPP_COLON)) |
13876 | { |
13877 | attr_comb = make_location (caret: attr_end, start: attr_start, |
13878 | finish: attr_end); |
13879 | error_at (attr_comb, "setter method names must" |
13880 | " terminate with %<:%>" ); |
13881 | prop->parse_error = syntax_error = true; |
13882 | } |
13883 | else |
13884 | { |
13885 | attr_end = get_finish (loc: c_parser_peek_token |
13886 | (parser)->location); |
13887 | c_parser_consume_token (parser); |
13888 | } |
13889 | attr_comb = make_location (caret: attr_start, start: attr_start, |
13890 | finish: attr_end); |
13891 | } |
13892 | else |
13893 | attr_comb = make_location (caret: attr_start, start: attr_start, |
13894 | finish: attr_end); |
13895 | prop->ident = meth_name; |
13896 | /* Updated location including all that was successfully |
13897 | parsed. */ |
13898 | prop->prop_loc = attr_comb; |
13899 | break; |
13900 | } |
13901 | |
13902 | /* If we see a comma here, then keep going - even if we already |
13903 | saw a syntax error. For simple mistakes e.g. (asign, getter=x) |
13904 | this makes a more useful output and avoid spurious warnings about |
13905 | missing attributes that are, in fact, specified after the one with |
13906 | the syntax error. */ |
13907 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13908 | c_parser_consume_token (parser); |
13909 | else |
13910 | break; |
13911 | } |
13912 | parser->objc_property_attr_context = false; |
13913 | |
13914 | if (syntax_error && c_parser_next_token_is_not (parser, type: CPP_CLOSE_PAREN)) |
13915 | /* We don't really want to chew the whole of the file looking for a |
13916 | matching closing parenthesis, so we will try to read the decl and |
13917 | let the error handling for that close out the statement. */ |
13918 | ; |
13919 | else |
13920 | syntax_error = false, parens.skip_until_found_close (parser); |
13921 | } |
13922 | |
13923 | /* 'properties' is the list of properties that we read. Usually a |
13924 | single one, but maybe more (eg, in "@property int a, b, c;" there |
13925 | are three). */ |
13926 | tree properties = c_parser_struct_declaration (parser, NULL); |
13927 | |
13928 | if (properties == error_mark_node) |
13929 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
13930 | else |
13931 | { |
13932 | if (properties == NULL_TREE) |
13933 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13934 | else |
13935 | { |
13936 | /* Comma-separated properties are chained together in reverse order; |
13937 | add them one by one. */ |
13938 | properties = nreverse (properties); |
13939 | for (; properties; properties = TREE_CHAIN (properties)) |
13940 | objc_add_property_declaration (loc, copy_node (properties), |
13941 | prop_attr_list); |
13942 | } |
13943 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13944 | } |
13945 | |
13946 | while (!prop_attr_list.is_empty()) |
13947 | delete prop_attr_list.pop (); |
13948 | prop_attr_list.release (); |
13949 | parser->error = false; |
13950 | } |
13951 | |
13952 | /* Parse an Objective-C @synthesize declaration. The syntax is: |
13953 | |
13954 | objc-synthesize-declaration: |
13955 | @synthesize objc-synthesize-identifier-list ; |
13956 | |
13957 | objc-synthesize-identifier-list: |
13958 | objc-synthesize-identifier |
13959 | objc-synthesize-identifier-list, objc-synthesize-identifier |
13960 | |
13961 | objc-synthesize-identifier |
13962 | identifier |
13963 | identifier = identifier |
13964 | |
13965 | For example: |
13966 | @synthesize MyProperty; |
13967 | @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty; |
13968 | |
13969 | PS: This function is identical to cp_parser_objc_at_synthesize_declaration |
13970 | for C++. Keep them in sync. |
13971 | */ |
13972 | static void |
13973 | c_parser_objc_at_synthesize_declaration (c_parser *parser) |
13974 | { |
13975 | tree list = NULL_TREE; |
13976 | location_t loc; |
13977 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); |
13978 | loc = c_parser_peek_token (parser)->location; |
13979 | |
13980 | c_parser_consume_token (parser); |
13981 | while (true) |
13982 | { |
13983 | tree property, ivar; |
13984 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13985 | { |
13986 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13987 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
13988 | /* Once we find the semicolon, we can resume normal parsing. |
13989 | We have to reset parser->error manually because |
13990 | c_parser_skip_until_found() won't reset it for us if the |
13991 | next token is precisely a semicolon. */ |
13992 | parser->error = false; |
13993 | return; |
13994 | } |
13995 | property = c_parser_peek_token (parser)->value; |
13996 | c_parser_consume_token (parser); |
13997 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
13998 | { |
13999 | c_parser_consume_token (parser); |
14000 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
14001 | { |
14002 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14003 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
14004 | parser->error = false; |
14005 | return; |
14006 | } |
14007 | ivar = c_parser_peek_token (parser)->value; |
14008 | c_parser_consume_token (parser); |
14009 | } |
14010 | else |
14011 | ivar = NULL_TREE; |
14012 | list = chainon (list, build_tree_list (ivar, property)); |
14013 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
14014 | c_parser_consume_token (parser); |
14015 | else |
14016 | break; |
14017 | } |
14018 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
14019 | objc_add_synthesize_declaration (loc, list); |
14020 | } |
14021 | |
14022 | /* Parse an Objective-C @dynamic declaration. The syntax is: |
14023 | |
14024 | objc-dynamic-declaration: |
14025 | @dynamic identifier-list ; |
14026 | |
14027 | For example: |
14028 | @dynamic MyProperty; |
14029 | @dynamic MyProperty, AnotherProperty; |
14030 | |
14031 | PS: This function is identical to cp_parser_objc_at_dynamic_declaration |
14032 | for C++. Keep them in sync. |
14033 | */ |
14034 | static void |
14035 | c_parser_objc_at_dynamic_declaration (c_parser *parser) |
14036 | { |
14037 | tree list = NULL_TREE; |
14038 | location_t loc; |
14039 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); |
14040 | loc = c_parser_peek_token (parser)->location; |
14041 | |
14042 | c_parser_consume_token (parser); |
14043 | while (true) |
14044 | { |
14045 | tree property; |
14046 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
14047 | { |
14048 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14049 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
14050 | parser->error = false; |
14051 | return; |
14052 | } |
14053 | property = c_parser_peek_token (parser)->value; |
14054 | list = chainon (list, build_tree_list (NULL_TREE, property)); |
14055 | c_parser_consume_token (parser); |
14056 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
14057 | c_parser_consume_token (parser); |
14058 | else |
14059 | break; |
14060 | } |
14061 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
14062 | objc_add_dynamic_declaration (loc, list); |
14063 | } |
14064 | |
14065 | |
14066 | /* Parse a pragma GCC ivdep. */ |
14067 | |
14068 | static bool |
14069 | c_parse_pragma_ivdep (c_parser *parser) |
14070 | { |
14071 | c_parser_consume_pragma (parser); |
14072 | c_parser_skip_to_pragma_eol (parser); |
14073 | return true; |
14074 | } |
14075 | |
14076 | /* Parse a pragma GCC novector. */ |
14077 | |
14078 | static bool |
14079 | c_parse_pragma_novector (c_parser *parser) |
14080 | { |
14081 | c_parser_consume_pragma (parser); |
14082 | c_parser_skip_to_pragma_eol (parser); |
14083 | return true; |
14084 | } |
14085 | |
14086 | /* Parse a pragma GCC unroll. */ |
14087 | |
14088 | static unsigned short |
14089 | c_parser_pragma_unroll (c_parser *parser) |
14090 | { |
14091 | unsigned short unroll; |
14092 | c_parser_consume_pragma (parser); |
14093 | location_t location = c_parser_peek_token (parser)->location; |
14094 | tree expr = c_parser_expr_no_commas (parser, NULL).value; |
14095 | mark_exp_read (expr); |
14096 | expr = c_fully_fold (expr, false, NULL); |
14097 | HOST_WIDE_INT lunroll = 0; |
14098 | if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) |
14099 | || TREE_CODE (expr) != INTEGER_CST |
14100 | || (lunroll = tree_to_shwi (expr)) < 0 |
14101 | || lunroll >= USHRT_MAX) |
14102 | { |
14103 | error_at (location, "%<#pragma GCC unroll%> requires an" |
14104 | " assignment-expression that evaluates to a non-negative" |
14105 | " integral constant less than %u" , USHRT_MAX); |
14106 | unroll = 0; |
14107 | } |
14108 | else |
14109 | { |
14110 | unroll = (unsigned short)lunroll; |
14111 | if (unroll == 0) |
14112 | unroll = 1; |
14113 | } |
14114 | |
14115 | c_parser_skip_to_pragma_eol (parser); |
14116 | return unroll; |
14117 | } |
14118 | |
14119 | /* Handle pragmas. Some OpenMP pragmas are associated with, and therefore |
14120 | should be considered, statements. ALLOW_STMT is true if we're within |
14121 | the context of a function and such pragmas are to be allowed. Returns |
14122 | true if we actually parsed such a pragma. */ |
14123 | |
14124 | static bool |
14125 | c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) |
14126 | { |
14127 | unsigned int id; |
14128 | const char *construct = NULL; |
14129 | |
14130 | input_location = c_parser_peek_token (parser)->location; |
14131 | id = c_parser_peek_token (parser)->pragma_kind; |
14132 | gcc_assert (id != PRAGMA_NONE); |
14133 | if (parser->omp_for_parse_state |
14134 | && parser->omp_for_parse_state->in_intervening_code |
14135 | && id >= PRAGMA_OMP__START_ |
14136 | && id <= PRAGMA_OMP__LAST_) |
14137 | { |
14138 | error_at (input_location, |
14139 | "intervening code must not contain OpenMP directives" ); |
14140 | parser->omp_for_parse_state->fail = true; |
14141 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14142 | return false; |
14143 | } |
14144 | |
14145 | switch (id) |
14146 | { |
14147 | case PRAGMA_OACC_DECLARE: |
14148 | c_parser_oacc_declare (parser); |
14149 | return false; |
14150 | |
14151 | case PRAGMA_OACC_ENTER_DATA: |
14152 | if (context != pragma_compound) |
14153 | { |
14154 | construct = "acc enter data" ; |
14155 | in_compound: |
14156 | if (context == pragma_stmt) |
14157 | { |
14158 | error_at (c_parser_peek_token (parser)->location, |
14159 | "%<#pragma %s%> may only be used in compound " |
14160 | "statements" , construct); |
14161 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14162 | return true; |
14163 | } |
14164 | goto bad_stmt; |
14165 | } |
14166 | c_parser_oacc_enter_exit_data (parser, true); |
14167 | return false; |
14168 | |
14169 | case PRAGMA_OACC_EXIT_DATA: |
14170 | if (context != pragma_compound) |
14171 | { |
14172 | construct = "acc exit data" ; |
14173 | goto in_compound; |
14174 | } |
14175 | c_parser_oacc_enter_exit_data (parser, false); |
14176 | return false; |
14177 | |
14178 | case PRAGMA_OACC_ROUTINE: |
14179 | if (context != pragma_external) |
14180 | { |
14181 | error_at (c_parser_peek_token (parser)->location, |
14182 | "%<#pragma acc routine%> must be at file scope" ); |
14183 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14184 | return false; |
14185 | } |
14186 | c_parser_oacc_routine (parser, context); |
14187 | return false; |
14188 | |
14189 | case PRAGMA_OACC_UPDATE: |
14190 | if (context != pragma_compound) |
14191 | { |
14192 | construct = "acc update" ; |
14193 | goto in_compound; |
14194 | } |
14195 | c_parser_oacc_update (parser); |
14196 | return false; |
14197 | |
14198 | case PRAGMA_OMP_BARRIER: |
14199 | if (context != pragma_compound) |
14200 | { |
14201 | construct = "omp barrier" ; |
14202 | goto in_compound; |
14203 | } |
14204 | c_parser_omp_barrier (parser); |
14205 | return false; |
14206 | |
14207 | case PRAGMA_OMP_DEPOBJ: |
14208 | if (context != pragma_compound) |
14209 | { |
14210 | construct = "omp depobj" ; |
14211 | goto in_compound; |
14212 | } |
14213 | c_parser_omp_depobj (parser); |
14214 | return false; |
14215 | |
14216 | case PRAGMA_OMP_FLUSH: |
14217 | if (context != pragma_compound) |
14218 | { |
14219 | construct = "omp flush" ; |
14220 | goto in_compound; |
14221 | } |
14222 | c_parser_omp_flush (parser); |
14223 | return false; |
14224 | |
14225 | case PRAGMA_OMP_TASKWAIT: |
14226 | if (context != pragma_compound) |
14227 | { |
14228 | construct = "omp taskwait" ; |
14229 | goto in_compound; |
14230 | } |
14231 | c_parser_omp_taskwait (parser); |
14232 | return false; |
14233 | |
14234 | case PRAGMA_OMP_TASKYIELD: |
14235 | if (context != pragma_compound) |
14236 | { |
14237 | construct = "omp taskyield" ; |
14238 | goto in_compound; |
14239 | } |
14240 | c_parser_omp_taskyield (parser); |
14241 | return false; |
14242 | |
14243 | case PRAGMA_OMP_CANCEL: |
14244 | if (context != pragma_compound) |
14245 | { |
14246 | construct = "omp cancel" ; |
14247 | goto in_compound; |
14248 | } |
14249 | c_parser_omp_cancel (parser); |
14250 | return false; |
14251 | |
14252 | case PRAGMA_OMP_CANCELLATION_POINT: |
14253 | return c_parser_omp_cancellation_point (parser, context); |
14254 | |
14255 | case PRAGMA_OMP_THREADPRIVATE: |
14256 | c_parser_omp_threadprivate (parser); |
14257 | return false; |
14258 | |
14259 | case PRAGMA_OMP_TARGET: |
14260 | return c_parser_omp_target (parser, context, if_p); |
14261 | |
14262 | case PRAGMA_OMP_BEGIN: |
14263 | c_parser_omp_begin (parser); |
14264 | return false; |
14265 | |
14266 | case PRAGMA_OMP_END: |
14267 | c_parser_omp_end (parser); |
14268 | return false; |
14269 | |
14270 | case PRAGMA_OMP_SCAN: |
14271 | error_at (c_parser_peek_token (parser)->location, |
14272 | "%<#pragma omp scan%> may only be used in " |
14273 | "a loop construct with %<inscan%> %<reduction%> clause" ); |
14274 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14275 | return false; |
14276 | |
14277 | case PRAGMA_OMP_SECTION: |
14278 | error_at (c_parser_peek_token (parser)->location, |
14279 | "%<#pragma omp section%> may only be used in " |
14280 | "%<#pragma omp sections%> construct" ); |
14281 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14282 | return false; |
14283 | |
14284 | case PRAGMA_OMP_DECLARE: |
14285 | return c_parser_omp_declare (parser, context); |
14286 | |
14287 | case PRAGMA_OMP_REQUIRES: |
14288 | if (context != pragma_external) |
14289 | { |
14290 | error_at (c_parser_peek_token (parser)->location, |
14291 | "%<#pragma %s%> may only be used at file scope" , |
14292 | "omp requires" ); |
14293 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14294 | return false; |
14295 | } |
14296 | c_parser_omp_requires (parser); |
14297 | return false; |
14298 | |
14299 | case PRAGMA_OMP_ALLOCATE: |
14300 | c_parser_omp_allocate (parser); |
14301 | return false; |
14302 | |
14303 | case PRAGMA_OMP_ASSUMES: |
14304 | if (context != pragma_external) |
14305 | { |
14306 | error_at (c_parser_peek_token (parser)->location, |
14307 | "%<#pragma %s%> may only be used at file scope" , |
14308 | "omp assumes" ); |
14309 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14310 | return false; |
14311 | } |
14312 | c_parser_omp_assumes (parser); |
14313 | return false; |
14314 | |
14315 | case PRAGMA_OMP_NOTHING: |
14316 | c_parser_omp_nothing (parser); |
14317 | return false; |
14318 | |
14319 | case PRAGMA_OMP_ERROR: |
14320 | return c_parser_omp_error (parser, context); |
14321 | |
14322 | case PRAGMA_OMP_ORDERED: |
14323 | return c_parser_omp_ordered (parser, context, if_p); |
14324 | |
14325 | case PRAGMA_NOVECTOR: |
14326 | case PRAGMA_UNROLL: |
14327 | case PRAGMA_IVDEP: |
14328 | { |
14329 | bool novector = false; |
14330 | unsigned short unroll = 0; |
14331 | bool ivdep = false; |
14332 | |
14333 | switch (id) |
14334 | { |
14335 | case PRAGMA_NOVECTOR: |
14336 | novector = c_parse_pragma_novector (parser); |
14337 | break; |
14338 | case PRAGMA_UNROLL: |
14339 | unroll = c_parser_pragma_unroll (parser); |
14340 | break; |
14341 | case PRAGMA_IVDEP: |
14342 | ivdep = c_parse_pragma_ivdep (parser); |
14343 | break; |
14344 | default: |
14345 | gcc_unreachable (); |
14346 | } |
14347 | |
14348 | c_token *tok = c_parser_peek_token (parser); |
14349 | bool has_more = tok->type == CPP_PRAGMA; |
14350 | while (has_more) |
14351 | { |
14352 | switch (tok->pragma_kind) |
14353 | { |
14354 | case PRAGMA_IVDEP: |
14355 | ivdep = c_parse_pragma_ivdep (parser); |
14356 | break; |
14357 | case PRAGMA_UNROLL: |
14358 | unroll = c_parser_pragma_unroll (parser); |
14359 | break; |
14360 | case PRAGMA_NOVECTOR: |
14361 | novector = c_parse_pragma_novector (parser); |
14362 | break; |
14363 | default: |
14364 | has_more = false; |
14365 | break; |
14366 | } |
14367 | tok = c_parser_peek_token (parser); |
14368 | has_more = has_more && tok->type == CPP_PRAGMA; |
14369 | } |
14370 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_FOR) |
14371 | && !c_parser_next_token_is_keyword (parser, keyword: RID_WHILE) |
14372 | && !c_parser_next_token_is_keyword (parser, keyword: RID_DO)) |
14373 | { |
14374 | c_parser_error (parser, gmsgid: "for, while or do statement expected" ); |
14375 | return false; |
14376 | } |
14377 | if (c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
14378 | c_parser_for_statement (parser, ivdep, unroll, novector, if_p); |
14379 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_WHILE)) |
14380 | c_parser_while_statement (parser, ivdep, unroll, novector, if_p); |
14381 | else |
14382 | c_parser_do_statement (parser, ivdep, unroll, novector); |
14383 | } |
14384 | return true; |
14385 | |
14386 | case PRAGMA_GCC_PCH_PREPROCESS: |
14387 | c_parser_error (parser, gmsgid: "%<#pragma GCC pch_preprocess%> must be first" ); |
14388 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14389 | return false; |
14390 | |
14391 | case PRAGMA_OACC_WAIT: |
14392 | if (context != pragma_compound) |
14393 | { |
14394 | construct = "acc wait" ; |
14395 | goto in_compound; |
14396 | } |
14397 | /* FALL THROUGH. */ |
14398 | |
14399 | default: |
14400 | if (id < PRAGMA_FIRST_EXTERNAL) |
14401 | { |
14402 | if (context != pragma_stmt && context != pragma_compound) |
14403 | { |
14404 | bad_stmt: |
14405 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
14406 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14407 | return false; |
14408 | } |
14409 | c_parser_omp_construct (parser, if_p); |
14410 | return true; |
14411 | } |
14412 | break; |
14413 | } |
14414 | |
14415 | c_parser_consume_pragma (parser); |
14416 | c_invoke_pragma_handler (id); |
14417 | |
14418 | /* Skip to EOL, but suppress any error message. Those will have been |
14419 | generated by the handler routine through calling error, as opposed |
14420 | to calling c_parser_error. */ |
14421 | parser->error = true; |
14422 | c_parser_skip_to_pragma_eol (parser); |
14423 | |
14424 | return false; |
14425 | } |
14426 | |
14427 | /* The interface the pragma parsers have to the lexer. */ |
14428 | |
14429 | enum cpp_ttype |
14430 | pragma_lex (tree *value, location_t *loc) |
14431 | { |
14432 | c_token *tok = c_parser_peek_token (parser: the_parser); |
14433 | enum cpp_ttype ret = tok->type; |
14434 | |
14435 | *value = tok->value; |
14436 | if (loc) |
14437 | *loc = tok->location; |
14438 | |
14439 | if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) |
14440 | ret = CPP_EOF; |
14441 | else if (ret == CPP_STRING) |
14442 | *value = c_parser_string_literal (parser: the_parser, translate: false, wide_ok: false).value; |
14443 | else |
14444 | { |
14445 | if (ret == CPP_KEYWORD) |
14446 | ret = CPP_NAME; |
14447 | c_parser_consume_token (parser: the_parser); |
14448 | } |
14449 | |
14450 | return ret; |
14451 | } |
14452 | |
14453 | void |
14454 | pragma_lex_discard_to_eol () |
14455 | { |
14456 | cpp_ttype type; |
14457 | do |
14458 | { |
14459 | type = c_parser_peek_token (parser: the_parser)->type; |
14460 | gcc_assert (type != CPP_EOF); |
14461 | c_parser_consume_token (parser: the_parser); |
14462 | } while (type != CPP_PRAGMA_EOL); |
14463 | } |
14464 | |
14465 | static void |
14466 | c_parser_pragma_pch_preprocess (c_parser *parser) |
14467 | { |
14468 | tree name = NULL; |
14469 | |
14470 | parser->lex_joined_string = true; |
14471 | c_parser_consume_pragma (parser); |
14472 | if (c_parser_next_token_is (parser, type: CPP_STRING)) |
14473 | { |
14474 | name = c_parser_peek_token (parser)->value; |
14475 | c_parser_consume_token (parser); |
14476 | } |
14477 | else |
14478 | c_parser_error (parser, gmsgid: "expected string literal" ); |
14479 | c_parser_skip_to_pragma_eol (parser); |
14480 | parser->lex_joined_string = false; |
14481 | |
14482 | if (name) |
14483 | c_common_pch_pragma (pfile: parse_in, TREE_STRING_POINTER (name)); |
14484 | } |
14485 | |
14486 | /* OpenACC and OpenMP parsing routines. */ |
14487 | |
14488 | /* Returns name of the next clause. |
14489 | If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and |
14490 | the token is not consumed. Otherwise appropriate pragma_omp_clause is |
14491 | returned and the token is consumed. */ |
14492 | |
14493 | static pragma_omp_clause |
14494 | c_parser_omp_clause_name (c_parser *parser) |
14495 | { |
14496 | pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; |
14497 | |
14498 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AUTO)) |
14499 | result = PRAGMA_OACC_CLAUSE_AUTO; |
14500 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
14501 | result = PRAGMA_OMP_CLAUSE_IF; |
14502 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT)) |
14503 | result = PRAGMA_OMP_CLAUSE_DEFAULT; |
14504 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
14505 | result = PRAGMA_OMP_CLAUSE_FOR; |
14506 | else if (c_parser_next_token_is (parser, type: CPP_NAME)) |
14507 | { |
14508 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
14509 | |
14510 | switch (p[0]) |
14511 | { |
14512 | case 'a': |
14513 | if (!strcmp (s1: "affinity" , s2: p)) |
14514 | result = PRAGMA_OMP_CLAUSE_AFFINITY; |
14515 | else if (!strcmp (s1: "aligned" , s2: p)) |
14516 | result = PRAGMA_OMP_CLAUSE_ALIGNED; |
14517 | else if (!strcmp (s1: "allocate" , s2: p)) |
14518 | result = PRAGMA_OMP_CLAUSE_ALLOCATE; |
14519 | else if (!strcmp (s1: "async" , s2: p)) |
14520 | result = PRAGMA_OACC_CLAUSE_ASYNC; |
14521 | else if (!strcmp (s1: "attach" , s2: p)) |
14522 | result = PRAGMA_OACC_CLAUSE_ATTACH; |
14523 | break; |
14524 | case 'b': |
14525 | if (!strcmp (s1: "bind" , s2: p)) |
14526 | result = PRAGMA_OMP_CLAUSE_BIND; |
14527 | break; |
14528 | case 'c': |
14529 | if (!strcmp (s1: "collapse" , s2: p)) |
14530 | result = PRAGMA_OMP_CLAUSE_COLLAPSE; |
14531 | else if (!strcmp (s1: "copy" , s2: p)) |
14532 | result = PRAGMA_OACC_CLAUSE_COPY; |
14533 | else if (!strcmp (s1: "copyin" , s2: p)) |
14534 | result = PRAGMA_OMP_CLAUSE_COPYIN; |
14535 | else if (!strcmp (s1: "copyout" , s2: p)) |
14536 | result = PRAGMA_OACC_CLAUSE_COPYOUT; |
14537 | else if (!strcmp (s1: "copyprivate" , s2: p)) |
14538 | result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; |
14539 | else if (!strcmp (s1: "create" , s2: p)) |
14540 | result = PRAGMA_OACC_CLAUSE_CREATE; |
14541 | break; |
14542 | case 'd': |
14543 | if (!strcmp (s1: "defaultmap" , s2: p)) |
14544 | result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; |
14545 | else if (!strcmp (s1: "delete" , s2: p)) |
14546 | result = PRAGMA_OACC_CLAUSE_DELETE; |
14547 | else if (!strcmp (s1: "depend" , s2: p)) |
14548 | result = PRAGMA_OMP_CLAUSE_DEPEND; |
14549 | else if (!strcmp (s1: "detach" , s2: p)) |
14550 | result = PRAGMA_OACC_CLAUSE_DETACH; |
14551 | else if (!strcmp (s1: "device" , s2: p)) |
14552 | result = PRAGMA_OMP_CLAUSE_DEVICE; |
14553 | else if (!strcmp (s1: "deviceptr" , s2: p)) |
14554 | result = PRAGMA_OACC_CLAUSE_DEVICEPTR; |
14555 | else if (!strcmp (s1: "device_resident" , s2: p)) |
14556 | result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT; |
14557 | else if (!strcmp (s1: "device_type" , s2: p)) |
14558 | result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE; |
14559 | else if (!strcmp (s1: "dist_schedule" , s2: p)) |
14560 | result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; |
14561 | else if (!strcmp (s1: "doacross" , s2: p)) |
14562 | result = PRAGMA_OMP_CLAUSE_DOACROSS; |
14563 | break; |
14564 | case 'e': |
14565 | if (!strcmp (s1: "enter" , s2: p)) |
14566 | result = PRAGMA_OMP_CLAUSE_ENTER; |
14567 | break; |
14568 | case 'f': |
14569 | if (!strcmp (s1: "filter" , s2: p)) |
14570 | result = PRAGMA_OMP_CLAUSE_FILTER; |
14571 | else if (!strcmp (s1: "final" , s2: p)) |
14572 | result = PRAGMA_OMP_CLAUSE_FINAL; |
14573 | else if (!strcmp (s1: "finalize" , s2: p)) |
14574 | result = PRAGMA_OACC_CLAUSE_FINALIZE; |
14575 | else if (!strcmp (s1: "firstprivate" , s2: p)) |
14576 | result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; |
14577 | else if (!strcmp (s1: "from" , s2: p)) |
14578 | result = PRAGMA_OMP_CLAUSE_FROM; |
14579 | break; |
14580 | case 'g': |
14581 | if (!strcmp (s1: "gang" , s2: p)) |
14582 | result = PRAGMA_OACC_CLAUSE_GANG; |
14583 | else if (!strcmp (s1: "grainsize" , s2: p)) |
14584 | result = PRAGMA_OMP_CLAUSE_GRAINSIZE; |
14585 | break; |
14586 | case 'h': |
14587 | if (!strcmp (s1: "has_device_addr" , s2: p)) |
14588 | result = PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR; |
14589 | else if (!strcmp (s1: "hint" , s2: p)) |
14590 | result = PRAGMA_OMP_CLAUSE_HINT; |
14591 | else if (!strcmp (s1: "host" , s2: p)) |
14592 | result = PRAGMA_OACC_CLAUSE_HOST; |
14593 | break; |
14594 | case 'i': |
14595 | if (!strcmp (s1: "if_present" , s2: p)) |
14596 | result = PRAGMA_OACC_CLAUSE_IF_PRESENT; |
14597 | else if (!strcmp (s1: "in_reduction" , s2: p)) |
14598 | result = PRAGMA_OMP_CLAUSE_IN_REDUCTION; |
14599 | else if (!strcmp (s1: "inbranch" , s2: p)) |
14600 | result = PRAGMA_OMP_CLAUSE_INBRANCH; |
14601 | else if (!strcmp (s1: "indirect" , s2: p)) |
14602 | result = PRAGMA_OMP_CLAUSE_INDIRECT; |
14603 | else if (!strcmp (s1: "independent" , s2: p)) |
14604 | result = PRAGMA_OACC_CLAUSE_INDEPENDENT; |
14605 | else if (!strcmp (s1: "is_device_ptr" , s2: p)) |
14606 | result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR; |
14607 | break; |
14608 | case 'l': |
14609 | if (!strcmp (s1: "lastprivate" , s2: p)) |
14610 | result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; |
14611 | else if (!strcmp (s1: "linear" , s2: p)) |
14612 | result = PRAGMA_OMP_CLAUSE_LINEAR; |
14613 | else if (!strcmp (s1: "link" , s2: p)) |
14614 | result = PRAGMA_OMP_CLAUSE_LINK; |
14615 | break; |
14616 | case 'm': |
14617 | if (!strcmp (s1: "map" , s2: p)) |
14618 | result = PRAGMA_OMP_CLAUSE_MAP; |
14619 | else if (!strcmp (s1: "mergeable" , s2: p)) |
14620 | result = PRAGMA_OMP_CLAUSE_MERGEABLE; |
14621 | break; |
14622 | case 'n': |
14623 | if (!strcmp (s1: "no_create" , s2: p)) |
14624 | result = PRAGMA_OACC_CLAUSE_NO_CREATE; |
14625 | else if (!strcmp (s1: "nogroup" , s2: p)) |
14626 | result = PRAGMA_OMP_CLAUSE_NOGROUP; |
14627 | else if (!strcmp (s1: "nohost" , s2: p)) |
14628 | result = PRAGMA_OACC_CLAUSE_NOHOST; |
14629 | else if (!strcmp (s1: "nontemporal" , s2: p)) |
14630 | result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; |
14631 | else if (!strcmp (s1: "notinbranch" , s2: p)) |
14632 | result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; |
14633 | else if (!strcmp (s1: "nowait" , s2: p)) |
14634 | result = PRAGMA_OMP_CLAUSE_NOWAIT; |
14635 | else if (!strcmp (s1: "num_gangs" , s2: p)) |
14636 | result = PRAGMA_OACC_CLAUSE_NUM_GANGS; |
14637 | else if (!strcmp (s1: "num_tasks" , s2: p)) |
14638 | result = PRAGMA_OMP_CLAUSE_NUM_TASKS; |
14639 | else if (!strcmp (s1: "num_teams" , s2: p)) |
14640 | result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; |
14641 | else if (!strcmp (s1: "num_threads" , s2: p)) |
14642 | result = PRAGMA_OMP_CLAUSE_NUM_THREADS; |
14643 | else if (!strcmp (s1: "num_workers" , s2: p)) |
14644 | result = PRAGMA_OACC_CLAUSE_NUM_WORKERS; |
14645 | break; |
14646 | case 'o': |
14647 | if (!strcmp (s1: "ordered" , s2: p)) |
14648 | result = PRAGMA_OMP_CLAUSE_ORDERED; |
14649 | else if (!strcmp (s1: "order" , s2: p)) |
14650 | result = PRAGMA_OMP_CLAUSE_ORDER; |
14651 | break; |
14652 | case 'p': |
14653 | if (!strcmp (s1: "parallel" , s2: p)) |
14654 | result = PRAGMA_OMP_CLAUSE_PARALLEL; |
14655 | else if (!strcmp (s1: "present" , s2: p)) |
14656 | result = PRAGMA_OACC_CLAUSE_PRESENT; |
14657 | /* As of OpenACC 2.5, these are now aliases of the non-present_or |
14658 | clauses. */ |
14659 | else if (!strcmp (s1: "present_or_copy" , s2: p) |
14660 | || !strcmp (s1: "pcopy" , s2: p)) |
14661 | result = PRAGMA_OACC_CLAUSE_COPY; |
14662 | else if (!strcmp (s1: "present_or_copyin" , s2: p) |
14663 | || !strcmp (s1: "pcopyin" , s2: p)) |
14664 | result = PRAGMA_OACC_CLAUSE_COPYIN; |
14665 | else if (!strcmp (s1: "present_or_copyout" , s2: p) |
14666 | || !strcmp (s1: "pcopyout" , s2: p)) |
14667 | result = PRAGMA_OACC_CLAUSE_COPYOUT; |
14668 | else if (!strcmp (s1: "present_or_create" , s2: p) |
14669 | || !strcmp (s1: "pcreate" , s2: p)) |
14670 | result = PRAGMA_OACC_CLAUSE_CREATE; |
14671 | else if (!strcmp (s1: "priority" , s2: p)) |
14672 | result = PRAGMA_OMP_CLAUSE_PRIORITY; |
14673 | else if (!strcmp (s1: "private" , s2: p)) |
14674 | result = PRAGMA_OMP_CLAUSE_PRIVATE; |
14675 | else if (!strcmp (s1: "proc_bind" , s2: p)) |
14676 | result = PRAGMA_OMP_CLAUSE_PROC_BIND; |
14677 | break; |
14678 | case 'r': |
14679 | if (!strcmp (s1: "reduction" , s2: p)) |
14680 | result = PRAGMA_OMP_CLAUSE_REDUCTION; |
14681 | break; |
14682 | case 's': |
14683 | if (!strcmp (s1: "safelen" , s2: p)) |
14684 | result = PRAGMA_OMP_CLAUSE_SAFELEN; |
14685 | else if (!strcmp (s1: "schedule" , s2: p)) |
14686 | result = PRAGMA_OMP_CLAUSE_SCHEDULE; |
14687 | else if (!strcmp (s1: "sections" , s2: p)) |
14688 | result = PRAGMA_OMP_CLAUSE_SECTIONS; |
14689 | else if (!strcmp (s1: "self" , s2: p)) |
14690 | result = PRAGMA_OACC_CLAUSE_SELF; |
14691 | else if (!strcmp (s1: "seq" , s2: p)) |
14692 | result = PRAGMA_OACC_CLAUSE_SEQ; |
14693 | else if (!strcmp (s1: "shared" , s2: p)) |
14694 | result = PRAGMA_OMP_CLAUSE_SHARED; |
14695 | else if (!strcmp (s1: "simd" , s2: p)) |
14696 | result = PRAGMA_OMP_CLAUSE_SIMD; |
14697 | else if (!strcmp (s1: "simdlen" , s2: p)) |
14698 | result = PRAGMA_OMP_CLAUSE_SIMDLEN; |
14699 | break; |
14700 | case 't': |
14701 | if (!strcmp (s1: "task_reduction" , s2: p)) |
14702 | result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION; |
14703 | else if (!strcmp (s1: "taskgroup" , s2: p)) |
14704 | result = PRAGMA_OMP_CLAUSE_TASKGROUP; |
14705 | else if (!strcmp (s1: "thread_limit" , s2: p)) |
14706 | result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; |
14707 | else if (!strcmp (s1: "threads" , s2: p)) |
14708 | result = PRAGMA_OMP_CLAUSE_THREADS; |
14709 | else if (!strcmp (s1: "tile" , s2: p)) |
14710 | result = PRAGMA_OACC_CLAUSE_TILE; |
14711 | else if (!strcmp (s1: "to" , s2: p)) |
14712 | result = PRAGMA_OMP_CLAUSE_TO; |
14713 | break; |
14714 | case 'u': |
14715 | if (!strcmp (s1: "uniform" , s2: p)) |
14716 | result = PRAGMA_OMP_CLAUSE_UNIFORM; |
14717 | else if (!strcmp (s1: "untied" , s2: p)) |
14718 | result = PRAGMA_OMP_CLAUSE_UNTIED; |
14719 | else if (!strcmp (s1: "use_device" , s2: p)) |
14720 | result = PRAGMA_OACC_CLAUSE_USE_DEVICE; |
14721 | else if (!strcmp (s1: "use_device_addr" , s2: p)) |
14722 | result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR; |
14723 | else if (!strcmp (s1: "use_device_ptr" , s2: p)) |
14724 | result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR; |
14725 | break; |
14726 | case 'v': |
14727 | if (!strcmp (s1: "vector" , s2: p)) |
14728 | result = PRAGMA_OACC_CLAUSE_VECTOR; |
14729 | else if (!strcmp (s1: "vector_length" , s2: p)) |
14730 | result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH; |
14731 | break; |
14732 | case 'w': |
14733 | if (!strcmp (s1: "wait" , s2: p)) |
14734 | result = PRAGMA_OACC_CLAUSE_WAIT; |
14735 | else if (!strcmp (s1: "worker" , s2: p)) |
14736 | result = PRAGMA_OACC_CLAUSE_WORKER; |
14737 | break; |
14738 | } |
14739 | } |
14740 | |
14741 | if (result != PRAGMA_OMP_CLAUSE_NONE) |
14742 | c_parser_consume_token (parser); |
14743 | |
14744 | return result; |
14745 | } |
14746 | |
14747 | /* Validate that a clause of the given type does not already exist. */ |
14748 | |
14749 | static void |
14750 | check_no_duplicate_clause (tree clauses, enum omp_clause_code code, |
14751 | const char *name) |
14752 | { |
14753 | if (tree c = omp_find_clause (clauses, kind: code)) |
14754 | error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses" , name); |
14755 | } |
14756 | |
14757 | /* OpenACC 2.0 |
14758 | Parse wait clause or wait directive parameters. */ |
14759 | |
14760 | static tree |
14761 | c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) |
14762 | { |
14763 | vec<tree, va_gc> *args; |
14764 | tree t, args_tree; |
14765 | |
14766 | matching_parens parens; |
14767 | if (!parens.require_open (parser)) |
14768 | return list; |
14769 | |
14770 | args = c_parser_expr_list (parser, convert_p: false, fold_p: true, NULL, NULL, NULL, NULL); |
14771 | args_tree = build_tree_list_vec (args); |
14772 | |
14773 | for (t = args_tree; t; t = TREE_CHAIN (t)) |
14774 | { |
14775 | tree targ = TREE_VALUE (t); |
14776 | |
14777 | if (targ != error_mark_node) |
14778 | { |
14779 | if (!INTEGRAL_TYPE_P (TREE_TYPE (targ))) |
14780 | { |
14781 | c_parser_error (parser, gmsgid: "expression must be integral" ); |
14782 | targ = error_mark_node; |
14783 | } |
14784 | else |
14785 | { |
14786 | tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); |
14787 | |
14788 | OMP_CLAUSE_DECL (c) = targ; |
14789 | OMP_CLAUSE_CHAIN (c) = list; |
14790 | list = c; |
14791 | } |
14792 | } |
14793 | } |
14794 | |
14795 | release_tree_vector (args); |
14796 | parens.require_close (parser); |
14797 | return list; |
14798 | } |
14799 | |
14800 | /* OpenACC 2.0, OpenMP 2.5: |
14801 | variable-list: |
14802 | identifier |
14803 | variable-list , identifier |
14804 | |
14805 | If KIND is nonzero, create the appropriate node and install the |
14806 | decl in OMP_CLAUSE_DECL and add the node to the head of the list. |
14807 | If KIND is nonzero, CLAUSE_LOC is the location of the clause. |
14808 | |
14809 | If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; |
14810 | return the list created. |
14811 | |
14812 | The optional ALLOW_DEREF argument is true if list items can use the deref |
14813 | (->) operator. */ |
14814 | |
14815 | struct omp_dim |
14816 | { |
14817 | tree low_bound, length; |
14818 | location_t loc; |
14819 | bool no_colon; |
14820 | omp_dim (tree lb, tree len, location_t lo, bool nc) |
14821 | : low_bound (lb), length (len), loc (lo), no_colon (nc) {} |
14822 | }; |
14823 | |
14824 | static tree |
14825 | c_parser_omp_variable_list (c_parser *parser, |
14826 | location_t clause_loc, |
14827 | enum omp_clause_code kind, tree list, |
14828 | bool allow_deref = false) |
14829 | { |
14830 | auto_vec<omp_dim> dims; |
14831 | bool array_section_p; |
14832 | auto_vec<c_token> tokens; |
14833 | unsigned int tokens_avail = 0; |
14834 | c_token *saved_tokens = NULL; |
14835 | bool first = true; |
14836 | |
14837 | while (1) |
14838 | { |
14839 | if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) |
14840 | { |
14841 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
14842 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
14843 | { |
14844 | struct c_expr expr; |
14845 | if (kind == OMP_CLAUSE_DEPEND |
14846 | && c_parser_next_token_is_keyword (parser, |
14847 | keyword: RID_OMP_ALL_MEMORY) |
14848 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
14849 | || (c_parser_peek_2nd_token (parser)->type |
14850 | == CPP_CLOSE_PAREN))) |
14851 | { |
14852 | expr.value = ridpointers[RID_OMP_ALL_MEMORY]; |
14853 | c_parser_consume_token (parser); |
14854 | } |
14855 | else |
14856 | expr = c_parser_expr_no_commas (parser, NULL); |
14857 | if (expr.value != error_mark_node) |
14858 | { |
14859 | tree u = build_omp_clause (clause_loc, kind); |
14860 | OMP_CLAUSE_DECL (u) = expr.value; |
14861 | OMP_CLAUSE_CHAIN (u) = list; |
14862 | list = u; |
14863 | } |
14864 | |
14865 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
14866 | break; |
14867 | |
14868 | c_parser_consume_token (parser); |
14869 | first = false; |
14870 | continue; |
14871 | } |
14872 | |
14873 | tokens.truncate (size: 0); |
14874 | unsigned int nesting_depth = 0; |
14875 | while (1) |
14876 | { |
14877 | c_token *token = c_parser_peek_token (parser); |
14878 | switch (token->type) |
14879 | { |
14880 | case CPP_EOF: |
14881 | case CPP_PRAGMA_EOL: |
14882 | break; |
14883 | case CPP_OPEN_BRACE: |
14884 | case CPP_OPEN_PAREN: |
14885 | case CPP_OPEN_SQUARE: |
14886 | ++nesting_depth; |
14887 | goto add; |
14888 | case CPP_CLOSE_BRACE: |
14889 | case CPP_CLOSE_PAREN: |
14890 | case CPP_CLOSE_SQUARE: |
14891 | if (nesting_depth-- == 0) |
14892 | break; |
14893 | goto add; |
14894 | case CPP_COMMA: |
14895 | if (nesting_depth == 0) |
14896 | break; |
14897 | goto add; |
14898 | default: |
14899 | add: |
14900 | tokens.safe_push (obj: *token); |
14901 | c_parser_consume_token (parser); |
14902 | continue; |
14903 | } |
14904 | break; |
14905 | } |
14906 | |
14907 | /* Make sure nothing tries to read past the end of the tokens. */ |
14908 | c_token eof_token; |
14909 | memset (s: &eof_token, c: 0, n: sizeof (eof_token)); |
14910 | eof_token.type = CPP_EOF; |
14911 | tokens.safe_push (obj: eof_token); |
14912 | tokens.safe_push (obj: eof_token); |
14913 | |
14914 | saved_tokens = parser->tokens; |
14915 | tokens_avail = parser->tokens_avail; |
14916 | parser->tokens = tokens.address (); |
14917 | parser->tokens_avail = tokens.length (); |
14918 | } |
14919 | |
14920 | tree t = NULL_TREE; |
14921 | |
14922 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
14923 | && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
14924 | { |
14925 | t = lookup_name (c_parser_peek_token (parser)->value); |
14926 | |
14927 | if (t == NULL_TREE) |
14928 | { |
14929 | undeclared_variable (c_parser_peek_token (parser)->location, |
14930 | c_parser_peek_token (parser)->value); |
14931 | t = error_mark_node; |
14932 | } |
14933 | |
14934 | c_parser_consume_token (parser); |
14935 | } |
14936 | else if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
14937 | && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME |
14938 | || (c_parser_peek_token (parser)->keyword |
14939 | == RID_PRETTY_FUNCTION_NAME) |
14940 | || (c_parser_peek_token (parser)->keyword |
14941 | == RID_C99_FUNCTION_NAME))) |
14942 | t = c_parser_predefined_identifier (parser).value; |
14943 | else |
14944 | { |
14945 | if (first) |
14946 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14947 | break; |
14948 | } |
14949 | |
14950 | if (t == error_mark_node) |
14951 | ; |
14952 | else if (kind != 0) |
14953 | { |
14954 | switch (kind) |
14955 | { |
14956 | case OMP_CLAUSE__CACHE_: |
14957 | /* The OpenACC cache directive explicitly only allows "array |
14958 | elements or subarrays". */ |
14959 | if (c_parser_peek_token (parser)->type != CPP_OPEN_SQUARE) |
14960 | { |
14961 | c_parser_error (parser, gmsgid: "expected %<[%>" ); |
14962 | t = error_mark_node; |
14963 | break; |
14964 | } |
14965 | /* FALLTHROUGH */ |
14966 | case OMP_CLAUSE_MAP: |
14967 | case OMP_CLAUSE_FROM: |
14968 | case OMP_CLAUSE_TO: |
14969 | start_component_ref: |
14970 | while (c_parser_next_token_is (parser, type: CPP_DOT) |
14971 | || (allow_deref |
14972 | && c_parser_next_token_is (parser, type: CPP_DEREF))) |
14973 | { |
14974 | location_t op_loc = c_parser_peek_token (parser)->location; |
14975 | location_t arrow_loc = UNKNOWN_LOCATION; |
14976 | if (c_parser_next_token_is (parser, type: CPP_DEREF)) |
14977 | { |
14978 | c_expr t_expr; |
14979 | t_expr.value = t; |
14980 | t_expr.original_code = ERROR_MARK; |
14981 | t_expr.original_type = NULL; |
14982 | set_c_expr_source_range (expr: &t_expr, start: op_loc, finish: op_loc); |
14983 | t_expr.m_decimal = 0; |
14984 | t_expr = convert_lvalue_to_rvalue (op_loc, t_expr, |
14985 | true, false); |
14986 | t = build_indirect_ref (op_loc, t_expr.value, RO_ARROW); |
14987 | arrow_loc = t_expr.get_location (); |
14988 | } |
14989 | c_parser_consume_token (parser); |
14990 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
14991 | { |
14992 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14993 | t = error_mark_node; |
14994 | break; |
14995 | } |
14996 | |
14997 | c_token *comp_tok = c_parser_peek_token (parser); |
14998 | tree ident = comp_tok->value; |
14999 | location_t comp_loc = comp_tok->location; |
15000 | c_parser_consume_token (parser); |
15001 | t = build_component_ref (op_loc, t, ident, comp_loc, |
15002 | arrow_loc); |
15003 | } |
15004 | /* FALLTHROUGH */ |
15005 | case OMP_CLAUSE_AFFINITY: |
15006 | case OMP_CLAUSE_DEPEND: |
15007 | case OMP_CLAUSE_REDUCTION: |
15008 | case OMP_CLAUSE_IN_REDUCTION: |
15009 | case OMP_CLAUSE_TASK_REDUCTION: |
15010 | case OMP_CLAUSE_HAS_DEVICE_ADDR: |
15011 | array_section_p = false; |
15012 | dims.truncate (size: 0); |
15013 | while (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE)) |
15014 | { |
15015 | location_t loc = UNKNOWN_LOCATION; |
15016 | tree low_bound = NULL_TREE, length = NULL_TREE; |
15017 | bool no_colon = false; |
15018 | |
15019 | c_parser_consume_token (parser); |
15020 | if (!c_parser_next_token_is (parser, type: CPP_COLON)) |
15021 | { |
15022 | location_t expr_loc |
15023 | = c_parser_peek_token (parser)->location; |
15024 | c_expr expr = c_parser_expression (parser); |
15025 | expr = convert_lvalue_to_rvalue (expr_loc, expr, |
15026 | false, true); |
15027 | low_bound = expr.value; |
15028 | loc = expr_loc; |
15029 | } |
15030 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
15031 | { |
15032 | length = integer_one_node; |
15033 | no_colon = true; |
15034 | } |
15035 | else |
15036 | { |
15037 | /* Look for `:'. */ |
15038 | if (!c_parser_require (parser, type: CPP_COLON, |
15039 | msgid: "expected %<:%>" )) |
15040 | { |
15041 | t = error_mark_node; |
15042 | break; |
15043 | } |
15044 | array_section_p = true; |
15045 | if (!c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
15046 | { |
15047 | location_t expr_loc |
15048 | = c_parser_peek_token (parser)->location; |
15049 | c_expr expr = c_parser_expression (parser); |
15050 | expr = convert_lvalue_to_rvalue (expr_loc, expr, |
15051 | false, true); |
15052 | length = expr.value; |
15053 | } |
15054 | } |
15055 | /* Look for the closing `]'. */ |
15056 | if (!c_parser_require (parser, type: CPP_CLOSE_SQUARE, |
15057 | msgid: "expected %<]%>" )) |
15058 | { |
15059 | t = error_mark_node; |
15060 | break; |
15061 | } |
15062 | |
15063 | dims.safe_push (obj: omp_dim (low_bound, length, loc, no_colon)); |
15064 | } |
15065 | |
15066 | if (t != error_mark_node) |
15067 | { |
15068 | if ((kind == OMP_CLAUSE_MAP |
15069 | || kind == OMP_CLAUSE_FROM |
15070 | || kind == OMP_CLAUSE_TO) |
15071 | && !array_section_p |
15072 | && (c_parser_next_token_is (parser, type: CPP_DOT) |
15073 | || (allow_deref |
15074 | && c_parser_next_token_is (parser, |
15075 | type: CPP_DEREF)))) |
15076 | { |
15077 | for (unsigned i = 0; i < dims.length (); i++) |
15078 | { |
15079 | gcc_assert (dims[i].length == integer_one_node); |
15080 | t = build_array_ref (dims[i].loc, |
15081 | t, dims[i].low_bound); |
15082 | } |
15083 | goto start_component_ref; |
15084 | } |
15085 | else |
15086 | for (unsigned i = 0; i < dims.length (); i++) |
15087 | t = tree_cons (dims[i].low_bound, dims[i].length, t); |
15088 | } |
15089 | |
15090 | if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) |
15091 | && t != error_mark_node |
15092 | && parser->tokens_avail != 2) |
15093 | { |
15094 | if (array_section_p) |
15095 | { |
15096 | error_at (c_parser_peek_token (parser)->location, |
15097 | "expected %<)%> or %<,%>" ); |
15098 | t = error_mark_node; |
15099 | } |
15100 | else |
15101 | { |
15102 | parser->tokens = tokens.address (); |
15103 | parser->tokens_avail = tokens.length (); |
15104 | |
15105 | t = c_parser_expr_no_commas (parser, NULL).value; |
15106 | if (t != error_mark_node && parser->tokens_avail != 2) |
15107 | { |
15108 | error_at (c_parser_peek_token (parser)->location, |
15109 | "expected %<)%> or %<,%>" ); |
15110 | t = error_mark_node; |
15111 | } |
15112 | } |
15113 | } |
15114 | break; |
15115 | default: |
15116 | break; |
15117 | } |
15118 | |
15119 | if (t != error_mark_node) |
15120 | { |
15121 | tree u = build_omp_clause (clause_loc, kind); |
15122 | OMP_CLAUSE_DECL (u) = t; |
15123 | OMP_CLAUSE_CHAIN (u) = list; |
15124 | list = u; |
15125 | } |
15126 | } |
15127 | else |
15128 | list = tree_cons (t, NULL_TREE, list); |
15129 | |
15130 | if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) |
15131 | { |
15132 | parser->tokens = saved_tokens; |
15133 | parser->tokens_avail = tokens_avail; |
15134 | } |
15135 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
15136 | break; |
15137 | |
15138 | c_parser_consume_token (parser); |
15139 | first = false; |
15140 | } |
15141 | |
15142 | return list; |
15143 | } |
15144 | |
15145 | /* Similarly, but expect leading and trailing parenthesis. This is a very |
15146 | common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF |
15147 | argument is true if list items can use the deref (->) operator. */ |
15148 | |
15149 | static tree |
15150 | c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, |
15151 | tree list, bool allow_deref = false) |
15152 | { |
15153 | /* The clauses location. */ |
15154 | location_t loc = c_parser_peek_token (parser)->location; |
15155 | |
15156 | if (parser->in_omp_decl_attribute) |
15157 | { |
15158 | if (kind) |
15159 | { |
15160 | tree u = build_omp_clause (loc, kind); |
15161 | OMP_CLAUSE_DECL (u) = parser->in_omp_decl_attribute; |
15162 | OMP_CLAUSE_CHAIN (u) = list; |
15163 | return u; |
15164 | } |
15165 | else |
15166 | return tree_cons (parser->in_omp_decl_attribute, NULL_TREE, list); |
15167 | } |
15168 | |
15169 | matching_parens parens; |
15170 | if (parens.require_open (parser)) |
15171 | { |
15172 | list = c_parser_omp_variable_list (parser, clause_loc: loc, kind, list, allow_deref); |
15173 | parens.skip_until_found_close (parser); |
15174 | } |
15175 | return list; |
15176 | } |
15177 | |
15178 | /* OpenACC 2.0: |
15179 | copy ( variable-list ) |
15180 | copyin ( variable-list ) |
15181 | copyout ( variable-list ) |
15182 | create ( variable-list ) |
15183 | delete ( variable-list ) |
15184 | present ( variable-list ) |
15185 | |
15186 | OpenACC 2.6: |
15187 | no_create ( variable-list ) |
15188 | attach ( variable-list ) |
15189 | detach ( variable-list ) */ |
15190 | |
15191 | static tree |
15192 | c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, |
15193 | tree list) |
15194 | { |
15195 | enum gomp_map_kind kind; |
15196 | switch (c_kind) |
15197 | { |
15198 | case PRAGMA_OACC_CLAUSE_ATTACH: |
15199 | kind = GOMP_MAP_ATTACH; |
15200 | break; |
15201 | case PRAGMA_OACC_CLAUSE_COPY: |
15202 | kind = GOMP_MAP_TOFROM; |
15203 | break; |
15204 | case PRAGMA_OACC_CLAUSE_COPYIN: |
15205 | kind = GOMP_MAP_TO; |
15206 | break; |
15207 | case PRAGMA_OACC_CLAUSE_COPYOUT: |
15208 | kind = GOMP_MAP_FROM; |
15209 | break; |
15210 | case PRAGMA_OACC_CLAUSE_CREATE: |
15211 | kind = GOMP_MAP_ALLOC; |
15212 | break; |
15213 | case PRAGMA_OACC_CLAUSE_DELETE: |
15214 | kind = GOMP_MAP_RELEASE; |
15215 | break; |
15216 | case PRAGMA_OACC_CLAUSE_DETACH: |
15217 | kind = GOMP_MAP_DETACH; |
15218 | break; |
15219 | case PRAGMA_OACC_CLAUSE_DEVICE: |
15220 | kind = GOMP_MAP_FORCE_TO; |
15221 | break; |
15222 | case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: |
15223 | kind = GOMP_MAP_DEVICE_RESIDENT; |
15224 | break; |
15225 | case PRAGMA_OACC_CLAUSE_LINK: |
15226 | kind = GOMP_MAP_LINK; |
15227 | break; |
15228 | case PRAGMA_OACC_CLAUSE_NO_CREATE: |
15229 | kind = GOMP_MAP_IF_PRESENT; |
15230 | break; |
15231 | case PRAGMA_OACC_CLAUSE_PRESENT: |
15232 | kind = GOMP_MAP_FORCE_PRESENT; |
15233 | break; |
15234 | case PRAGMA_OACC_CLAUSE_SELF: |
15235 | /* "The 'host' clause is a synonym for the 'self' clause." */ |
15236 | case PRAGMA_OACC_CLAUSE_HOST: |
15237 | kind = GOMP_MAP_FORCE_FROM; |
15238 | break; |
15239 | default: |
15240 | gcc_unreachable (); |
15241 | } |
15242 | tree nl, c; |
15243 | nl = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_MAP, list, allow_deref: true); |
15244 | |
15245 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
15246 | OMP_CLAUSE_SET_MAP_KIND (c, kind); |
15247 | |
15248 | return nl; |
15249 | } |
15250 | |
15251 | /* OpenACC 2.0: |
15252 | deviceptr ( variable-list ) */ |
15253 | |
15254 | static tree |
15255 | c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list) |
15256 | { |
15257 | location_t loc = c_parser_peek_token (parser)->location; |
15258 | tree vars, t; |
15259 | |
15260 | /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic |
15261 | c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, |
15262 | variable-list must only allow for pointer variables. */ |
15263 | vars = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ERROR, NULL); |
15264 | for (t = vars; t && t; t = TREE_CHAIN (t)) |
15265 | { |
15266 | tree v = TREE_PURPOSE (t); |
15267 | |
15268 | /* FIXME diagnostics: Ideally we should keep individual |
15269 | locations for all the variables in the var list to make the |
15270 | following errors more precise. Perhaps |
15271 | c_parser_omp_var_list_parens() should construct a list of |
15272 | locations to go along with the var list. */ |
15273 | |
15274 | if (!VAR_P (v) && TREE_CODE (v) != PARM_DECL) |
15275 | error_at (loc, "%qD is not a variable" , v); |
15276 | else if (TREE_TYPE (v) == error_mark_node) |
15277 | ; |
15278 | else if (!POINTER_TYPE_P (TREE_TYPE (v))) |
15279 | error_at (loc, "%qD is not a pointer variable" , v); |
15280 | |
15281 | tree u = build_omp_clause (loc, OMP_CLAUSE_MAP); |
15282 | OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR); |
15283 | OMP_CLAUSE_DECL (u) = v; |
15284 | OMP_CLAUSE_CHAIN (u) = list; |
15285 | list = u; |
15286 | } |
15287 | |
15288 | return list; |
15289 | } |
15290 | |
15291 | /* OpenACC 2.0, OpenMP 3.0: |
15292 | collapse ( constant-expression ) */ |
15293 | |
15294 | static tree |
15295 | c_parser_omp_clause_collapse (c_parser *parser, tree list) |
15296 | { |
15297 | tree c, num = error_mark_node; |
15298 | HOST_WIDE_INT n; |
15299 | location_t loc; |
15300 | |
15301 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_COLLAPSE, name: "collapse" ); |
15302 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_TILE, name: "tile" ); |
15303 | |
15304 | loc = c_parser_peek_token (parser)->location; |
15305 | matching_parens parens; |
15306 | if (parens.require_open (parser)) |
15307 | { |
15308 | num = c_parser_expr_no_commas (parser, NULL).value; |
15309 | parens.skip_until_found_close (parser); |
15310 | } |
15311 | if (num == error_mark_node) |
15312 | return list; |
15313 | mark_exp_read (num); |
15314 | num = c_fully_fold (num, false, NULL); |
15315 | if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) |
15316 | || !tree_fits_shwi_p (num) |
15317 | || (n = tree_to_shwi (num)) <= 0 |
15318 | || (int) n != n) |
15319 | { |
15320 | error_at (loc, |
15321 | "collapse argument needs positive constant integer expression" ); |
15322 | return list; |
15323 | } |
15324 | c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE); |
15325 | OMP_CLAUSE_COLLAPSE_EXPR (c) = num; |
15326 | OMP_CLAUSE_CHAIN (c) = list; |
15327 | return c; |
15328 | } |
15329 | |
15330 | /* OpenMP 2.5: |
15331 | copyin ( variable-list ) */ |
15332 | |
15333 | static tree |
15334 | c_parser_omp_clause_copyin (c_parser *parser, tree list) |
15335 | { |
15336 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_COPYIN, list); |
15337 | } |
15338 | |
15339 | /* OpenMP 2.5: |
15340 | copyprivate ( variable-list ) */ |
15341 | |
15342 | static tree |
15343 | c_parser_omp_clause_copyprivate (c_parser *parser, tree list) |
15344 | { |
15345 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_COPYPRIVATE, list); |
15346 | } |
15347 | |
15348 | /* OpenMP 2.5: |
15349 | default ( none | shared ) |
15350 | |
15351 | OpenMP 5.1: |
15352 | default ( private | firstprivate ) |
15353 | |
15354 | OpenACC: |
15355 | default ( none | present ) */ |
15356 | |
15357 | static tree |
15358 | c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) |
15359 | { |
15360 | enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; |
15361 | location_t loc = c_parser_peek_token (parser)->location; |
15362 | tree c; |
15363 | |
15364 | matching_parens parens; |
15365 | if (!parens.require_open (parser)) |
15366 | return list; |
15367 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
15368 | { |
15369 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
15370 | |
15371 | switch (p[0]) |
15372 | { |
15373 | case 'n': |
15374 | if (strcmp (s1: "none" , s2: p) != 0) |
15375 | goto invalid_kind; |
15376 | kind = OMP_CLAUSE_DEFAULT_NONE; |
15377 | break; |
15378 | |
15379 | case 'p': |
15380 | if (is_oacc) |
15381 | { |
15382 | if (strcmp (s1: "present" , s2: p) != 0) |
15383 | goto invalid_kind; |
15384 | kind = OMP_CLAUSE_DEFAULT_PRESENT; |
15385 | } |
15386 | else |
15387 | { |
15388 | if (strcmp (s1: "private" , s2: p) != 0) |
15389 | goto invalid_kind; |
15390 | kind = OMP_CLAUSE_DEFAULT_PRIVATE; |
15391 | } |
15392 | break; |
15393 | |
15394 | case 'f': |
15395 | if (strcmp (s1: "firstprivate" , s2: p) != 0 || is_oacc) |
15396 | goto invalid_kind; |
15397 | kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; |
15398 | break; |
15399 | |
15400 | case 's': |
15401 | if (strcmp (s1: "shared" , s2: p) != 0 || is_oacc) |
15402 | goto invalid_kind; |
15403 | kind = OMP_CLAUSE_DEFAULT_SHARED; |
15404 | break; |
15405 | |
15406 | default: |
15407 | goto invalid_kind; |
15408 | } |
15409 | |
15410 | c_parser_consume_token (parser); |
15411 | } |
15412 | else |
15413 | { |
15414 | invalid_kind: |
15415 | if (is_oacc) |
15416 | c_parser_error (parser, gmsgid: "expected %<none%> or %<present%>" ); |
15417 | else |
15418 | c_parser_error (parser, gmsgid: "expected %<none%>, %<shared%>, " |
15419 | "%<private%> or %<firstprivate%>" ); |
15420 | } |
15421 | parens.skip_until_found_close (parser); |
15422 | |
15423 | if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) |
15424 | return list; |
15425 | |
15426 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_DEFAULT, name: "default" ); |
15427 | c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); |
15428 | OMP_CLAUSE_CHAIN (c) = list; |
15429 | OMP_CLAUSE_DEFAULT_KIND (c) = kind; |
15430 | |
15431 | return c; |
15432 | } |
15433 | |
15434 | /* OpenMP 2.5: |
15435 | firstprivate ( variable-list ) */ |
15436 | |
15437 | static tree |
15438 | c_parser_omp_clause_firstprivate (c_parser *parser, tree list) |
15439 | { |
15440 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_FIRSTPRIVATE, list); |
15441 | } |
15442 | |
15443 | /* OpenMP 3.1: |
15444 | final ( expression ) */ |
15445 | |
15446 | static tree |
15447 | c_parser_omp_clause_final (c_parser *parser, tree list) |
15448 | { |
15449 | location_t loc = c_parser_peek_token (parser)->location; |
15450 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
15451 | { |
15452 | matching_parens parens; |
15453 | tree t, c; |
15454 | if (!parens.require_open (parser)) |
15455 | t = error_mark_node; |
15456 | else |
15457 | { |
15458 | location_t eloc = c_parser_peek_token (parser)->location; |
15459 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15460 | t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; |
15461 | t = c_objc_common_truthvalue_conversion (eloc, t); |
15462 | t = c_fully_fold (t, false, NULL); |
15463 | parens.skip_until_found_close (parser); |
15464 | } |
15465 | |
15466 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_FINAL, name: "final" ); |
15467 | |
15468 | c = build_omp_clause (loc, OMP_CLAUSE_FINAL); |
15469 | OMP_CLAUSE_FINAL_EXPR (c) = t; |
15470 | OMP_CLAUSE_CHAIN (c) = list; |
15471 | list = c; |
15472 | } |
15473 | else |
15474 | c_parser_error (parser, gmsgid: "expected %<(%>" ); |
15475 | |
15476 | return list; |
15477 | } |
15478 | |
15479 | /* OpenMP 5.1: |
15480 | indirect [( expression )] |
15481 | */ |
15482 | |
15483 | static tree |
15484 | c_parser_omp_clause_indirect (c_parser *parser, tree list) |
15485 | { |
15486 | location_t location = c_parser_peek_token (parser)->location; |
15487 | tree t; |
15488 | |
15489 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
15490 | { |
15491 | matching_parens parens; |
15492 | if (!parens.require_open (parser)) |
15493 | return list; |
15494 | |
15495 | location_t loc = c_parser_peek_token (parser)->location; |
15496 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15497 | expr = convert_lvalue_to_rvalue (loc, expr, true, true); |
15498 | t = c_objc_common_truthvalue_conversion (loc, expr.value); |
15499 | t = c_fully_fold (t, false, NULL); |
15500 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
15501 | || TREE_CODE (t) != INTEGER_CST) |
15502 | { |
15503 | c_parser_error (parser, gmsgid: "expected constant logical expression" ); |
15504 | return list; |
15505 | } |
15506 | parens.skip_until_found_close (parser); |
15507 | } |
15508 | else |
15509 | t = integer_one_node; |
15510 | |
15511 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_INDIRECT, name: "indirect" ); |
15512 | |
15513 | tree c = build_omp_clause (location, OMP_CLAUSE_INDIRECT); |
15514 | OMP_CLAUSE_INDIRECT_EXPR (c) = t; |
15515 | OMP_CLAUSE_CHAIN (c) = list; |
15516 | |
15517 | return c; |
15518 | } |
15519 | |
15520 | /* OpenACC, OpenMP 2.5: |
15521 | if ( expression ) |
15522 | |
15523 | OpenMP 4.5: |
15524 | if ( directive-name-modifier : expression ) |
15525 | |
15526 | directive-name-modifier: |
15527 | parallel | task | taskloop | target data | target | target update |
15528 | | target enter data | target exit data |
15529 | |
15530 | OpenMP 5.0: |
15531 | directive-name-modifier: |
15532 | ... | simd | cancel */ |
15533 | |
15534 | static tree |
15535 | c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) |
15536 | { |
15537 | location_t location = c_parser_peek_token (parser)->location; |
15538 | enum tree_code if_modifier = ERROR_MARK; |
15539 | |
15540 | matching_parens parens; |
15541 | if (!parens.require_open (parser)) |
15542 | return list; |
15543 | |
15544 | if (is_omp && c_parser_next_token_is (parser, type: CPP_NAME)) |
15545 | { |
15546 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
15547 | int n = 2; |
15548 | if (strcmp (s1: p, s2: "cancel" ) == 0) |
15549 | if_modifier = VOID_CST; |
15550 | else if (strcmp (s1: p, s2: "parallel" ) == 0) |
15551 | if_modifier = OMP_PARALLEL; |
15552 | else if (strcmp (s1: p, s2: "simd" ) == 0) |
15553 | if_modifier = OMP_SIMD; |
15554 | else if (strcmp (s1: p, s2: "task" ) == 0) |
15555 | if_modifier = OMP_TASK; |
15556 | else if (strcmp (s1: p, s2: "taskloop" ) == 0) |
15557 | if_modifier = OMP_TASKLOOP; |
15558 | else if (strcmp (s1: p, s2: "target" ) == 0) |
15559 | { |
15560 | if_modifier = OMP_TARGET; |
15561 | if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
15562 | { |
15563 | p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value); |
15564 | if (strcmp (s1: "data" , s2: p) == 0) |
15565 | if_modifier = OMP_TARGET_DATA; |
15566 | else if (strcmp (s1: "update" , s2: p) == 0) |
15567 | if_modifier = OMP_TARGET_UPDATE; |
15568 | else if (strcmp (s1: "enter" , s2: p) == 0) |
15569 | if_modifier = OMP_TARGET_ENTER_DATA; |
15570 | else if (strcmp (s1: "exit" , s2: p) == 0) |
15571 | if_modifier = OMP_TARGET_EXIT_DATA; |
15572 | if (if_modifier != OMP_TARGET) |
15573 | { |
15574 | n = 3; |
15575 | c_parser_consume_token (parser); |
15576 | } |
15577 | else |
15578 | { |
15579 | location_t loc = c_parser_peek_2nd_token (parser)->location; |
15580 | error_at (loc, "expected %<data%>, %<update%>, %<enter%> " |
15581 | "or %<exit%>" ); |
15582 | if_modifier = ERROR_MARK; |
15583 | } |
15584 | if (if_modifier == OMP_TARGET_ENTER_DATA |
15585 | || if_modifier == OMP_TARGET_EXIT_DATA) |
15586 | { |
15587 | if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
15588 | { |
15589 | p = IDENTIFIER_POINTER |
15590 | (c_parser_peek_2nd_token (parser)->value); |
15591 | if (strcmp (s1: "data" , s2: p) == 0) |
15592 | n = 4; |
15593 | } |
15594 | if (n == 4) |
15595 | c_parser_consume_token (parser); |
15596 | else |
15597 | { |
15598 | location_t loc |
15599 | = c_parser_peek_2nd_token (parser)->location; |
15600 | error_at (loc, "expected %<data%>" ); |
15601 | if_modifier = ERROR_MARK; |
15602 | } |
15603 | } |
15604 | } |
15605 | } |
15606 | if (if_modifier != ERROR_MARK) |
15607 | { |
15608 | if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
15609 | { |
15610 | c_parser_consume_token (parser); |
15611 | c_parser_consume_token (parser); |
15612 | } |
15613 | else |
15614 | { |
15615 | if (n > 2) |
15616 | { |
15617 | location_t loc = c_parser_peek_2nd_token (parser)->location; |
15618 | error_at (loc, "expected %<:%>" ); |
15619 | } |
15620 | if_modifier = ERROR_MARK; |
15621 | } |
15622 | } |
15623 | } |
15624 | |
15625 | location_t loc = c_parser_peek_token (parser)->location; |
15626 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15627 | expr = convert_lvalue_to_rvalue (loc, expr, true, true); |
15628 | tree t = c_objc_common_truthvalue_conversion (loc, expr.value), c; |
15629 | t = c_fully_fold (t, false, NULL); |
15630 | parens.skip_until_found_close (parser); |
15631 | |
15632 | for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) |
15633 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) |
15634 | { |
15635 | if (if_modifier != ERROR_MARK |
15636 | && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) |
15637 | { |
15638 | const char *p = NULL; |
15639 | switch (if_modifier) |
15640 | { |
15641 | case VOID_CST: p = "cancel" ; break; |
15642 | case OMP_PARALLEL: p = "parallel" ; break; |
15643 | case OMP_SIMD: p = "simd" ; break; |
15644 | case OMP_TASK: p = "task" ; break; |
15645 | case OMP_TASKLOOP: p = "taskloop" ; break; |
15646 | case OMP_TARGET_DATA: p = "target data" ; break; |
15647 | case OMP_TARGET: p = "target" ; break; |
15648 | case OMP_TARGET_UPDATE: p = "target update" ; break; |
15649 | case OMP_TARGET_ENTER_DATA: p = "target enter data" ; break; |
15650 | case OMP_TARGET_EXIT_DATA: p = "target exit data" ; break; |
15651 | default: gcc_unreachable (); |
15652 | } |
15653 | error_at (location, "too many %<if%> clauses with %qs modifier" , |
15654 | p); |
15655 | return list; |
15656 | } |
15657 | else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) |
15658 | { |
15659 | if (!is_omp) |
15660 | error_at (location, "too many %<if%> clauses" ); |
15661 | else |
15662 | error_at (location, "too many %<if%> clauses without modifier" ); |
15663 | return list; |
15664 | } |
15665 | else if (if_modifier == ERROR_MARK |
15666 | || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) |
15667 | { |
15668 | error_at (location, "if any %<if%> clause has modifier, then all " |
15669 | "%<if%> clauses have to use modifier" ); |
15670 | return list; |
15671 | } |
15672 | } |
15673 | |
15674 | c = build_omp_clause (location, OMP_CLAUSE_IF); |
15675 | OMP_CLAUSE_IF_MODIFIER (c) = if_modifier; |
15676 | OMP_CLAUSE_IF_EXPR (c) = t; |
15677 | OMP_CLAUSE_CHAIN (c) = list; |
15678 | return c; |
15679 | } |
15680 | |
15681 | /* OpenMP 2.5: |
15682 | lastprivate ( variable-list ) |
15683 | |
15684 | OpenMP 5.0: |
15685 | lastprivate ( [ lastprivate-modifier : ] variable-list ) */ |
15686 | |
15687 | static tree |
15688 | c_parser_omp_clause_lastprivate (c_parser *parser, tree list) |
15689 | { |
15690 | /* The clauses location. */ |
15691 | location_t loc = c_parser_peek_token (parser)->location; |
15692 | |
15693 | if (c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
15694 | { |
15695 | bool conditional = false; |
15696 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
15697 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
15698 | { |
15699 | const char *p |
15700 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
15701 | if (strcmp (s1: p, s2: "conditional" ) == 0) |
15702 | { |
15703 | conditional = true; |
15704 | c_parser_consume_token (parser); |
15705 | c_parser_consume_token (parser); |
15706 | } |
15707 | } |
15708 | tree nlist = c_parser_omp_variable_list (parser, clause_loc: loc, |
15709 | kind: OMP_CLAUSE_LASTPRIVATE, list); |
15710 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" ); |
15711 | if (conditional) |
15712 | for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) |
15713 | OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1; |
15714 | return nlist; |
15715 | } |
15716 | return list; |
15717 | } |
15718 | |
15719 | /* OpenMP 3.1: |
15720 | mergeable */ |
15721 | |
15722 | static tree |
15723 | c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
15724 | { |
15725 | tree c; |
15726 | |
15727 | /* FIXME: Should we allow duplicates? */ |
15728 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_MERGEABLE, name: "mergeable" ); |
15729 | |
15730 | c = build_omp_clause (c_parser_peek_token (parser)->location, |
15731 | OMP_CLAUSE_MERGEABLE); |
15732 | OMP_CLAUSE_CHAIN (c) = list; |
15733 | |
15734 | return c; |
15735 | } |
15736 | |
15737 | /* OpenMP 2.5: |
15738 | nowait */ |
15739 | |
15740 | static tree |
15741 | c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
15742 | { |
15743 | tree c; |
15744 | location_t loc = c_parser_peek_token (parser)->location; |
15745 | |
15746 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NOWAIT, name: "nowait" ); |
15747 | |
15748 | c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); |
15749 | OMP_CLAUSE_CHAIN (c) = list; |
15750 | return c; |
15751 | } |
15752 | |
15753 | /* OpenMP 2.5: |
15754 | num_threads ( expression ) */ |
15755 | |
15756 | static tree |
15757 | c_parser_omp_clause_num_threads (c_parser *parser, tree list) |
15758 | { |
15759 | location_t num_threads_loc = c_parser_peek_token (parser)->location; |
15760 | matching_parens parens; |
15761 | if (parens.require_open (parser)) |
15762 | { |
15763 | location_t expr_loc = c_parser_peek_token (parser)->location; |
15764 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15765 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
15766 | tree c, t = expr.value; |
15767 | t = c_fully_fold (t, false, NULL); |
15768 | |
15769 | parens.skip_until_found_close (parser); |
15770 | |
15771 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
15772 | { |
15773 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
15774 | return list; |
15775 | } |
15776 | |
15777 | /* Attempt to statically determine when the number isn't positive. */ |
15778 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
15779 | build_int_cst (TREE_TYPE (t), 0)); |
15780 | protected_set_expr_location (c, expr_loc); |
15781 | if (c == boolean_true_node) |
15782 | { |
15783 | warning_at (expr_loc, 0, |
15784 | "%<num_threads%> value must be positive" ); |
15785 | t = integer_one_node; |
15786 | } |
15787 | |
15788 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NUM_THREADS, name: "num_threads" ); |
15789 | |
15790 | c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS); |
15791 | OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; |
15792 | OMP_CLAUSE_CHAIN (c) = list; |
15793 | list = c; |
15794 | } |
15795 | |
15796 | return list; |
15797 | } |
15798 | |
15799 | /* OpenMP 4.5: |
15800 | num_tasks ( expression ) |
15801 | |
15802 | OpenMP 5.1: |
15803 | num_tasks ( strict : expression ) */ |
15804 | |
15805 | static tree |
15806 | c_parser_omp_clause_num_tasks (c_parser *parser, tree list) |
15807 | { |
15808 | location_t num_tasks_loc = c_parser_peek_token (parser)->location; |
15809 | matching_parens parens; |
15810 | if (parens.require_open (parser)) |
15811 | { |
15812 | bool strict = false; |
15813 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
15814 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON |
15815 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
15816 | s2: "strict" ) == 0) |
15817 | { |
15818 | strict = true; |
15819 | c_parser_consume_token (parser); |
15820 | c_parser_consume_token (parser); |
15821 | } |
15822 | |
15823 | location_t expr_loc = c_parser_peek_token (parser)->location; |
15824 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15825 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
15826 | tree c, t = expr.value; |
15827 | t = c_fully_fold (t, false, NULL); |
15828 | |
15829 | parens.skip_until_found_close (parser); |
15830 | |
15831 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
15832 | { |
15833 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
15834 | return list; |
15835 | } |
15836 | |
15837 | /* Attempt to statically determine when the number isn't positive. */ |
15838 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
15839 | build_int_cst (TREE_TYPE (t), 0)); |
15840 | if (CAN_HAVE_LOCATION_P (c)) |
15841 | SET_EXPR_LOCATION (c, expr_loc); |
15842 | if (c == boolean_true_node) |
15843 | { |
15844 | warning_at (expr_loc, 0, "%<num_tasks%> value must be positive" ); |
15845 | t = integer_one_node; |
15846 | } |
15847 | |
15848 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NUM_TASKS, name: "num_tasks" ); |
15849 | |
15850 | c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS); |
15851 | OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; |
15852 | OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; |
15853 | OMP_CLAUSE_CHAIN (c) = list; |
15854 | list = c; |
15855 | } |
15856 | |
15857 | return list; |
15858 | } |
15859 | |
15860 | /* OpenMP 4.5: |
15861 | grainsize ( expression ) |
15862 | |
15863 | OpenMP 5.1: |
15864 | grainsize ( strict : expression ) */ |
15865 | |
15866 | static tree |
15867 | c_parser_omp_clause_grainsize (c_parser *parser, tree list) |
15868 | { |
15869 | location_t grainsize_loc = c_parser_peek_token (parser)->location; |
15870 | matching_parens parens; |
15871 | if (parens.require_open (parser)) |
15872 | { |
15873 | bool strict = false; |
15874 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
15875 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON |
15876 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
15877 | s2: "strict" ) == 0) |
15878 | { |
15879 | strict = true; |
15880 | c_parser_consume_token (parser); |
15881 | c_parser_consume_token (parser); |
15882 | } |
15883 | |
15884 | location_t expr_loc = c_parser_peek_token (parser)->location; |
15885 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15886 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
15887 | tree c, t = expr.value; |
15888 | t = c_fully_fold (t, false, NULL); |
15889 | |
15890 | parens.skip_until_found_close (parser); |
15891 | |
15892 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
15893 | { |
15894 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
15895 | return list; |
15896 | } |
15897 | |
15898 | /* Attempt to statically determine when the number isn't positive. */ |
15899 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
15900 | build_int_cst (TREE_TYPE (t), 0)); |
15901 | if (CAN_HAVE_LOCATION_P (c)) |
15902 | SET_EXPR_LOCATION (c, expr_loc); |
15903 | if (c == boolean_true_node) |
15904 | { |
15905 | warning_at (expr_loc, 0, "%<grainsize%> value must be positive" ); |
15906 | t = integer_one_node; |
15907 | } |
15908 | |
15909 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_GRAINSIZE, name: "grainsize" ); |
15910 | |
15911 | c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE); |
15912 | OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; |
15913 | OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; |
15914 | OMP_CLAUSE_CHAIN (c) = list; |
15915 | list = c; |
15916 | } |
15917 | |
15918 | return list; |
15919 | } |
15920 | |
15921 | /* OpenMP 4.5: |
15922 | priority ( expression ) */ |
15923 | |
15924 | static tree |
15925 | c_parser_omp_clause_priority (c_parser *parser, tree list) |
15926 | { |
15927 | location_t priority_loc = c_parser_peek_token (parser)->location; |
15928 | matching_parens parens; |
15929 | if (parens.require_open (parser)) |
15930 | { |
15931 | location_t expr_loc = c_parser_peek_token (parser)->location; |
15932 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15933 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
15934 | tree c, t = expr.value; |
15935 | t = c_fully_fold (t, false, NULL); |
15936 | |
15937 | parens.skip_until_found_close (parser); |
15938 | |
15939 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
15940 | { |
15941 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
15942 | return list; |
15943 | } |
15944 | |
15945 | /* Attempt to statically determine when the number isn't |
15946 | non-negative. */ |
15947 | c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, t, |
15948 | build_int_cst (TREE_TYPE (t), 0)); |
15949 | if (CAN_HAVE_LOCATION_P (c)) |
15950 | SET_EXPR_LOCATION (c, expr_loc); |
15951 | if (c == boolean_true_node) |
15952 | { |
15953 | warning_at (expr_loc, 0, "%<priority%> value must be non-negative" ); |
15954 | t = integer_one_node; |
15955 | } |
15956 | |
15957 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_PRIORITY, name: "priority" ); |
15958 | |
15959 | c = build_omp_clause (priority_loc, OMP_CLAUSE_PRIORITY); |
15960 | OMP_CLAUSE_PRIORITY_EXPR (c) = t; |
15961 | OMP_CLAUSE_CHAIN (c) = list; |
15962 | list = c; |
15963 | } |
15964 | |
15965 | return list; |
15966 | } |
15967 | |
15968 | /* OpenMP 4.5: |
15969 | hint ( expression ) */ |
15970 | |
15971 | static tree |
15972 | c_parser_omp_clause_hint (c_parser *parser, tree list) |
15973 | { |
15974 | location_t hint_loc = c_parser_peek_token (parser)->location; |
15975 | matching_parens parens; |
15976 | if (parens.require_open (parser)) |
15977 | { |
15978 | location_t expr_loc = c_parser_peek_token (parser)->location; |
15979 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15980 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
15981 | tree c, t = expr.value; |
15982 | t = c_fully_fold (t, false, NULL); |
15983 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
15984 | || TREE_CODE (t) != INTEGER_CST |
15985 | || tree_int_cst_sgn (t) == -1) |
15986 | { |
15987 | c_parser_error (parser, gmsgid: "expected constant integer expression " |
15988 | "with valid sync-hint value" ); |
15989 | return list; |
15990 | } |
15991 | parens.skip_until_found_close (parser); |
15992 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_HINT, name: "hint" ); |
15993 | |
15994 | c = build_omp_clause (hint_loc, OMP_CLAUSE_HINT); |
15995 | OMP_CLAUSE_HINT_EXPR (c) = t; |
15996 | OMP_CLAUSE_CHAIN (c) = list; |
15997 | list = c; |
15998 | } |
15999 | |
16000 | return list; |
16001 | } |
16002 | |
16003 | /* OpenMP 5.1: |
16004 | filter ( integer-expression ) */ |
16005 | |
16006 | static tree |
16007 | c_parser_omp_clause_filter (c_parser *parser, tree list) |
16008 | { |
16009 | location_t hint_loc = c_parser_peek_token (parser)->location; |
16010 | matching_parens parens; |
16011 | if (parens.require_open (parser)) |
16012 | { |
16013 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16014 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16015 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16016 | tree c, t = expr.value; |
16017 | t = c_fully_fold (t, false, NULL); |
16018 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16019 | { |
16020 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16021 | return list; |
16022 | } |
16023 | parens.skip_until_found_close (parser); |
16024 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_FILTER, name: "filter" ); |
16025 | |
16026 | c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); |
16027 | OMP_CLAUSE_FILTER_EXPR (c) = t; |
16028 | OMP_CLAUSE_CHAIN (c) = list; |
16029 | list = c; |
16030 | } |
16031 | |
16032 | return list; |
16033 | } |
16034 | |
16035 | /* OpenMP 4.5: |
16036 | defaultmap ( tofrom : scalar ) |
16037 | |
16038 | OpenMP 5.0: |
16039 | defaultmap ( implicit-behavior [ : variable-category ] ) */ |
16040 | |
16041 | static tree |
16042 | c_parser_omp_clause_defaultmap (c_parser *parser, tree list) |
16043 | { |
16044 | location_t loc = c_parser_peek_token (parser)->location; |
16045 | tree c; |
16046 | const char *p; |
16047 | enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; |
16048 | enum omp_clause_defaultmap_kind category |
16049 | = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; |
16050 | |
16051 | matching_parens parens; |
16052 | if (!parens.require_open (parser)) |
16053 | return list; |
16054 | if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT)) |
16055 | p = "default" ; |
16056 | else if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
16057 | { |
16058 | invalid_behavior: |
16059 | c_parser_error (parser, gmsgid: "expected %<alloc%>, %<to%>, %<from%>, " |
16060 | "%<tofrom%>, %<firstprivate%>, %<none%> " |
16061 | "or %<default%>" ); |
16062 | goto out_err; |
16063 | } |
16064 | else |
16065 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16066 | |
16067 | switch (p[0]) |
16068 | { |
16069 | case 'a': |
16070 | if (strcmp (s1: "alloc" , s2: p) == 0) |
16071 | behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; |
16072 | else |
16073 | goto invalid_behavior; |
16074 | break; |
16075 | |
16076 | case 'd': |
16077 | if (strcmp (s1: "default" , s2: p) == 0) |
16078 | behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; |
16079 | else |
16080 | goto invalid_behavior; |
16081 | break; |
16082 | |
16083 | case 'f': |
16084 | if (strcmp (s1: "firstprivate" , s2: p) == 0) |
16085 | behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; |
16086 | else if (strcmp (s1: "from" , s2: p) == 0) |
16087 | behavior = OMP_CLAUSE_DEFAULTMAP_FROM; |
16088 | else |
16089 | goto invalid_behavior; |
16090 | break; |
16091 | |
16092 | case 'n': |
16093 | if (strcmp (s1: "none" , s2: p) == 0) |
16094 | behavior = OMP_CLAUSE_DEFAULTMAP_NONE; |
16095 | else |
16096 | goto invalid_behavior; |
16097 | break; |
16098 | |
16099 | case 'p': |
16100 | if (strcmp (s1: "present" , s2: p) == 0) |
16101 | behavior = OMP_CLAUSE_DEFAULTMAP_PRESENT; |
16102 | else |
16103 | goto invalid_behavior; |
16104 | break; |
16105 | |
16106 | case 't': |
16107 | if (strcmp (s1: "tofrom" , s2: p) == 0) |
16108 | behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; |
16109 | else if (strcmp (s1: "to" , s2: p) == 0) |
16110 | behavior = OMP_CLAUSE_DEFAULTMAP_TO; |
16111 | else |
16112 | goto invalid_behavior; |
16113 | break; |
16114 | |
16115 | default: |
16116 | goto invalid_behavior; |
16117 | } |
16118 | c_parser_consume_token (parser); |
16119 | |
16120 | if (!c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
16121 | { |
16122 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
16123 | goto out_err; |
16124 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
16125 | { |
16126 | invalid_category: |
16127 | c_parser_error (parser, gmsgid: "expected %<scalar%>, %<aggregate%>, " |
16128 | "%<pointer%> or %<all%>" ); |
16129 | goto out_err; |
16130 | } |
16131 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16132 | switch (p[0]) |
16133 | { |
16134 | case 'a': |
16135 | if (strcmp (s1: "aggregate" , s2: p) == 0) |
16136 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; |
16137 | else if (strcmp (s1: "all" , s2: p) == 0) |
16138 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL; |
16139 | else |
16140 | goto invalid_category; |
16141 | break; |
16142 | |
16143 | case 'p': |
16144 | if (strcmp (s1: "pointer" , s2: p) == 0) |
16145 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; |
16146 | else |
16147 | goto invalid_category; |
16148 | break; |
16149 | |
16150 | case 's': |
16151 | if (strcmp (s1: "scalar" , s2: p) == 0) |
16152 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; |
16153 | else |
16154 | goto invalid_category; |
16155 | break; |
16156 | |
16157 | default: |
16158 | goto invalid_category; |
16159 | } |
16160 | |
16161 | c_parser_consume_token (parser); |
16162 | } |
16163 | parens.skip_until_found_close (parser); |
16164 | |
16165 | for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) |
16166 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP |
16167 | && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED |
16168 | || category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL |
16169 | || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category |
16170 | || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) |
16171 | == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) |
16172 | || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) |
16173 | == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL))) |
16174 | { |
16175 | enum omp_clause_defaultmap_kind cat = category; |
16176 | location_t loc = OMP_CLAUSE_LOCATION (c); |
16177 | if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED |
16178 | || (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL |
16179 | && (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) |
16180 | != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) |
16181 | cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); |
16182 | p = NULL; |
16183 | switch (cat) |
16184 | { |
16185 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: |
16186 | p = NULL; |
16187 | break; |
16188 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL: |
16189 | p = "all" ; |
16190 | break; |
16191 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: |
16192 | p = "aggregate" ; |
16193 | break; |
16194 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: |
16195 | p = "pointer" ; |
16196 | break; |
16197 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: |
16198 | p = "scalar" ; |
16199 | break; |
16200 | default: |
16201 | gcc_unreachable (); |
16202 | } |
16203 | if (p) |
16204 | error_at (loc, "too many %<defaultmap%> clauses with %qs category" , |
16205 | p); |
16206 | else |
16207 | error_at (loc, "too many %<defaultmap%> clauses with unspecified " |
16208 | "category" ); |
16209 | break; |
16210 | } |
16211 | |
16212 | c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); |
16213 | OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); |
16214 | OMP_CLAUSE_CHAIN (c) = list; |
16215 | return c; |
16216 | |
16217 | out_err: |
16218 | parens.skip_until_found_close (parser); |
16219 | return list; |
16220 | } |
16221 | |
16222 | /* OpenACC 2.0: |
16223 | use_device ( variable-list ) |
16224 | |
16225 | OpenMP 4.5: |
16226 | use_device_ptr ( variable-list ) */ |
16227 | |
16228 | static tree |
16229 | c_parser_omp_clause_use_device_ptr (c_parser *parser, tree list) |
16230 | { |
16231 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_USE_DEVICE_PTR, |
16232 | list); |
16233 | } |
16234 | |
16235 | /* OpenMP 5.0: |
16236 | use_device_addr ( variable-list ) */ |
16237 | |
16238 | static tree |
16239 | c_parser_omp_clause_use_device_addr (c_parser *parser, tree list) |
16240 | { |
16241 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_USE_DEVICE_ADDR, |
16242 | list); |
16243 | } |
16244 | |
16245 | /* OpenMP 5.1: |
16246 | has_device_addr ( variable-list ) */ |
16247 | |
16248 | static tree |
16249 | c_parser_omp_clause_has_device_addr (c_parser *parser, tree list) |
16250 | { |
16251 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_HAS_DEVICE_ADDR, |
16252 | list); |
16253 | } |
16254 | |
16255 | /* OpenMP 4.5: |
16256 | is_device_ptr ( variable-list ) */ |
16257 | |
16258 | static tree |
16259 | c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list) |
16260 | { |
16261 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_IS_DEVICE_PTR, list); |
16262 | } |
16263 | |
16264 | /* OpenACC: |
16265 | num_gangs ( expression ) |
16266 | num_workers ( expression ) |
16267 | vector_length ( expression ) */ |
16268 | |
16269 | static tree |
16270 | c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code, |
16271 | tree list) |
16272 | { |
16273 | location_t loc = c_parser_peek_token (parser)->location; |
16274 | |
16275 | matching_parens parens; |
16276 | if (!parens.require_open (parser)) |
16277 | return list; |
16278 | |
16279 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16280 | c_expr expr = c_parser_expression (parser); |
16281 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16282 | tree c, t = expr.value; |
16283 | t = c_fully_fold (t, false, NULL); |
16284 | |
16285 | parens.skip_until_found_close (parser); |
16286 | |
16287 | if (t == error_mark_node) |
16288 | return list; |
16289 | else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16290 | { |
16291 | error_at (expr_loc, "%qs expression must be integral" , |
16292 | omp_clause_code_name[code]); |
16293 | return list; |
16294 | } |
16295 | |
16296 | /* Attempt to statically determine when the number isn't positive. */ |
16297 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
16298 | build_int_cst (TREE_TYPE (t), 0)); |
16299 | protected_set_expr_location (c, expr_loc); |
16300 | if (c == boolean_true_node) |
16301 | { |
16302 | warning_at (expr_loc, 0, |
16303 | "%qs value must be positive" , |
16304 | omp_clause_code_name[code]); |
16305 | t = integer_one_node; |
16306 | } |
16307 | |
16308 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
16309 | |
16310 | c = build_omp_clause (loc, code); |
16311 | OMP_CLAUSE_OPERAND (c, 0) = t; |
16312 | OMP_CLAUSE_CHAIN (c) = list; |
16313 | return c; |
16314 | } |
16315 | |
16316 | /* OpenACC: |
16317 | |
16318 | gang [( gang-arg-list )] |
16319 | worker [( [num:] int-expr )] |
16320 | vector [( [length:] int-expr )] |
16321 | |
16322 | where gang-arg is one of: |
16323 | |
16324 | [num:] int-expr |
16325 | static: size-expr |
16326 | |
16327 | and size-expr may be: |
16328 | |
16329 | * |
16330 | int-expr |
16331 | */ |
16332 | |
16333 | static tree |
16334 | c_parser_oacc_shape_clause (c_parser *parser, location_t loc, |
16335 | omp_clause_code kind, |
16336 | const char *str, tree list) |
16337 | { |
16338 | const char *id = "num" ; |
16339 | tree ops[2] = { NULL_TREE, NULL_TREE }, c; |
16340 | |
16341 | if (kind == OMP_CLAUSE_VECTOR) |
16342 | id = "length" ; |
16343 | |
16344 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
16345 | { |
16346 | c_parser_consume_token (parser); |
16347 | |
16348 | do |
16349 | { |
16350 | c_token *next = c_parser_peek_token (parser); |
16351 | int idx = 0; |
16352 | |
16353 | /* Gang static argument. */ |
16354 | if (kind == OMP_CLAUSE_GANG |
16355 | && c_parser_next_token_is_keyword (parser, keyword: RID_STATIC)) |
16356 | { |
16357 | c_parser_consume_token (parser); |
16358 | |
16359 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
16360 | goto cleanup_error; |
16361 | |
16362 | idx = 1; |
16363 | if (ops[idx] != NULL_TREE) |
16364 | { |
16365 | c_parser_error (parser, gmsgid: "too many %<static%> arguments" ); |
16366 | goto cleanup_error; |
16367 | } |
16368 | |
16369 | /* Check for the '*' argument. */ |
16370 | if (c_parser_next_token_is (parser, type: CPP_MULT) |
16371 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
16372 | || c_parser_peek_2nd_token (parser)->type |
16373 | == CPP_CLOSE_PAREN)) |
16374 | { |
16375 | c_parser_consume_token (parser); |
16376 | ops[idx] = integer_minus_one_node; |
16377 | |
16378 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
16379 | { |
16380 | c_parser_consume_token (parser); |
16381 | continue; |
16382 | } |
16383 | else |
16384 | break; |
16385 | } |
16386 | } |
16387 | /* Worker num: argument and vector length: arguments. */ |
16388 | else if (c_parser_next_token_is (parser, type: CPP_NAME) |
16389 | && strcmp (s1: id, IDENTIFIER_POINTER (next->value)) == 0 |
16390 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
16391 | { |
16392 | c_parser_consume_token (parser); /* id */ |
16393 | c_parser_consume_token (parser); /* ':' */ |
16394 | } |
16395 | |
16396 | /* Now collect the actual argument. */ |
16397 | if (ops[idx] != NULL_TREE) |
16398 | { |
16399 | c_parser_error (parser, gmsgid: "unexpected argument" ); |
16400 | goto cleanup_error; |
16401 | } |
16402 | |
16403 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16404 | c_expr cexpr = c_parser_expr_no_commas (parser, NULL); |
16405 | cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); |
16406 | tree expr = cexpr.value; |
16407 | if (expr == error_mark_node) |
16408 | goto cleanup_error; |
16409 | |
16410 | expr = c_fully_fold (expr, false, NULL); |
16411 | |
16412 | /* Attempt to statically determine when the number isn't a |
16413 | positive integer. */ |
16414 | |
16415 | if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))) |
16416 | { |
16417 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16418 | return list; |
16419 | } |
16420 | |
16421 | tree c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, expr, |
16422 | build_int_cst (TREE_TYPE (expr), 0)); |
16423 | if (c == boolean_true_node) |
16424 | { |
16425 | warning_at (loc, 0, |
16426 | "%qs value must be positive" , str); |
16427 | expr = integer_one_node; |
16428 | } |
16429 | |
16430 | ops[idx] = expr; |
16431 | |
16432 | if (kind == OMP_CLAUSE_GANG |
16433 | && c_parser_next_token_is (parser, type: CPP_COMMA)) |
16434 | { |
16435 | c_parser_consume_token (parser); |
16436 | continue; |
16437 | } |
16438 | break; |
16439 | } |
16440 | while (1); |
16441 | |
16442 | if (!c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
16443 | goto cleanup_error; |
16444 | } |
16445 | |
16446 | check_no_duplicate_clause (clauses: list, code: kind, name: str); |
16447 | |
16448 | c = build_omp_clause (loc, kind); |
16449 | |
16450 | if (ops[1]) |
16451 | OMP_CLAUSE_OPERAND (c, 1) = ops[1]; |
16452 | |
16453 | OMP_CLAUSE_OPERAND (c, 0) = ops[0]; |
16454 | OMP_CLAUSE_CHAIN (c) = list; |
16455 | |
16456 | return c; |
16457 | |
16458 | cleanup_error: |
16459 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: 0); |
16460 | return list; |
16461 | } |
16462 | |
16463 | /* OpenACC 2.5: |
16464 | auto |
16465 | finalize |
16466 | independent |
16467 | nohost |
16468 | seq */ |
16469 | |
16470 | static tree |
16471 | c_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code, |
16472 | tree list) |
16473 | { |
16474 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
16475 | |
16476 | tree c = build_omp_clause (loc, code); |
16477 | OMP_CLAUSE_CHAIN (c) = list; |
16478 | |
16479 | return c; |
16480 | } |
16481 | |
16482 | /* OpenACC: |
16483 | async [( int-expr )] */ |
16484 | |
16485 | static tree |
16486 | c_parser_oacc_clause_async (c_parser *parser, tree list) |
16487 | { |
16488 | tree c, t; |
16489 | location_t loc = c_parser_peek_token (parser)->location; |
16490 | |
16491 | t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); |
16492 | |
16493 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
16494 | { |
16495 | c_parser_consume_token (parser); |
16496 | |
16497 | t = c_parser_expr_no_commas (parser, NULL).value; |
16498 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16499 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16500 | else if (t == error_mark_node |
16501 | || !c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
16502 | return list; |
16503 | } |
16504 | else |
16505 | t = c_fully_fold (t, false, NULL); |
16506 | |
16507 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_ASYNC, name: "async" ); |
16508 | |
16509 | c = build_omp_clause (loc, OMP_CLAUSE_ASYNC); |
16510 | OMP_CLAUSE_ASYNC_EXPR (c) = t; |
16511 | OMP_CLAUSE_CHAIN (c) = list; |
16512 | list = c; |
16513 | |
16514 | return list; |
16515 | } |
16516 | |
16517 | /* OpenACC 2.0: |
16518 | tile ( size-expr-list ) */ |
16519 | |
16520 | static tree |
16521 | c_parser_oacc_clause_tile (c_parser *parser, tree list) |
16522 | { |
16523 | tree c, expr = error_mark_node; |
16524 | location_t loc; |
16525 | tree tile = NULL_TREE; |
16526 | |
16527 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_TILE, name: "tile" ); |
16528 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_COLLAPSE, name: "collapse" ); |
16529 | |
16530 | loc = c_parser_peek_token (parser)->location; |
16531 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
16532 | return list; |
16533 | |
16534 | do |
16535 | { |
16536 | if (tile && !c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
16537 | return list; |
16538 | |
16539 | if (c_parser_next_token_is (parser, type: CPP_MULT) |
16540 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
16541 | || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) |
16542 | { |
16543 | c_parser_consume_token (parser); |
16544 | expr = integer_zero_node; |
16545 | } |
16546 | else |
16547 | { |
16548 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16549 | c_expr cexpr = c_parser_expr_no_commas (parser, NULL); |
16550 | cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); |
16551 | expr = cexpr.value; |
16552 | |
16553 | if (expr == error_mark_node) |
16554 | { |
16555 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
16556 | msgid: "expected %<)%>" ); |
16557 | return list; |
16558 | } |
16559 | |
16560 | expr = c_fully_fold (expr, false, NULL); |
16561 | |
16562 | if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) |
16563 | || !tree_fits_shwi_p (expr) |
16564 | || tree_to_shwi (expr) <= 0) |
16565 | { |
16566 | error_at (expr_loc, "%<tile%> argument needs positive" |
16567 | " integral constant" ); |
16568 | expr = integer_zero_node; |
16569 | } |
16570 | } |
16571 | |
16572 | tile = tree_cons (NULL_TREE, expr, tile); |
16573 | } |
16574 | while (c_parser_next_token_is_not (parser, type: CPP_CLOSE_PAREN)); |
16575 | |
16576 | /* Consume the trailing ')'. */ |
16577 | c_parser_consume_token (parser); |
16578 | |
16579 | c = build_omp_clause (loc, OMP_CLAUSE_TILE); |
16580 | tile = nreverse (tile); |
16581 | OMP_CLAUSE_TILE_LIST (c) = tile; |
16582 | OMP_CLAUSE_CHAIN (c) = list; |
16583 | return c; |
16584 | } |
16585 | |
16586 | /* OpenACC: |
16587 | wait [( int-expr-list )] */ |
16588 | |
16589 | static tree |
16590 | c_parser_oacc_clause_wait (c_parser *parser, tree list) |
16591 | { |
16592 | location_t clause_loc = c_parser_peek_token (parser)->location; |
16593 | |
16594 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
16595 | list = c_parser_oacc_wait_list (parser, clause_loc, list); |
16596 | else |
16597 | { |
16598 | tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); |
16599 | |
16600 | OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); |
16601 | OMP_CLAUSE_CHAIN (c) = list; |
16602 | list = c; |
16603 | } |
16604 | |
16605 | return list; |
16606 | } |
16607 | |
16608 | /* OpenACC 2.7: |
16609 | self [( expression )] */ |
16610 | |
16611 | static tree |
16612 | c_parser_oacc_compute_clause_self (c_parser *parser, tree list) |
16613 | { |
16614 | tree t; |
16615 | location_t location = c_parser_peek_token (parser)->location; |
16616 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
16617 | { |
16618 | matching_parens parens; |
16619 | parens.consume_open (parser); |
16620 | |
16621 | location_t loc = c_parser_peek_token (parser)->location; |
16622 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16623 | expr = convert_lvalue_to_rvalue (loc, expr, true, true); |
16624 | t = c_objc_common_truthvalue_conversion (loc, expr.value); |
16625 | t = c_fully_fold (t, false, NULL); |
16626 | parens.skip_until_found_close (parser); |
16627 | } |
16628 | else |
16629 | t = truthvalue_true_node; |
16630 | |
16631 | for (tree c = list; c; c = OMP_CLAUSE_CHAIN (c)) |
16632 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SELF) |
16633 | { |
16634 | error_at (location, "too many %<self%> clauses" ); |
16635 | return list; |
16636 | } |
16637 | |
16638 | tree c = build_omp_clause (location, OMP_CLAUSE_SELF); |
16639 | OMP_CLAUSE_SELF_EXPR (c) = t; |
16640 | OMP_CLAUSE_CHAIN (c) = list; |
16641 | return c; |
16642 | } |
16643 | |
16644 | /* OpenMP 5.0: |
16645 | order ( concurrent ) |
16646 | |
16647 | OpenMP 5.1: |
16648 | order ( order-modifier : concurrent ) |
16649 | |
16650 | order-modifier: |
16651 | reproducible |
16652 | unconstrained */ |
16653 | |
16654 | static tree |
16655 | c_parser_omp_clause_order (c_parser *parser, tree list) |
16656 | { |
16657 | location_t loc = c_parser_peek_token (parser)->location; |
16658 | tree c; |
16659 | const char *p; |
16660 | bool unconstrained = false; |
16661 | bool reproducible = false; |
16662 | |
16663 | matching_parens parens; |
16664 | if (!parens.require_open (parser)) |
16665 | return list; |
16666 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
16667 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
16668 | { |
16669 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16670 | if (strcmp (s1: p, s2: "unconstrained" ) == 0) |
16671 | unconstrained = true; |
16672 | else if (strcmp (s1: p, s2: "reproducible" ) == 0) |
16673 | reproducible = true; |
16674 | else |
16675 | { |
16676 | c_parser_error (parser, gmsgid: "expected %<reproducible%> or " |
16677 | "%<unconstrained%>" ); |
16678 | goto out_err; |
16679 | } |
16680 | c_parser_consume_token (parser); |
16681 | c_parser_consume_token (parser); |
16682 | } |
16683 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
16684 | { |
16685 | c_parser_error (parser, gmsgid: "expected %<concurrent%>" ); |
16686 | goto out_err; |
16687 | } |
16688 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16689 | if (strcmp (s1: p, s2: "concurrent" ) != 0) |
16690 | { |
16691 | c_parser_error (parser, gmsgid: "expected %<concurrent%>" ); |
16692 | goto out_err; |
16693 | } |
16694 | c_parser_consume_token (parser); |
16695 | parens.skip_until_found_close (parser); |
16696 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_ORDER, name: "order" ); |
16697 | c = build_omp_clause (loc, OMP_CLAUSE_ORDER); |
16698 | OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; |
16699 | OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; |
16700 | OMP_CLAUSE_CHAIN (c) = list; |
16701 | return c; |
16702 | |
16703 | out_err: |
16704 | parens.skip_until_found_close (parser); |
16705 | return list; |
16706 | } |
16707 | |
16708 | |
16709 | /* OpenMP 5.0: |
16710 | bind ( teams | parallel | thread ) */ |
16711 | |
16712 | static tree |
16713 | c_parser_omp_clause_bind (c_parser *parser, tree list) |
16714 | { |
16715 | location_t loc = c_parser_peek_token (parser)->location; |
16716 | tree c; |
16717 | const char *p; |
16718 | enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD; |
16719 | |
16720 | matching_parens parens; |
16721 | if (!parens.require_open (parser)) |
16722 | return list; |
16723 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
16724 | { |
16725 | invalid: |
16726 | c_parser_error (parser, |
16727 | gmsgid: "expected %<teams%>, %<parallel%> or %<thread%>" ); |
16728 | parens.skip_until_found_close (parser); |
16729 | return list; |
16730 | } |
16731 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16732 | if (strcmp (s1: p, s2: "teams" ) == 0) |
16733 | kind = OMP_CLAUSE_BIND_TEAMS; |
16734 | else if (strcmp (s1: p, s2: "parallel" ) == 0) |
16735 | kind = OMP_CLAUSE_BIND_PARALLEL; |
16736 | else if (strcmp (s1: p, s2: "thread" ) != 0) |
16737 | goto invalid; |
16738 | c_parser_consume_token (parser); |
16739 | parens.skip_until_found_close (parser); |
16740 | /* check_no_duplicate_clause (list, OMP_CLAUSE_BIND, "bind"); */ |
16741 | c = build_omp_clause (loc, OMP_CLAUSE_BIND); |
16742 | OMP_CLAUSE_BIND_KIND (c) = kind; |
16743 | OMP_CLAUSE_CHAIN (c) = list; |
16744 | return c; |
16745 | } |
16746 | |
16747 | |
16748 | /* OpenMP 2.5: |
16749 | ordered |
16750 | |
16751 | OpenMP 4.5: |
16752 | ordered ( constant-expression ) */ |
16753 | |
16754 | static tree |
16755 | c_parser_omp_clause_ordered (c_parser *parser, tree list) |
16756 | { |
16757 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_ORDERED, name: "ordered" ); |
16758 | |
16759 | tree c, num = NULL_TREE; |
16760 | HOST_WIDE_INT n; |
16761 | location_t loc = c_parser_peek_token (parser)->location; |
16762 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
16763 | { |
16764 | matching_parens parens; |
16765 | parens.consume_open (parser); |
16766 | num = c_parser_expr_no_commas (parser, NULL).value; |
16767 | parens.skip_until_found_close (parser); |
16768 | } |
16769 | if (num == error_mark_node) |
16770 | return list; |
16771 | if (num) |
16772 | { |
16773 | mark_exp_read (num); |
16774 | num = c_fully_fold (num, false, NULL); |
16775 | if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) |
16776 | || !tree_fits_shwi_p (num) |
16777 | || (n = tree_to_shwi (num)) <= 0 |
16778 | || (int) n != n) |
16779 | { |
16780 | error_at (loc, "ordered argument needs positive " |
16781 | "constant integer expression" ); |
16782 | return list; |
16783 | } |
16784 | } |
16785 | c = build_omp_clause (loc, OMP_CLAUSE_ORDERED); |
16786 | OMP_CLAUSE_ORDERED_EXPR (c) = num; |
16787 | OMP_CLAUSE_CHAIN (c) = list; |
16788 | return c; |
16789 | } |
16790 | |
16791 | /* OpenMP 2.5: |
16792 | private ( variable-list ) */ |
16793 | |
16794 | static tree |
16795 | c_parser_omp_clause_private (c_parser *parser, tree list) |
16796 | { |
16797 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_PRIVATE, list); |
16798 | } |
16799 | |
16800 | /* OpenMP 2.5: |
16801 | reduction ( reduction-operator : variable-list ) |
16802 | |
16803 | reduction-operator: |
16804 | One of: + * - & ^ | && || |
16805 | |
16806 | OpenMP 3.1: |
16807 | |
16808 | reduction-operator: |
16809 | One of: + * - & ^ | && || max min |
16810 | |
16811 | OpenMP 4.0: |
16812 | |
16813 | reduction-operator: |
16814 | One of: + * - & ^ | && || |
16815 | identifier |
16816 | |
16817 | OpenMP 5.0: |
16818 | reduction ( reduction-modifier, reduction-operator : variable-list ) |
16819 | in_reduction ( reduction-operator : variable-list ) |
16820 | task_reduction ( reduction-operator : variable-list ) */ |
16821 | |
16822 | static tree |
16823 | c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, |
16824 | bool is_omp, tree list) |
16825 | { |
16826 | location_t clause_loc = c_parser_peek_token (parser)->location; |
16827 | matching_parens parens; |
16828 | if (parens.require_open (parser)) |
16829 | { |
16830 | bool task = false; |
16831 | bool inscan = false; |
16832 | enum tree_code code = ERROR_MARK; |
16833 | tree reduc_id = NULL_TREE; |
16834 | |
16835 | if (kind == OMP_CLAUSE_REDUCTION && is_omp) |
16836 | { |
16837 | if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT) |
16838 | && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) |
16839 | { |
16840 | c_parser_consume_token (parser); |
16841 | c_parser_consume_token (parser); |
16842 | } |
16843 | else if (c_parser_next_token_is (parser, type: CPP_NAME) |
16844 | && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) |
16845 | { |
16846 | const char *p |
16847 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16848 | if (strcmp (s1: p, s2: "task" ) == 0) |
16849 | task = true; |
16850 | else if (strcmp (s1: p, s2: "inscan" ) == 0) |
16851 | inscan = true; |
16852 | if (task || inscan) |
16853 | { |
16854 | c_parser_consume_token (parser); |
16855 | c_parser_consume_token (parser); |
16856 | } |
16857 | } |
16858 | } |
16859 | |
16860 | switch (c_parser_peek_token (parser)->type) |
16861 | { |
16862 | case CPP_PLUS: |
16863 | code = PLUS_EXPR; |
16864 | break; |
16865 | case CPP_MULT: |
16866 | code = MULT_EXPR; |
16867 | break; |
16868 | case CPP_MINUS: |
16869 | code = MINUS_EXPR; |
16870 | break; |
16871 | case CPP_AND: |
16872 | code = BIT_AND_EXPR; |
16873 | break; |
16874 | case CPP_XOR: |
16875 | code = BIT_XOR_EXPR; |
16876 | break; |
16877 | case CPP_OR: |
16878 | code = BIT_IOR_EXPR; |
16879 | break; |
16880 | case CPP_AND_AND: |
16881 | code = TRUTH_ANDIF_EXPR; |
16882 | break; |
16883 | case CPP_OR_OR: |
16884 | code = TRUTH_ORIF_EXPR; |
16885 | break; |
16886 | case CPP_NAME: |
16887 | { |
16888 | const char *p |
16889 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16890 | if (strcmp (s1: p, s2: "min" ) == 0) |
16891 | { |
16892 | code = MIN_EXPR; |
16893 | break; |
16894 | } |
16895 | if (strcmp (s1: p, s2: "max" ) == 0) |
16896 | { |
16897 | code = MAX_EXPR; |
16898 | break; |
16899 | } |
16900 | reduc_id = c_parser_peek_token (parser)->value; |
16901 | break; |
16902 | } |
16903 | default: |
16904 | c_parser_error (parser, |
16905 | gmsgid: "expected %<+%>, %<*%>, %<-%>, %<&%>, " |
16906 | "%<^%>, %<|%>, %<&&%>, %<||%> or identifier" ); |
16907 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: 0); |
16908 | return list; |
16909 | } |
16910 | c_parser_consume_token (parser); |
16911 | reduc_id = c_omp_reduction_id (code, reduc_id); |
16912 | if (c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
16913 | { |
16914 | tree nl, c; |
16915 | |
16916 | nl = c_parser_omp_variable_list (parser, clause_loc, kind, list); |
16917 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
16918 | { |
16919 | tree d = OMP_CLAUSE_DECL (c), type; |
16920 | if (TREE_CODE (d) != TREE_LIST) |
16921 | type = TREE_TYPE (d); |
16922 | else |
16923 | { |
16924 | int cnt = 0; |
16925 | tree t; |
16926 | for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t)) |
16927 | cnt++; |
16928 | type = TREE_TYPE (t); |
16929 | while (cnt > 0) |
16930 | { |
16931 | if (TREE_CODE (type) != POINTER_TYPE |
16932 | && TREE_CODE (type) != ARRAY_TYPE) |
16933 | break; |
16934 | type = TREE_TYPE (type); |
16935 | cnt--; |
16936 | } |
16937 | } |
16938 | while (TREE_CODE (type) == ARRAY_TYPE) |
16939 | type = TREE_TYPE (type); |
16940 | OMP_CLAUSE_REDUCTION_CODE (c) = code; |
16941 | if (task) |
16942 | OMP_CLAUSE_REDUCTION_TASK (c) = 1; |
16943 | else if (inscan) |
16944 | OMP_CLAUSE_REDUCTION_INSCAN (c) = 1; |
16945 | if (code == ERROR_MARK |
16946 | || !(INTEGRAL_TYPE_P (type) |
16947 | || SCALAR_FLOAT_TYPE_P (type) |
16948 | || TREE_CODE (type) == COMPLEX_TYPE)) |
16949 | OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) |
16950 | = c_omp_reduction_lookup (reduc_id, |
16951 | TYPE_MAIN_VARIANT (type)); |
16952 | } |
16953 | |
16954 | list = nl; |
16955 | } |
16956 | parens.skip_until_found_close (parser); |
16957 | } |
16958 | return list; |
16959 | } |
16960 | |
16961 | /* OpenMP 2.5: |
16962 | schedule ( schedule-kind ) |
16963 | schedule ( schedule-kind , expression ) |
16964 | |
16965 | schedule-kind: |
16966 | static | dynamic | guided | runtime | auto |
16967 | |
16968 | OpenMP 4.5: |
16969 | schedule ( schedule-modifier : schedule-kind ) |
16970 | schedule ( schedule-modifier [ , schedule-modifier ] : schedule-kind , expression ) |
16971 | |
16972 | schedule-modifier: |
16973 | simd |
16974 | monotonic |
16975 | nonmonotonic */ |
16976 | |
16977 | static tree |
16978 | c_parser_omp_clause_schedule (c_parser *parser, tree list) |
16979 | { |
16980 | tree c, t; |
16981 | location_t loc = c_parser_peek_token (parser)->location; |
16982 | int modifiers = 0, nmodifiers = 0; |
16983 | |
16984 | matching_parens parens; |
16985 | if (!parens.require_open (parser)) |
16986 | return list; |
16987 | |
16988 | c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); |
16989 | |
16990 | location_t comma = UNKNOWN_LOCATION; |
16991 | while (c_parser_next_token_is (parser, type: CPP_NAME)) |
16992 | { |
16993 | tree kind = c_parser_peek_token (parser)->value; |
16994 | const char *p = IDENTIFIER_POINTER (kind); |
16995 | if (strcmp (s1: "simd" , s2: p) == 0) |
16996 | OMP_CLAUSE_SCHEDULE_SIMD (c) = 1; |
16997 | else if (strcmp (s1: "monotonic" , s2: p) == 0) |
16998 | modifiers |= OMP_CLAUSE_SCHEDULE_MONOTONIC; |
16999 | else if (strcmp (s1: "nonmonotonic" , s2: p) == 0) |
17000 | modifiers |= OMP_CLAUSE_SCHEDULE_NONMONOTONIC; |
17001 | else |
17002 | break; |
17003 | comma = UNKNOWN_LOCATION; |
17004 | c_parser_consume_token (parser); |
17005 | if (nmodifiers++ == 0 |
17006 | && c_parser_next_token_is (parser, type: CPP_COMMA)) |
17007 | { |
17008 | comma = c_parser_peek_token (parser)->location; |
17009 | c_parser_consume_token (parser); |
17010 | } |
17011 | else |
17012 | { |
17013 | c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" ); |
17014 | break; |
17015 | } |
17016 | } |
17017 | if (comma != UNKNOWN_LOCATION) |
17018 | error_at (comma, "expected %<:%>" ); |
17019 | |
17020 | if ((modifiers & (OMP_CLAUSE_SCHEDULE_MONOTONIC |
17021 | | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) |
17022 | == (OMP_CLAUSE_SCHEDULE_MONOTONIC |
17023 | | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) |
17024 | { |
17025 | error_at (loc, "both %<monotonic%> and %<nonmonotonic%> modifiers " |
17026 | "specified" ); |
17027 | modifiers = 0; |
17028 | } |
17029 | |
17030 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
17031 | { |
17032 | tree kind = c_parser_peek_token (parser)->value; |
17033 | const char *p = IDENTIFIER_POINTER (kind); |
17034 | |
17035 | switch (p[0]) |
17036 | { |
17037 | case 'd': |
17038 | if (strcmp (s1: "dynamic" , s2: p) != 0) |
17039 | goto invalid_kind; |
17040 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; |
17041 | break; |
17042 | |
17043 | case 'g': |
17044 | if (strcmp (s1: "guided" , s2: p) != 0) |
17045 | goto invalid_kind; |
17046 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; |
17047 | break; |
17048 | |
17049 | case 'r': |
17050 | if (strcmp (s1: "runtime" , s2: p) != 0) |
17051 | goto invalid_kind; |
17052 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; |
17053 | break; |
17054 | |
17055 | default: |
17056 | goto invalid_kind; |
17057 | } |
17058 | } |
17059 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_STATIC)) |
17060 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; |
17061 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AUTO)) |
17062 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; |
17063 | else |
17064 | goto invalid_kind; |
17065 | |
17066 | c_parser_consume_token (parser); |
17067 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
17068 | { |
17069 | location_t here; |
17070 | c_parser_consume_token (parser); |
17071 | |
17072 | here = c_parser_peek_token (parser)->location; |
17073 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17074 | expr = convert_lvalue_to_rvalue (here, expr, false, true); |
17075 | t = expr.value; |
17076 | t = c_fully_fold (t, false, NULL); |
17077 | |
17078 | if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) |
17079 | error_at (here, "schedule %<runtime%> does not take " |
17080 | "a %<chunk_size%> parameter" ); |
17081 | else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) |
17082 | error_at (here, |
17083 | "schedule %<auto%> does not take " |
17084 | "a %<chunk_size%> parameter" ); |
17085 | else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE |
17086 | || TREE_CODE (TREE_TYPE (t)) == BITINT_TYPE) |
17087 | { |
17088 | /* Attempt to statically determine when the number isn't |
17089 | positive. */ |
17090 | tree s = fold_build2_loc (loc, LE_EXPR, boolean_type_node, t, |
17091 | build_int_cst (TREE_TYPE (t), 0)); |
17092 | protected_set_expr_location (s, loc); |
17093 | if (s == boolean_true_node) |
17094 | { |
17095 | warning_at (loc, 0, |
17096 | "chunk size value must be positive" ); |
17097 | t = integer_one_node; |
17098 | } |
17099 | OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; |
17100 | } |
17101 | else |
17102 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
17103 | |
17104 | parens.skip_until_found_close (parser); |
17105 | } |
17106 | else |
17107 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
17108 | msgid: "expected %<,%> or %<)%>" ); |
17109 | |
17110 | OMP_CLAUSE_SCHEDULE_KIND (c) |
17111 | = (enum omp_clause_schedule_kind) |
17112 | (OMP_CLAUSE_SCHEDULE_KIND (c) | modifiers); |
17113 | |
17114 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_SCHEDULE, name: "schedule" ); |
17115 | OMP_CLAUSE_CHAIN (c) = list; |
17116 | return c; |
17117 | |
17118 | invalid_kind: |
17119 | c_parser_error (parser, gmsgid: "invalid schedule kind" ); |
17120 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: 0); |
17121 | return list; |
17122 | } |
17123 | |
17124 | /* OpenMP 2.5: |
17125 | shared ( variable-list ) */ |
17126 | |
17127 | static tree |
17128 | c_parser_omp_clause_shared (c_parser *parser, tree list) |
17129 | { |
17130 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_SHARED, list); |
17131 | } |
17132 | |
17133 | /* OpenMP 3.0: |
17134 | untied */ |
17135 | |
17136 | static tree |
17137 | c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
17138 | { |
17139 | tree c; |
17140 | |
17141 | /* FIXME: Should we allow duplicates? */ |
17142 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_UNTIED, name: "untied" ); |
17143 | |
17144 | c = build_omp_clause (c_parser_peek_token (parser)->location, |
17145 | OMP_CLAUSE_UNTIED); |
17146 | OMP_CLAUSE_CHAIN (c) = list; |
17147 | |
17148 | return c; |
17149 | } |
17150 | |
17151 | /* OpenMP 4.0: |
17152 | inbranch |
17153 | notinbranch */ |
17154 | |
17155 | static tree |
17156 | c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, |
17157 | enum omp_clause_code code, tree list) |
17158 | { |
17159 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
17160 | |
17161 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); |
17162 | OMP_CLAUSE_CHAIN (c) = list; |
17163 | |
17164 | return c; |
17165 | } |
17166 | |
17167 | /* OpenMP 4.0: |
17168 | parallel |
17169 | for |
17170 | sections |
17171 | taskgroup */ |
17172 | |
17173 | static tree |
17174 | c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, |
17175 | enum omp_clause_code code, tree list) |
17176 | { |
17177 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); |
17178 | OMP_CLAUSE_CHAIN (c) = list; |
17179 | |
17180 | return c; |
17181 | } |
17182 | |
17183 | /* OpenMP 4.5: |
17184 | nogroup */ |
17185 | |
17186 | static tree |
17187 | c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
17188 | { |
17189 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NOGROUP, name: "nogroup" ); |
17190 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, |
17191 | OMP_CLAUSE_NOGROUP); |
17192 | OMP_CLAUSE_CHAIN (c) = list; |
17193 | return c; |
17194 | } |
17195 | |
17196 | /* OpenMP 4.5: |
17197 | simd |
17198 | threads */ |
17199 | |
17200 | static tree |
17201 | c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED, |
17202 | enum omp_clause_code code, tree list) |
17203 | { |
17204 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
17205 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); |
17206 | OMP_CLAUSE_CHAIN (c) = list; |
17207 | return c; |
17208 | } |
17209 | |
17210 | /* OpenMP 4.0: |
17211 | num_teams ( expression ) |
17212 | |
17213 | OpenMP 5.1: |
17214 | num_teams ( expression : expression ) */ |
17215 | |
17216 | static tree |
17217 | c_parser_omp_clause_num_teams (c_parser *parser, tree list) |
17218 | { |
17219 | location_t num_teams_loc = c_parser_peek_token (parser)->location; |
17220 | matching_parens parens; |
17221 | if (parens.require_open (parser)) |
17222 | { |
17223 | location_t upper_loc = c_parser_peek_token (parser)->location; |
17224 | location_t lower_loc = UNKNOWN_LOCATION; |
17225 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17226 | expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); |
17227 | tree c, upper = expr.value, lower = NULL_TREE; |
17228 | upper = c_fully_fold (upper, false, NULL); |
17229 | |
17230 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
17231 | { |
17232 | c_parser_consume_token (parser); |
17233 | lower_loc = upper_loc; |
17234 | lower = upper; |
17235 | upper_loc = c_parser_peek_token (parser)->location; |
17236 | expr = c_parser_expr_no_commas (parser, NULL); |
17237 | expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); |
17238 | upper = expr.value; |
17239 | upper = c_fully_fold (upper, false, NULL); |
17240 | } |
17241 | |
17242 | parens.skip_until_found_close (parser); |
17243 | |
17244 | if (!INTEGRAL_TYPE_P (TREE_TYPE (upper)) |
17245 | || (lower && !INTEGRAL_TYPE_P (TREE_TYPE (lower)))) |
17246 | { |
17247 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
17248 | return list; |
17249 | } |
17250 | |
17251 | /* Attempt to statically determine when the number isn't positive. */ |
17252 | c = fold_build2_loc (upper_loc, LE_EXPR, boolean_type_node, upper, |
17253 | build_int_cst (TREE_TYPE (upper), 0)); |
17254 | protected_set_expr_location (c, upper_loc); |
17255 | if (c == boolean_true_node) |
17256 | { |
17257 | warning_at (upper_loc, 0, "%<num_teams%> value must be positive" ); |
17258 | upper = integer_one_node; |
17259 | } |
17260 | if (lower) |
17261 | { |
17262 | c = fold_build2_loc (lower_loc, LE_EXPR, boolean_type_node, lower, |
17263 | build_int_cst (TREE_TYPE (lower), 0)); |
17264 | protected_set_expr_location (c, lower_loc); |
17265 | if (c == boolean_true_node) |
17266 | { |
17267 | warning_at (lower_loc, 0, "%<num_teams%> value must be positive" ); |
17268 | lower = NULL_TREE; |
17269 | } |
17270 | else if (TREE_CODE (lower) == INTEGER_CST |
17271 | && TREE_CODE (upper) == INTEGER_CST |
17272 | && tree_int_cst_lt (t1: upper, t2: lower)) |
17273 | { |
17274 | warning_at (lower_loc, 0, "%<num_teams%> lower bound %qE bigger " |
17275 | "than upper bound %qE" , lower, upper); |
17276 | lower = NULL_TREE; |
17277 | } |
17278 | } |
17279 | |
17280 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NUM_TEAMS, name: "num_teams" ); |
17281 | |
17282 | c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); |
17283 | OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (c) = upper; |
17284 | OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) = lower; |
17285 | OMP_CLAUSE_CHAIN (c) = list; |
17286 | list = c; |
17287 | } |
17288 | |
17289 | return list; |
17290 | } |
17291 | |
17292 | /* OpenMP 4.0: |
17293 | thread_limit ( expression ) */ |
17294 | |
17295 | static tree |
17296 | c_parser_omp_clause_thread_limit (c_parser *parser, tree list) |
17297 | { |
17298 | location_t num_thread_limit_loc = c_parser_peek_token (parser)->location; |
17299 | matching_parens parens; |
17300 | if (parens.require_open (parser)) |
17301 | { |
17302 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17303 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17304 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17305 | tree c, t = expr.value; |
17306 | t = c_fully_fold (t, false, NULL); |
17307 | |
17308 | parens.skip_until_found_close (parser); |
17309 | |
17310 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
17311 | { |
17312 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
17313 | return list; |
17314 | } |
17315 | |
17316 | /* Attempt to statically determine when the number isn't positive. */ |
17317 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
17318 | build_int_cst (TREE_TYPE (t), 0)); |
17319 | protected_set_expr_location (c, expr_loc); |
17320 | if (c == boolean_true_node) |
17321 | { |
17322 | warning_at (expr_loc, 0, "%<thread_limit%> value must be positive" ); |
17323 | t = integer_one_node; |
17324 | } |
17325 | |
17326 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_THREAD_LIMIT, |
17327 | name: "thread_limit" ); |
17328 | |
17329 | c = build_omp_clause (num_thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT); |
17330 | OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; |
17331 | OMP_CLAUSE_CHAIN (c) = list; |
17332 | list = c; |
17333 | } |
17334 | |
17335 | return list; |
17336 | } |
17337 | |
17338 | /* OpenMP 4.0: |
17339 | aligned ( variable-list ) |
17340 | aligned ( variable-list : constant-expression ) */ |
17341 | |
17342 | static tree |
17343 | c_parser_omp_clause_aligned (c_parser *parser, tree list) |
17344 | { |
17345 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17346 | tree nl, c; |
17347 | |
17348 | matching_parens parens; |
17349 | if (!parens.require_open (parser)) |
17350 | return list; |
17351 | |
17352 | nl = c_parser_omp_variable_list (parser, clause_loc, |
17353 | kind: OMP_CLAUSE_ALIGNED, list); |
17354 | |
17355 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
17356 | { |
17357 | c_parser_consume_token (parser); |
17358 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17359 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17360 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17361 | tree alignment = expr.value; |
17362 | alignment = c_fully_fold (alignment, false, NULL); |
17363 | if (TREE_CODE (alignment) != INTEGER_CST |
17364 | || !INTEGRAL_TYPE_P (TREE_TYPE (alignment)) |
17365 | || tree_int_cst_sgn (alignment) != 1) |
17366 | { |
17367 | error_at (clause_loc, "%<aligned%> clause alignment expression must " |
17368 | "be positive constant integer expression" ); |
17369 | alignment = NULL_TREE; |
17370 | } |
17371 | |
17372 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
17373 | OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; |
17374 | } |
17375 | |
17376 | parens.skip_until_found_close (parser); |
17377 | return nl; |
17378 | } |
17379 | |
17380 | /* OpenMP 5.0: |
17381 | allocate ( variable-list ) |
17382 | allocate ( expression : variable-list ) |
17383 | |
17384 | OpenMP 5.1: |
17385 | allocate ( allocator-modifier : variable-list ) |
17386 | allocate ( allocator-modifier , allocator-modifier : variable-list ) |
17387 | |
17388 | allocator-modifier: |
17389 | allocator ( expression ) |
17390 | align ( expression ) */ |
17391 | |
17392 | static tree |
17393 | c_parser_omp_clause_allocate (c_parser *parser, tree list) |
17394 | { |
17395 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17396 | tree nl, c; |
17397 | tree allocator = NULL_TREE; |
17398 | tree align = NULL_TREE; |
17399 | |
17400 | matching_parens parens; |
17401 | if (!parens.require_open (parser)) |
17402 | return list; |
17403 | |
17404 | if ((c_parser_next_token_is_not (parser, type: CPP_NAME) |
17405 | && c_parser_next_token_is_not (parser, type: CPP_KEYWORD)) |
17406 | || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA |
17407 | && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)) |
17408 | { |
17409 | bool has_modifiers = false; |
17410 | tree orig_type = NULL_TREE; |
17411 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
17412 | && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
17413 | { |
17414 | unsigned int n = 3; |
17415 | const char *p |
17416 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17417 | if ((strcmp (s1: p, s2: "allocator" ) == 0 || strcmp (s1: p, s2: "align" ) == 0) |
17418 | && c_parser_check_balanced_raw_token_sequence (parser, n: &n) |
17419 | && (c_parser_peek_nth_token_raw (parser, n)->type |
17420 | == CPP_CLOSE_PAREN)) |
17421 | { |
17422 | if (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
17423 | == CPP_COLON) |
17424 | has_modifiers = true; |
17425 | else if (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
17426 | == CPP_COMMA |
17427 | && (c_parser_peek_nth_token_raw (parser, n: n + 2)->type |
17428 | == CPP_NAME) |
17429 | && (c_parser_peek_nth_token_raw (parser, n: n + 3)->type |
17430 | == CPP_OPEN_PAREN)) |
17431 | { |
17432 | c_token *tok = c_parser_peek_nth_token_raw (parser, n: n + 2); |
17433 | const char *q = IDENTIFIER_POINTER (tok->value); |
17434 | n += 4; |
17435 | if ((strcmp (s1: q, s2: "allocator" ) == 0 |
17436 | || strcmp (s1: q, s2: "align" ) == 0) |
17437 | && c_parser_check_balanced_raw_token_sequence (parser, |
17438 | n: &n) |
17439 | && (c_parser_peek_nth_token_raw (parser, n)->type |
17440 | == CPP_CLOSE_PAREN) |
17441 | && (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
17442 | == CPP_COLON)) |
17443 | has_modifiers = true; |
17444 | } |
17445 | } |
17446 | if (has_modifiers) |
17447 | { |
17448 | c_parser_consume_token (parser); |
17449 | matching_parens parens2;; |
17450 | parens2.require_open (parser); |
17451 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17452 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17453 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17454 | if (expr.value == error_mark_node) |
17455 | ; |
17456 | else if (strcmp (s1: p, s2: "allocator" ) == 0) |
17457 | { |
17458 | allocator = expr.value; |
17459 | allocator = c_fully_fold (allocator, false, NULL); |
17460 | orig_type = expr.original_type |
17461 | ? expr.original_type : TREE_TYPE (allocator); |
17462 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
17463 | } |
17464 | else |
17465 | { |
17466 | align = expr.value; |
17467 | align = c_fully_fold (align, false, NULL); |
17468 | } |
17469 | parens2.skip_until_found_close (parser); |
17470 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
17471 | { |
17472 | c_parser_consume_token (parser); |
17473 | c_token *tok = c_parser_peek_token (parser); |
17474 | const char *q = "" ; |
17475 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
17476 | q = IDENTIFIER_POINTER (tok->value); |
17477 | if (strcmp (s1: q, s2: "allocator" ) != 0 && strcmp (s1: q, s2: "align" ) != 0) |
17478 | { |
17479 | c_parser_error (parser, gmsgid: "expected %<allocator%> or " |
17480 | "%<align%>" ); |
17481 | parens.skip_until_found_close (parser); |
17482 | return list; |
17483 | } |
17484 | else if (strcmp (s1: p, s2: q) == 0) |
17485 | { |
17486 | error_at (tok->location, "duplicate %qs modifier" , p); |
17487 | parens.skip_until_found_close (parser); |
17488 | return list; |
17489 | } |
17490 | c_parser_consume_token (parser); |
17491 | if (!parens2.require_open (parser)) |
17492 | { |
17493 | parens.skip_until_found_close (parser); |
17494 | return list; |
17495 | } |
17496 | expr_loc = c_parser_peek_token (parser)->location; |
17497 | expr = c_parser_expr_no_commas (parser, NULL); |
17498 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, |
17499 | true); |
17500 | if (strcmp (s1: q, s2: "allocator" ) == 0) |
17501 | { |
17502 | allocator = expr.value; |
17503 | allocator = c_fully_fold (allocator, false, NULL); |
17504 | orig_type = expr.original_type |
17505 | ? expr.original_type : TREE_TYPE (allocator); |
17506 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
17507 | } |
17508 | else |
17509 | { |
17510 | align = expr.value; |
17511 | align = c_fully_fold (align, false, NULL); |
17512 | } |
17513 | parens2.skip_until_found_close (parser); |
17514 | } |
17515 | } |
17516 | } |
17517 | if (!has_modifiers) |
17518 | { |
17519 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17520 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17521 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17522 | allocator = expr.value; |
17523 | allocator = c_fully_fold (allocator, false, NULL); |
17524 | orig_type = expr.original_type |
17525 | ? expr.original_type : TREE_TYPE (allocator); |
17526 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
17527 | } |
17528 | if (allocator |
17529 | && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) |
17530 | || TREE_CODE (orig_type) != ENUMERAL_TYPE |
17531 | || (TYPE_NAME (orig_type) |
17532 | != get_identifier ("omp_allocator_handle_t" )))) |
17533 | { |
17534 | error_at (clause_loc, "%<allocate%> clause allocator expression " |
17535 | "has type %qT rather than " |
17536 | "%<omp_allocator_handle_t%>" , |
17537 | TREE_TYPE (allocator)); |
17538 | allocator = NULL_TREE; |
17539 | } |
17540 | if (align |
17541 | && (!INTEGRAL_TYPE_P (TREE_TYPE (align)) |
17542 | || !tree_fits_uhwi_p (align) |
17543 | || !integer_pow2p (align))) |
17544 | { |
17545 | error_at (clause_loc, "%<allocate%> clause %<align%> modifier " |
17546 | "argument needs to be positive constant " |
17547 | "power of two integer expression" ); |
17548 | align = NULL_TREE; |
17549 | } |
17550 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
17551 | { |
17552 | parens.skip_until_found_close (parser); |
17553 | return list; |
17554 | } |
17555 | } |
17556 | |
17557 | nl = c_parser_omp_variable_list (parser, clause_loc, |
17558 | kind: OMP_CLAUSE_ALLOCATE, list); |
17559 | |
17560 | if (allocator || align) |
17561 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
17562 | { |
17563 | OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; |
17564 | OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; |
17565 | } |
17566 | |
17567 | parens.skip_until_found_close (parser); |
17568 | return nl; |
17569 | } |
17570 | |
17571 | /* OpenMP 4.0: |
17572 | linear ( variable-list ) |
17573 | linear ( variable-list : expression ) |
17574 | |
17575 | OpenMP 4.5: |
17576 | linear ( modifier ( variable-list ) ) |
17577 | linear ( modifier ( variable-list ) : expression ) |
17578 | |
17579 | modifier: |
17580 | val |
17581 | |
17582 | OpenMP 5.2: |
17583 | linear ( variable-list : modifiers-list ) |
17584 | |
17585 | modifiers: |
17586 | val |
17587 | step ( expression ) */ |
17588 | |
17589 | static tree |
17590 | c_parser_omp_clause_linear (c_parser *parser, tree list) |
17591 | { |
17592 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17593 | tree nl, c, step; |
17594 | enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; |
17595 | bool old_linear_modifier = false; |
17596 | |
17597 | matching_parens parens; |
17598 | if (!parens.require_open (parser)) |
17599 | return list; |
17600 | |
17601 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
17602 | { |
17603 | c_token *tok = c_parser_peek_token (parser); |
17604 | const char *p = IDENTIFIER_POINTER (tok->value); |
17605 | if (strcmp (s1: "val" , s2: p) == 0) |
17606 | kind = OMP_CLAUSE_LINEAR_VAL; |
17607 | if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN) |
17608 | kind = OMP_CLAUSE_LINEAR_DEFAULT; |
17609 | if (kind != OMP_CLAUSE_LINEAR_DEFAULT) |
17610 | { |
17611 | old_linear_modifier = true; |
17612 | c_parser_consume_token (parser); |
17613 | c_parser_consume_token (parser); |
17614 | } |
17615 | } |
17616 | |
17617 | nl = c_parser_omp_variable_list (parser, clause_loc, |
17618 | kind: OMP_CLAUSE_LINEAR, list); |
17619 | |
17620 | if (kind != OMP_CLAUSE_LINEAR_DEFAULT) |
17621 | parens.skip_until_found_close (parser); |
17622 | |
17623 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
17624 | { |
17625 | c_parser_consume_token (parser); |
17626 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17627 | bool has_modifiers = false; |
17628 | if (kind == OMP_CLAUSE_LINEAR_DEFAULT |
17629 | && c_parser_next_token_is (parser, type: CPP_NAME)) |
17630 | { |
17631 | c_token *tok = c_parser_peek_token (parser); |
17632 | const char *p = IDENTIFIER_POINTER (tok->value); |
17633 | unsigned int pos = 0; |
17634 | if (strcmp (s1: "val" , s2: p) == 0) |
17635 | pos = 2; |
17636 | else if (strcmp (s1: "step" , s2: p) == 0 |
17637 | && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
17638 | { |
17639 | pos = 3; |
17640 | if (c_parser_check_balanced_raw_token_sequence (parser, n: &pos) |
17641 | && (c_parser_peek_nth_token_raw (parser, n: pos)->type |
17642 | == CPP_CLOSE_PAREN)) |
17643 | ++pos; |
17644 | else |
17645 | pos = 0; |
17646 | } |
17647 | if (pos) |
17648 | { |
17649 | tok = c_parser_peek_nth_token_raw (parser, n: pos); |
17650 | if (tok->type == CPP_COMMA || tok->type == CPP_CLOSE_PAREN) |
17651 | has_modifiers = true; |
17652 | } |
17653 | } |
17654 | if (has_modifiers) |
17655 | { |
17656 | step = NULL_TREE; |
17657 | while (c_parser_next_token_is (parser, type: CPP_NAME)) |
17658 | { |
17659 | c_token *tok = c_parser_peek_token (parser); |
17660 | const char *p = IDENTIFIER_POINTER (tok->value); |
17661 | if (strcmp (s1: "val" , s2: p) == 0) |
17662 | { |
17663 | if (kind != OMP_CLAUSE_LINEAR_DEFAULT) |
17664 | error_at (tok->location, "multiple linear modifiers" ); |
17665 | kind = OMP_CLAUSE_LINEAR_DEFAULT; |
17666 | c_parser_consume_token (parser); |
17667 | } |
17668 | else if (strcmp (s1: "step" , s2: p) == 0) |
17669 | { |
17670 | c_parser_consume_token (parser); |
17671 | matching_parens parens2; |
17672 | if (parens2.require_open (parser)) |
17673 | { |
17674 | if (step) |
17675 | error_at (tok->location, |
17676 | "multiple %<step%> modifiers" ); |
17677 | expr_loc = c_parser_peek_token (parser)->location; |
17678 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17679 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, |
17680 | true); |
17681 | step = c_fully_fold (expr.value, false, NULL); |
17682 | if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) |
17683 | { |
17684 | error_at (clause_loc, "%<linear%> clause step " |
17685 | "expression must be integral" ); |
17686 | step = integer_one_node; |
17687 | } |
17688 | parens2.skip_until_found_close (parser); |
17689 | } |
17690 | else |
17691 | break; |
17692 | } |
17693 | else |
17694 | break; |
17695 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
17696 | { |
17697 | c_parser_consume_token (parser); |
17698 | continue; |
17699 | } |
17700 | break; |
17701 | } |
17702 | if (!step) |
17703 | step = integer_one_node; |
17704 | } |
17705 | else |
17706 | { |
17707 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17708 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17709 | step = c_fully_fold (expr.value, false, NULL); |
17710 | if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) |
17711 | { |
17712 | error_at (clause_loc, "%<linear%> clause step expression must " |
17713 | "be integral" ); |
17714 | step = integer_one_node; |
17715 | } |
17716 | } |
17717 | |
17718 | } |
17719 | else |
17720 | step = integer_one_node; |
17721 | |
17722 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
17723 | { |
17724 | OMP_CLAUSE_LINEAR_STEP (c) = step; |
17725 | OMP_CLAUSE_LINEAR_KIND (c) = kind; |
17726 | OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (c) = old_linear_modifier; |
17727 | } |
17728 | |
17729 | parens.skip_until_found_close (parser); |
17730 | return nl; |
17731 | } |
17732 | |
17733 | /* OpenMP 5.0: |
17734 | nontemporal ( variable-list ) */ |
17735 | |
17736 | static tree |
17737 | c_parser_omp_clause_nontemporal (c_parser *parser, tree list) |
17738 | { |
17739 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_NONTEMPORAL, list); |
17740 | } |
17741 | |
17742 | /* OpenMP 4.0: |
17743 | safelen ( constant-expression ) */ |
17744 | |
17745 | static tree |
17746 | c_parser_omp_clause_safelen (c_parser *parser, tree list) |
17747 | { |
17748 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17749 | tree c, t; |
17750 | |
17751 | matching_parens parens; |
17752 | if (!parens.require_open (parser)) |
17753 | return list; |
17754 | |
17755 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17756 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17757 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17758 | t = expr.value; |
17759 | t = c_fully_fold (t, false, NULL); |
17760 | if (TREE_CODE (t) != INTEGER_CST |
17761 | || !INTEGRAL_TYPE_P (TREE_TYPE (t)) |
17762 | || tree_int_cst_sgn (t) != 1) |
17763 | { |
17764 | error_at (clause_loc, "%<safelen%> clause expression must " |
17765 | "be positive constant integer expression" ); |
17766 | t = NULL_TREE; |
17767 | } |
17768 | |
17769 | parens.skip_until_found_close (parser); |
17770 | if (t == NULL_TREE || t == error_mark_node) |
17771 | return list; |
17772 | |
17773 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_SAFELEN, name: "safelen" ); |
17774 | |
17775 | c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); |
17776 | OMP_CLAUSE_SAFELEN_EXPR (c) = t; |
17777 | OMP_CLAUSE_CHAIN (c) = list; |
17778 | return c; |
17779 | } |
17780 | |
17781 | /* OpenMP 4.0: |
17782 | simdlen ( constant-expression ) */ |
17783 | |
17784 | static tree |
17785 | c_parser_omp_clause_simdlen (c_parser *parser, tree list) |
17786 | { |
17787 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17788 | tree c, t; |
17789 | |
17790 | matching_parens parens; |
17791 | if (!parens.require_open (parser)) |
17792 | return list; |
17793 | |
17794 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17795 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17796 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17797 | t = expr.value; |
17798 | t = c_fully_fold (t, false, NULL); |
17799 | if (TREE_CODE (t) != INTEGER_CST |
17800 | || !INTEGRAL_TYPE_P (TREE_TYPE (t)) |
17801 | || tree_int_cst_sgn (t) != 1) |
17802 | { |
17803 | error_at (clause_loc, "%<simdlen%> clause expression must " |
17804 | "be positive constant integer expression" ); |
17805 | t = NULL_TREE; |
17806 | } |
17807 | |
17808 | parens.skip_until_found_close (parser); |
17809 | if (t == NULL_TREE || t == error_mark_node) |
17810 | return list; |
17811 | |
17812 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_SIMDLEN, name: "simdlen" ); |
17813 | |
17814 | c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); |
17815 | OMP_CLAUSE_SIMDLEN_EXPR (c) = t; |
17816 | OMP_CLAUSE_CHAIN (c) = list; |
17817 | return c; |
17818 | } |
17819 | |
17820 | /* OpenMP 4.5: |
17821 | vec: |
17822 | identifier [+/- integer] |
17823 | vec , identifier [+/- integer] |
17824 | */ |
17825 | |
17826 | static tree |
17827 | c_parser_omp_clause_doacross_sink (c_parser *parser, location_t clause_loc, |
17828 | tree list, bool depend_p) |
17829 | { |
17830 | tree vec = NULL; |
17831 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
17832 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
17833 | { |
17834 | c_parser_error (parser, gmsgid: "expected identifier" ); |
17835 | return list; |
17836 | } |
17837 | |
17838 | if (!depend_p) |
17839 | { |
17840 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17841 | if (strcmp (s1: p, s2: "omp_cur_iteration" ) == 0 |
17842 | && c_parser_peek_2nd_token (parser)->type == CPP_MINUS |
17843 | && c_parser_peek_nth_token (parser, n: 3)->type == CPP_NUMBER |
17844 | && c_parser_peek_nth_token (parser, n: 4)->type == CPP_CLOSE_PAREN) |
17845 | { |
17846 | tree val = c_parser_peek_nth_token (parser, n: 3)->value; |
17847 | if (integer_onep (val)) |
17848 | { |
17849 | c_parser_consume_token (parser); |
17850 | c_parser_consume_token (parser); |
17851 | c_parser_consume_token (parser); |
17852 | tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
17853 | OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; |
17854 | OMP_CLAUSE_CHAIN (u) = list; |
17855 | return u; |
17856 | } |
17857 | } |
17858 | } |
17859 | |
17860 | |
17861 | |
17862 | while (c_parser_next_token_is (parser, type: CPP_NAME) |
17863 | && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
17864 | { |
17865 | tree t = lookup_name (c_parser_peek_token (parser)->value); |
17866 | tree addend = NULL; |
17867 | |
17868 | if (t == NULL_TREE) |
17869 | { |
17870 | undeclared_variable (c_parser_peek_token (parser)->location, |
17871 | c_parser_peek_token (parser)->value); |
17872 | t = error_mark_node; |
17873 | } |
17874 | |
17875 | c_parser_consume_token (parser); |
17876 | |
17877 | bool neg = false; |
17878 | if (c_parser_next_token_is (parser, type: CPP_MINUS)) |
17879 | neg = true; |
17880 | else if (!c_parser_next_token_is (parser, type: CPP_PLUS)) |
17881 | { |
17882 | addend = integer_zero_node; |
17883 | neg = false; |
17884 | goto add_to_vector; |
17885 | } |
17886 | c_parser_consume_token (parser); |
17887 | |
17888 | if (c_parser_next_token_is_not (parser, type: CPP_NUMBER)) |
17889 | { |
17890 | c_parser_error (parser, gmsgid: "expected integer" ); |
17891 | return list; |
17892 | } |
17893 | |
17894 | addend = c_parser_peek_token (parser)->value; |
17895 | if (TREE_CODE (addend) != INTEGER_CST) |
17896 | { |
17897 | c_parser_error (parser, gmsgid: "expected integer" ); |
17898 | return list; |
17899 | } |
17900 | c_parser_consume_token (parser); |
17901 | |
17902 | add_to_vector: |
17903 | if (t != error_mark_node) |
17904 | { |
17905 | vec = tree_cons (addend, t, vec); |
17906 | if (neg) |
17907 | OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1; |
17908 | } |
17909 | |
17910 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA) |
17911 | || c_parser_peek_2nd_token (parser)->type != CPP_NAME |
17912 | || c_parser_peek_2nd_token (parser)->id_kind != C_ID_ID) |
17913 | break; |
17914 | |
17915 | c_parser_consume_token (parser); |
17916 | } |
17917 | |
17918 | if (vec == NULL_TREE) |
17919 | return list; |
17920 | |
17921 | tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
17922 | OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; |
17923 | OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p; |
17924 | OMP_CLAUSE_DECL (u) = nreverse (vec); |
17925 | OMP_CLAUSE_CHAIN (u) = list; |
17926 | return u; |
17927 | } |
17928 | |
17929 | /* OpenMP 5.0: |
17930 | iterators ( iterators-definition ) |
17931 | |
17932 | iterators-definition: |
17933 | iterator-specifier |
17934 | iterator-specifier , iterators-definition |
17935 | |
17936 | iterator-specifier: |
17937 | identifier = range-specification |
17938 | iterator-type identifier = range-specification |
17939 | |
17940 | range-specification: |
17941 | begin : end |
17942 | begin : end : step */ |
17943 | |
17944 | static tree |
17945 | c_parser_omp_iterators (c_parser *parser) |
17946 | { |
17947 | tree ret = NULL_TREE, *last = &ret; |
17948 | c_parser_consume_token (parser); |
17949 | |
17950 | push_scope (); |
17951 | |
17952 | matching_parens parens; |
17953 | if (!parens.require_open (parser)) |
17954 | return error_mark_node; |
17955 | |
17956 | do |
17957 | { |
17958 | tree iter_type = NULL_TREE, type_expr = NULL_TREE; |
17959 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
17960 | { |
17961 | struct c_type_name *type = c_parser_type_name (parser); |
17962 | if (type != NULL) |
17963 | iter_type = groktypename (type, &type_expr, NULL); |
17964 | } |
17965 | if (iter_type == NULL_TREE) |
17966 | iter_type = integer_type_node; |
17967 | |
17968 | location_t loc = c_parser_peek_token (parser)->location; |
17969 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
17970 | { |
17971 | c_parser_error (parser, gmsgid: "expected identifier" ); |
17972 | break; |
17973 | } |
17974 | |
17975 | tree id = c_parser_peek_token (parser)->value; |
17976 | c_parser_consume_token (parser); |
17977 | |
17978 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
17979 | break; |
17980 | |
17981 | location_t eloc = c_parser_peek_token (parser)->location; |
17982 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17983 | expr = convert_lvalue_to_rvalue (eloc, expr, true, false); |
17984 | tree begin = expr.value; |
17985 | |
17986 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
17987 | break; |
17988 | |
17989 | eloc = c_parser_peek_token (parser)->location; |
17990 | expr = c_parser_expr_no_commas (parser, NULL); |
17991 | expr = convert_lvalue_to_rvalue (eloc, expr, true, false); |
17992 | tree end = expr.value; |
17993 | |
17994 | tree step = integer_one_node; |
17995 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
17996 | { |
17997 | c_parser_consume_token (parser); |
17998 | eloc = c_parser_peek_token (parser)->location; |
17999 | expr = c_parser_expr_no_commas (parser, NULL); |
18000 | expr = convert_lvalue_to_rvalue (eloc, expr, true, false); |
18001 | step = expr.value; |
18002 | } |
18003 | |
18004 | tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); |
18005 | DECL_ARTIFICIAL (iter_var) = 1; |
18006 | DECL_CONTEXT (iter_var) = current_function_decl; |
18007 | pushdecl (iter_var); |
18008 | |
18009 | *last = make_tree_vec (6); |
18010 | TREE_VEC_ELT (*last, 0) = iter_var; |
18011 | TREE_VEC_ELT (*last, 1) = begin; |
18012 | TREE_VEC_ELT (*last, 2) = end; |
18013 | TREE_VEC_ELT (*last, 3) = step; |
18014 | last = &TREE_CHAIN (*last); |
18015 | |
18016 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
18017 | { |
18018 | c_parser_consume_token (parser); |
18019 | continue; |
18020 | } |
18021 | break; |
18022 | } |
18023 | while (1); |
18024 | |
18025 | parens.skip_until_found_close (parser); |
18026 | return ret ? ret : error_mark_node; |
18027 | } |
18028 | |
18029 | /* OpenMP 5.0: |
18030 | affinity ( [aff-modifier :] variable-list ) |
18031 | aff-modifier: |
18032 | iterator ( iterators-definition ) */ |
18033 | |
18034 | static tree |
18035 | c_parser_omp_clause_affinity (c_parser *parser, tree list) |
18036 | { |
18037 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18038 | tree nl, iterators = NULL_TREE; |
18039 | |
18040 | matching_parens parens; |
18041 | if (!parens.require_open (parser)) |
18042 | return list; |
18043 | |
18044 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
18045 | { |
18046 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18047 | bool parse_iter = ((strcmp (s1: "iterator" , s2: p) == 0) |
18048 | && (c_parser_peek_2nd_token (parser)->type |
18049 | == CPP_OPEN_PAREN)); |
18050 | if (parse_iter) |
18051 | { |
18052 | unsigned n = 3; |
18053 | parse_iter = (c_parser_check_balanced_raw_token_sequence (parser, n: &n) |
18054 | && (c_parser_peek_nth_token_raw (parser, n)->type |
18055 | == CPP_CLOSE_PAREN) |
18056 | && (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
18057 | == CPP_COLON)); |
18058 | } |
18059 | if (parse_iter) |
18060 | { |
18061 | iterators = c_parser_omp_iterators (parser); |
18062 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18063 | { |
18064 | if (iterators) |
18065 | pop_scope (); |
18066 | parens.skip_until_found_close (parser); |
18067 | return list; |
18068 | } |
18069 | } |
18070 | } |
18071 | nl = c_parser_omp_variable_list (parser, clause_loc, kind: OMP_CLAUSE_AFFINITY, |
18072 | list); |
18073 | if (iterators) |
18074 | { |
18075 | tree block = pop_scope (); |
18076 | if (iterators != error_mark_node) |
18077 | { |
18078 | TREE_VEC_ELT (iterators, 5) = block; |
18079 | for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18080 | OMP_CLAUSE_DECL (c) = build_tree_list (iterators, |
18081 | OMP_CLAUSE_DECL (c)); |
18082 | } |
18083 | } |
18084 | |
18085 | parens.skip_until_found_close (parser); |
18086 | return nl; |
18087 | } |
18088 | |
18089 | |
18090 | /* OpenMP 4.0: |
18091 | depend ( depend-kind: variable-list ) |
18092 | |
18093 | depend-kind: |
18094 | in | out | inout |
18095 | |
18096 | OpenMP 4.5: |
18097 | depend ( source ) |
18098 | |
18099 | depend ( sink : vec ) |
18100 | |
18101 | OpenMP 5.0: |
18102 | depend ( depend-modifier , depend-kind: variable-list ) |
18103 | |
18104 | depend-kind: |
18105 | in | out | inout | mutexinoutset | depobj | inoutset |
18106 | |
18107 | depend-modifier: |
18108 | iterator ( iterators-definition ) */ |
18109 | |
18110 | static tree |
18111 | c_parser_omp_clause_depend (c_parser *parser, tree list) |
18112 | { |
18113 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18114 | enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; |
18115 | enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST; |
18116 | tree nl, c, iterators = NULL_TREE; |
18117 | |
18118 | matching_parens parens; |
18119 | if (!parens.require_open (parser)) |
18120 | return list; |
18121 | |
18122 | do |
18123 | { |
18124 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
18125 | goto invalid_kind; |
18126 | |
18127 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18128 | if (strcmp (s1: "iterator" , s2: p) == 0 && iterators == NULL_TREE) |
18129 | { |
18130 | iterators = c_parser_omp_iterators (parser); |
18131 | c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" ); |
18132 | continue; |
18133 | } |
18134 | if (strcmp (s1: "in" , s2: p) == 0) |
18135 | kind = OMP_CLAUSE_DEPEND_IN; |
18136 | else if (strcmp (s1: "inout" , s2: p) == 0) |
18137 | kind = OMP_CLAUSE_DEPEND_INOUT; |
18138 | else if (strcmp (s1: "inoutset" , s2: p) == 0) |
18139 | kind = OMP_CLAUSE_DEPEND_INOUTSET; |
18140 | else if (strcmp (s1: "mutexinoutset" , s2: p) == 0) |
18141 | kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; |
18142 | else if (strcmp (s1: "out" , s2: p) == 0) |
18143 | kind = OMP_CLAUSE_DEPEND_OUT; |
18144 | else if (strcmp (s1: "depobj" , s2: p) == 0) |
18145 | kind = OMP_CLAUSE_DEPEND_DEPOBJ; |
18146 | else if (strcmp (s1: "sink" , s2: p) == 0) |
18147 | dkind = OMP_CLAUSE_DOACROSS_SINK; |
18148 | else if (strcmp (s1: "source" , s2: p) == 0) |
18149 | dkind = OMP_CLAUSE_DOACROSS_SOURCE; |
18150 | else |
18151 | goto invalid_kind; |
18152 | break; |
18153 | } |
18154 | while (1); |
18155 | |
18156 | c_parser_consume_token (parser); |
18157 | |
18158 | if (iterators |
18159 | && (dkind == OMP_CLAUSE_DOACROSS_SOURCE |
18160 | || dkind == OMP_CLAUSE_DOACROSS_SINK)) |
18161 | { |
18162 | pop_scope (); |
18163 | error_at (clause_loc, "%<iterator%> modifier incompatible with %qs" , |
18164 | dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink" ); |
18165 | iterators = NULL_TREE; |
18166 | } |
18167 | |
18168 | if (dkind == OMP_CLAUSE_DOACROSS_SOURCE) |
18169 | { |
18170 | c = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
18171 | OMP_CLAUSE_DOACROSS_KIND (c) = dkind; |
18172 | OMP_CLAUSE_DOACROSS_DEPEND (c) = 1; |
18173 | OMP_CLAUSE_DECL (c) = NULL_TREE; |
18174 | OMP_CLAUSE_CHAIN (c) = list; |
18175 | parens.skip_until_found_close (parser); |
18176 | return c; |
18177 | } |
18178 | |
18179 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18180 | goto resync_fail; |
18181 | |
18182 | if (dkind == OMP_CLAUSE_DOACROSS_SINK) |
18183 | nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, depend_p: true); |
18184 | else |
18185 | { |
18186 | nl = c_parser_omp_variable_list (parser, clause_loc, |
18187 | kind: OMP_CLAUSE_DEPEND, list); |
18188 | |
18189 | if (iterators) |
18190 | { |
18191 | tree block = pop_scope (); |
18192 | if (iterators == error_mark_node) |
18193 | iterators = NULL_TREE; |
18194 | else |
18195 | TREE_VEC_ELT (iterators, 5) = block; |
18196 | } |
18197 | |
18198 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18199 | { |
18200 | OMP_CLAUSE_DEPEND_KIND (c) = kind; |
18201 | if (iterators) |
18202 | OMP_CLAUSE_DECL (c) |
18203 | = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); |
18204 | } |
18205 | } |
18206 | |
18207 | parens.skip_until_found_close (parser); |
18208 | return nl; |
18209 | |
18210 | invalid_kind: |
18211 | c_parser_error (parser, gmsgid: "invalid depend kind" ); |
18212 | resync_fail: |
18213 | parens.skip_until_found_close (parser); |
18214 | if (iterators) |
18215 | pop_scope (); |
18216 | return list; |
18217 | } |
18218 | |
18219 | /* OpenMP 5.2: |
18220 | doacross ( source : ) |
18221 | doacross ( source : omp_cur_iteration ) |
18222 | |
18223 | doacross ( sink : vec ) |
18224 | doacross ( sink : omp_cur_iteration - logical_iteration ) */ |
18225 | |
18226 | static tree |
18227 | c_parser_omp_clause_doacross (c_parser *parser, tree list) |
18228 | { |
18229 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18230 | enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST; |
18231 | tree nl; |
18232 | const char *p; |
18233 | |
18234 | matching_parens parens; |
18235 | if (!parens.require_open (parser)) |
18236 | return list; |
18237 | |
18238 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
18239 | goto invalid_kind; |
18240 | |
18241 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18242 | if (strcmp (s1: "sink" , s2: p) == 0) |
18243 | kind = OMP_CLAUSE_DOACROSS_SINK; |
18244 | else if (strcmp (s1: "source" , s2: p) == 0) |
18245 | kind = OMP_CLAUSE_DOACROSS_SOURCE; |
18246 | else |
18247 | goto invalid_kind; |
18248 | |
18249 | c_parser_consume_token (parser); |
18250 | |
18251 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18252 | goto resync_fail; |
18253 | |
18254 | if (kind == OMP_CLAUSE_DOACROSS_SOURCE) |
18255 | { |
18256 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
18257 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
18258 | s2: "omp_cur_iteration" ) == 0) |
18259 | c_parser_consume_token (parser); |
18260 | nl = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
18261 | OMP_CLAUSE_DOACROSS_KIND (nl) = OMP_CLAUSE_DOACROSS_SOURCE; |
18262 | OMP_CLAUSE_DECL (nl) = NULL_TREE; |
18263 | OMP_CLAUSE_CHAIN (nl) = list; |
18264 | } |
18265 | else |
18266 | nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, depend_p: false); |
18267 | |
18268 | parens.skip_until_found_close (parser); |
18269 | return nl; |
18270 | |
18271 | invalid_kind: |
18272 | c_parser_error (parser, gmsgid: "invalid doacross kind" ); |
18273 | resync_fail: |
18274 | parens.skip_until_found_close (parser); |
18275 | return list; |
18276 | } |
18277 | |
18278 | /* OpenMP 4.0: |
18279 | map ( map-kind: variable-list ) |
18280 | map ( variable-list ) |
18281 | |
18282 | map-kind: |
18283 | alloc | to | from | tofrom |
18284 | |
18285 | OpenMP 4.5: |
18286 | map-kind: |
18287 | alloc | to | from | tofrom | release | delete |
18288 | |
18289 | map ( always [,] map-kind: variable-list ) |
18290 | |
18291 | OpenMP 5.0: |
18292 | map ( [map-type-modifier[,] ...] map-kind: variable-list ) |
18293 | |
18294 | map-type-modifier: |
18295 | always | close */ |
18296 | |
18297 | static tree |
18298 | c_parser_omp_clause_map (c_parser *parser, tree list) |
18299 | { |
18300 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18301 | enum gomp_map_kind kind = GOMP_MAP_TOFROM; |
18302 | tree nl, c; |
18303 | |
18304 | matching_parens parens; |
18305 | if (!parens.require_open (parser)) |
18306 | return list; |
18307 | |
18308 | int pos = 1; |
18309 | int map_kind_pos = 0; |
18310 | while (c_parser_peek_nth_token_raw (parser, n: pos)->type == CPP_NAME) |
18311 | { |
18312 | if (c_parser_peek_nth_token_raw (parser, n: pos + 1)->type == CPP_COLON) |
18313 | { |
18314 | map_kind_pos = pos; |
18315 | break; |
18316 | } |
18317 | |
18318 | if (c_parser_peek_nth_token_raw (parser, n: pos + 1)->type == CPP_COMMA) |
18319 | pos++; |
18320 | pos++; |
18321 | } |
18322 | |
18323 | int always_modifier = 0; |
18324 | int close_modifier = 0; |
18325 | int present_modifier = 0; |
18326 | for (int pos = 1; pos < map_kind_pos; ++pos) |
18327 | { |
18328 | c_token *tok = c_parser_peek_token (parser); |
18329 | |
18330 | if (tok->type == CPP_COMMA) |
18331 | { |
18332 | c_parser_consume_token (parser); |
18333 | continue; |
18334 | } |
18335 | |
18336 | const char *p = IDENTIFIER_POINTER (tok->value); |
18337 | if (strcmp (s1: "always" , s2: p) == 0) |
18338 | { |
18339 | if (always_modifier) |
18340 | { |
18341 | c_parser_error (parser, gmsgid: "too many %<always%> modifiers" ); |
18342 | parens.skip_until_found_close (parser); |
18343 | return list; |
18344 | } |
18345 | always_modifier++; |
18346 | } |
18347 | else if (strcmp (s1: "close" , s2: p) == 0) |
18348 | { |
18349 | if (close_modifier) |
18350 | { |
18351 | c_parser_error (parser, gmsgid: "too many %<close%> modifiers" ); |
18352 | parens.skip_until_found_close (parser); |
18353 | return list; |
18354 | } |
18355 | close_modifier++; |
18356 | } |
18357 | else if (strcmp (s1: "present" , s2: p) == 0) |
18358 | { |
18359 | if (present_modifier) |
18360 | { |
18361 | c_parser_error (parser, gmsgid: "too many %<present%> modifiers" ); |
18362 | parens.skip_until_found_close (parser); |
18363 | return list; |
18364 | } |
18365 | present_modifier++; |
18366 | } |
18367 | else |
18368 | { |
18369 | c_parser_error (parser, gmsgid: "%<map%> clause with map-type modifier other " |
18370 | "than %<always%>, %<close%> or %<present%>" ); |
18371 | parens.skip_until_found_close (parser); |
18372 | return list; |
18373 | } |
18374 | |
18375 | c_parser_consume_token (parser); |
18376 | } |
18377 | |
18378 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
18379 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
18380 | { |
18381 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18382 | int always_present_modifier = always_modifier && present_modifier; |
18383 | |
18384 | if (strcmp (s1: "alloc" , s2: p) == 0) |
18385 | kind = present_modifier ? GOMP_MAP_PRESENT_ALLOC : GOMP_MAP_ALLOC; |
18386 | else if (strcmp (s1: "to" , s2: p) == 0) |
18387 | kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TO |
18388 | : present_modifier ? GOMP_MAP_PRESENT_TO |
18389 | : always_modifier ? GOMP_MAP_ALWAYS_TO |
18390 | : GOMP_MAP_TO); |
18391 | else if (strcmp (s1: "from" , s2: p) == 0) |
18392 | kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_FROM |
18393 | : present_modifier ? GOMP_MAP_PRESENT_FROM |
18394 | : always_modifier ? GOMP_MAP_ALWAYS_FROM |
18395 | : GOMP_MAP_FROM); |
18396 | else if (strcmp (s1: "tofrom" , s2: p) == 0) |
18397 | kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TOFROM |
18398 | : present_modifier ? GOMP_MAP_PRESENT_TOFROM |
18399 | : always_modifier ? GOMP_MAP_ALWAYS_TOFROM |
18400 | : GOMP_MAP_TOFROM); |
18401 | else if (strcmp (s1: "release" , s2: p) == 0) |
18402 | kind = GOMP_MAP_RELEASE; |
18403 | else if (strcmp (s1: "delete" , s2: p) == 0) |
18404 | kind = GOMP_MAP_DELETE; |
18405 | else |
18406 | { |
18407 | c_parser_error (parser, gmsgid: "invalid map kind" ); |
18408 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
18409 | msgid: "expected %<)%>" ); |
18410 | return list; |
18411 | } |
18412 | c_parser_consume_token (parser); |
18413 | c_parser_consume_token (parser); |
18414 | } |
18415 | |
18416 | nl = c_parser_omp_variable_list (parser, clause_loc, kind: OMP_CLAUSE_MAP, list, |
18417 | allow_deref: true); |
18418 | |
18419 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18420 | OMP_CLAUSE_SET_MAP_KIND (c, kind); |
18421 | |
18422 | parens.skip_until_found_close (parser); |
18423 | return nl; |
18424 | } |
18425 | |
18426 | /* OpenMP 4.0: |
18427 | device ( expression ) |
18428 | |
18429 | OpenMP 5.0: |
18430 | device ( [device-modifier :] integer-expression ) |
18431 | |
18432 | device-modifier: |
18433 | ancestor | device_num */ |
18434 | |
18435 | static tree |
18436 | c_parser_omp_clause_device (c_parser *parser, tree list) |
18437 | { |
18438 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18439 | location_t expr_loc; |
18440 | c_expr expr; |
18441 | tree c, t; |
18442 | bool ancestor = false; |
18443 | |
18444 | matching_parens parens; |
18445 | if (!parens.require_open (parser)) |
18446 | return list; |
18447 | |
18448 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
18449 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
18450 | { |
18451 | c_token *tok = c_parser_peek_token (parser); |
18452 | const char *p = IDENTIFIER_POINTER (tok->value); |
18453 | if (strcmp (s1: "ancestor" , s2: p) == 0) |
18454 | { |
18455 | /* A requires directive with the reverse_offload clause must be |
18456 | specified. */ |
18457 | if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) |
18458 | { |
18459 | error_at (tok->location, "%<ancestor%> device modifier not " |
18460 | "preceded by %<requires%> directive " |
18461 | "with %<reverse_offload%> clause" ); |
18462 | parens.skip_until_found_close (parser); |
18463 | return list; |
18464 | } |
18465 | ancestor = true; |
18466 | } |
18467 | else if (strcmp (s1: "device_num" , s2: p) == 0) |
18468 | ; |
18469 | else |
18470 | { |
18471 | error_at (tok->location, "expected %<ancestor%> or %<device_num%>" ); |
18472 | parens.skip_until_found_close (parser); |
18473 | return list; |
18474 | } |
18475 | c_parser_consume_token (parser); |
18476 | c_parser_consume_token (parser); |
18477 | } |
18478 | |
18479 | expr_loc = c_parser_peek_token (parser)->location; |
18480 | expr = c_parser_expr_no_commas (parser, NULL); |
18481 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18482 | t = expr.value; |
18483 | t = c_fully_fold (t, false, NULL); |
18484 | |
18485 | parens.skip_until_found_close (parser); |
18486 | |
18487 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
18488 | { |
18489 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
18490 | return list; |
18491 | } |
18492 | if (ancestor && TREE_CODE (t) == INTEGER_CST && !integer_onep (t)) |
18493 | { |
18494 | error_at (expr_loc, "the %<device%> clause expression must evaluate to " |
18495 | "%<1%>" ); |
18496 | return list; |
18497 | } |
18498 | |
18499 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_DEVICE, name: "device" ); |
18500 | |
18501 | c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); |
18502 | |
18503 | OMP_CLAUSE_DEVICE_ID (c) = t; |
18504 | OMP_CLAUSE_CHAIN (c) = list; |
18505 | OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; |
18506 | |
18507 | list = c; |
18508 | return list; |
18509 | } |
18510 | |
18511 | /* OpenMP 4.0: |
18512 | dist_schedule ( static ) |
18513 | dist_schedule ( static , expression ) */ |
18514 | |
18515 | static tree |
18516 | c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) |
18517 | { |
18518 | tree c, t = NULL_TREE; |
18519 | location_t loc = c_parser_peek_token (parser)->location; |
18520 | |
18521 | matching_parens parens; |
18522 | if (!parens.require_open (parser)) |
18523 | return list; |
18524 | |
18525 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_STATIC)) |
18526 | { |
18527 | c_parser_error (parser, gmsgid: "invalid dist_schedule kind" ); |
18528 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
18529 | msgid: "expected %<)%>" ); |
18530 | return list; |
18531 | } |
18532 | |
18533 | c_parser_consume_token (parser); |
18534 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
18535 | { |
18536 | c_parser_consume_token (parser); |
18537 | |
18538 | location_t expr_loc = c_parser_peek_token (parser)->location; |
18539 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18540 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18541 | t = expr.value; |
18542 | t = c_fully_fold (t, false, NULL); |
18543 | parens.skip_until_found_close (parser); |
18544 | } |
18545 | else |
18546 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
18547 | msgid: "expected %<,%> or %<)%>" ); |
18548 | |
18549 | /* check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, |
18550 | "dist_schedule"); */ |
18551 | if (omp_find_clause (clauses: list, kind: OMP_CLAUSE_DIST_SCHEDULE)) |
18552 | warning_at (loc, 0, "too many %qs clauses" , "dist_schedule" ); |
18553 | if (t == error_mark_node) |
18554 | return list; |
18555 | |
18556 | c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); |
18557 | OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; |
18558 | OMP_CLAUSE_CHAIN (c) = list; |
18559 | return c; |
18560 | } |
18561 | |
18562 | /* OpenMP 4.0: |
18563 | proc_bind ( proc-bind-kind ) |
18564 | |
18565 | proc-bind-kind: |
18566 | primary | master | close | spread |
18567 | where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ |
18568 | |
18569 | static tree |
18570 | c_parser_omp_clause_proc_bind (c_parser *parser, tree list) |
18571 | { |
18572 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18573 | enum omp_clause_proc_bind_kind kind; |
18574 | tree c; |
18575 | |
18576 | matching_parens parens; |
18577 | if (!parens.require_open (parser)) |
18578 | return list; |
18579 | |
18580 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
18581 | { |
18582 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18583 | if (strcmp (s1: "primary" , s2: p) == 0) |
18584 | kind = OMP_CLAUSE_PROC_BIND_PRIMARY; |
18585 | else if (strcmp (s1: "master" , s2: p) == 0) |
18586 | kind = OMP_CLAUSE_PROC_BIND_MASTER; |
18587 | else if (strcmp (s1: "close" , s2: p) == 0) |
18588 | kind = OMP_CLAUSE_PROC_BIND_CLOSE; |
18589 | else if (strcmp (s1: "spread" , s2: p) == 0) |
18590 | kind = OMP_CLAUSE_PROC_BIND_SPREAD; |
18591 | else |
18592 | goto invalid_kind; |
18593 | } |
18594 | else |
18595 | goto invalid_kind; |
18596 | |
18597 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_PROC_BIND, name: "proc_bind" ); |
18598 | c_parser_consume_token (parser); |
18599 | parens.skip_until_found_close (parser); |
18600 | c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); |
18601 | OMP_CLAUSE_PROC_BIND_KIND (c) = kind; |
18602 | OMP_CLAUSE_CHAIN (c) = list; |
18603 | return c; |
18604 | |
18605 | invalid_kind: |
18606 | c_parser_error (parser, gmsgid: "invalid proc_bind kind" ); |
18607 | parens.skip_until_found_close (parser); |
18608 | return list; |
18609 | } |
18610 | |
18611 | /* OpenMP 5.0: |
18612 | device_type ( host | nohost | any ) */ |
18613 | |
18614 | static tree |
18615 | c_parser_omp_clause_device_type (c_parser *parser, tree list) |
18616 | { |
18617 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18618 | enum omp_clause_device_type_kind kind; |
18619 | tree c; |
18620 | |
18621 | matching_parens parens; |
18622 | if (!parens.require_open (parser)) |
18623 | return list; |
18624 | |
18625 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
18626 | { |
18627 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18628 | if (strcmp (s1: "host" , s2: p) == 0) |
18629 | kind = OMP_CLAUSE_DEVICE_TYPE_HOST; |
18630 | else if (strcmp (s1: "nohost" , s2: p) == 0) |
18631 | kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST; |
18632 | else if (strcmp (s1: "any" , s2: p) == 0) |
18633 | kind = OMP_CLAUSE_DEVICE_TYPE_ANY; |
18634 | else |
18635 | goto invalid_kind; |
18636 | } |
18637 | else |
18638 | goto invalid_kind; |
18639 | |
18640 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_DEVICE_TYPE, |
18641 | name: "device_type" ); |
18642 | c_parser_consume_token (parser); |
18643 | parens.skip_until_found_close (parser); |
18644 | c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE); |
18645 | OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind; |
18646 | OMP_CLAUSE_CHAIN (c) = list; |
18647 | return c; |
18648 | |
18649 | invalid_kind: |
18650 | c_parser_error (parser, gmsgid: "expected %<host%>, %<nohost%> or %<any%>" ); |
18651 | parens.skip_until_found_close (parser); |
18652 | return list; |
18653 | } |
18654 | |
18655 | /* OpenMP 4.0: |
18656 | from ( variable-list ) |
18657 | to ( variable-list ) |
18658 | |
18659 | OpenMP 5.1: |
18660 | from ( [present :] variable-list ) |
18661 | to ( [present :] variable-list ) */ |
18662 | |
18663 | static tree |
18664 | c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, |
18665 | tree list) |
18666 | { |
18667 | location_t loc = c_parser_peek_token (parser)->location; |
18668 | matching_parens parens; |
18669 | if (!parens.require_open (parser)) |
18670 | return list; |
18671 | |
18672 | bool present = false; |
18673 | c_token *token = c_parser_peek_token (parser); |
18674 | |
18675 | if (token->type == CPP_NAME |
18676 | && strcmp (IDENTIFIER_POINTER (token->value), s2: "present" ) == 0 |
18677 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
18678 | { |
18679 | present = true; |
18680 | c_parser_consume_token (parser); |
18681 | c_parser_consume_token (parser); |
18682 | } |
18683 | |
18684 | tree nl = c_parser_omp_variable_list (parser, clause_loc: loc, kind, list); |
18685 | parens.skip_until_found_close (parser); |
18686 | |
18687 | if (present) |
18688 | for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18689 | OMP_CLAUSE_MOTION_PRESENT (c) = 1; |
18690 | |
18691 | return nl; |
18692 | } |
18693 | |
18694 | /* OpenMP 4.0: |
18695 | uniform ( variable-list ) */ |
18696 | |
18697 | static tree |
18698 | c_parser_omp_clause_uniform (c_parser *parser, tree list) |
18699 | { |
18700 | /* The clauses location. */ |
18701 | location_t loc = c_parser_peek_token (parser)->location; |
18702 | |
18703 | matching_parens parens; |
18704 | if (parens.require_open (parser)) |
18705 | { |
18706 | list = c_parser_omp_variable_list (parser, clause_loc: loc, kind: OMP_CLAUSE_UNIFORM, |
18707 | list); |
18708 | parens.skip_until_found_close (parser); |
18709 | } |
18710 | return list; |
18711 | } |
18712 | |
18713 | /* OpenMP 5.0: |
18714 | detach ( event-handle ) */ |
18715 | |
18716 | static tree |
18717 | c_parser_omp_clause_detach (c_parser *parser, tree list) |
18718 | { |
18719 | matching_parens parens; |
18720 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18721 | |
18722 | if (!parens.require_open (parser)) |
18723 | return list; |
18724 | |
18725 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
18726 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
18727 | { |
18728 | c_parser_error (parser, gmsgid: "expected identifier" ); |
18729 | parens.skip_until_found_close (parser); |
18730 | return list; |
18731 | } |
18732 | |
18733 | tree t = lookup_name (c_parser_peek_token (parser)->value); |
18734 | if (t == NULL_TREE) |
18735 | { |
18736 | undeclared_variable (c_parser_peek_token (parser)->location, |
18737 | c_parser_peek_token (parser)->value); |
18738 | parens.skip_until_found_close (parser); |
18739 | return list; |
18740 | } |
18741 | c_parser_consume_token (parser); |
18742 | |
18743 | tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); |
18744 | if (!INTEGRAL_TYPE_P (type) |
18745 | || TREE_CODE (type) != ENUMERAL_TYPE |
18746 | || TYPE_NAME (type) != get_identifier ("omp_event_handle_t" )) |
18747 | { |
18748 | error_at (clause_loc, "%<detach%> clause event handle " |
18749 | "has type %qT rather than " |
18750 | "%<omp_event_handle_t%>" , |
18751 | type); |
18752 | parens.skip_until_found_close (parser); |
18753 | return list; |
18754 | } |
18755 | |
18756 | tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DETACH); |
18757 | OMP_CLAUSE_DECL (u) = t; |
18758 | OMP_CLAUSE_CHAIN (u) = list; |
18759 | parens.skip_until_found_close (parser); |
18760 | return u; |
18761 | } |
18762 | |
18763 | /* Parse all OpenACC clauses. The set clauses allowed by the directive |
18764 | is a bitmask in MASK. Return the list of clauses found. */ |
18765 | |
18766 | static tree |
18767 | c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, |
18768 | const char *where, bool finish_p = true) |
18769 | { |
18770 | tree clauses = NULL; |
18771 | bool first = true; |
18772 | |
18773 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
18774 | { |
18775 | location_t here; |
18776 | pragma_omp_clause c_kind; |
18777 | const char *c_name; |
18778 | tree prev = clauses; |
18779 | |
18780 | if (!first && c_parser_next_token_is (parser, type: CPP_COMMA)) |
18781 | c_parser_consume_token (parser); |
18782 | |
18783 | here = c_parser_peek_token (parser)->location; |
18784 | c_kind = c_parser_omp_clause_name (parser); |
18785 | |
18786 | switch (c_kind) |
18787 | { |
18788 | case PRAGMA_OACC_CLAUSE_ASYNC: |
18789 | clauses = c_parser_oacc_clause_async (parser, list: clauses); |
18790 | c_name = "async" ; |
18791 | break; |
18792 | case PRAGMA_OACC_CLAUSE_AUTO: |
18793 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_AUTO, |
18794 | list: clauses); |
18795 | c_name = "auto" ; |
18796 | break; |
18797 | case PRAGMA_OACC_CLAUSE_ATTACH: |
18798 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18799 | c_name = "attach" ; |
18800 | break; |
18801 | case PRAGMA_OACC_CLAUSE_COLLAPSE: |
18802 | clauses = c_parser_omp_clause_collapse (parser, list: clauses); |
18803 | c_name = "collapse" ; |
18804 | break; |
18805 | case PRAGMA_OACC_CLAUSE_COPY: |
18806 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18807 | c_name = "copy" ; |
18808 | break; |
18809 | case PRAGMA_OACC_CLAUSE_COPYIN: |
18810 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18811 | c_name = "copyin" ; |
18812 | break; |
18813 | case PRAGMA_OACC_CLAUSE_COPYOUT: |
18814 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18815 | c_name = "copyout" ; |
18816 | break; |
18817 | case PRAGMA_OACC_CLAUSE_CREATE: |
18818 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18819 | c_name = "create" ; |
18820 | break; |
18821 | case PRAGMA_OACC_CLAUSE_DELETE: |
18822 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18823 | c_name = "delete" ; |
18824 | break; |
18825 | case PRAGMA_OMP_CLAUSE_DEFAULT: |
18826 | clauses = c_parser_omp_clause_default (parser, list: clauses, is_oacc: true); |
18827 | c_name = "default" ; |
18828 | break; |
18829 | case PRAGMA_OACC_CLAUSE_DETACH: |
18830 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18831 | c_name = "detach" ; |
18832 | break; |
18833 | case PRAGMA_OACC_CLAUSE_DEVICE: |
18834 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18835 | c_name = "device" ; |
18836 | break; |
18837 | case PRAGMA_OACC_CLAUSE_DEVICEPTR: |
18838 | clauses = c_parser_oacc_data_clause_deviceptr (parser, list: clauses); |
18839 | c_name = "deviceptr" ; |
18840 | break; |
18841 | case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: |
18842 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18843 | c_name = "device_resident" ; |
18844 | break; |
18845 | case PRAGMA_OACC_CLAUSE_FINALIZE: |
18846 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_FINALIZE, |
18847 | list: clauses); |
18848 | c_name = "finalize" ; |
18849 | break; |
18850 | case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE: |
18851 | clauses = c_parser_omp_clause_firstprivate (parser, list: clauses); |
18852 | c_name = "firstprivate" ; |
18853 | break; |
18854 | case PRAGMA_OACC_CLAUSE_GANG: |
18855 | c_name = "gang" ; |
18856 | clauses = c_parser_oacc_shape_clause (parser, loc: here, kind: OMP_CLAUSE_GANG, |
18857 | str: c_name, list: clauses); |
18858 | break; |
18859 | case PRAGMA_OACC_CLAUSE_HOST: |
18860 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18861 | c_name = "host" ; |
18862 | break; |
18863 | case PRAGMA_OACC_CLAUSE_IF: |
18864 | clauses = c_parser_omp_clause_if (parser, list: clauses, is_omp: false); |
18865 | c_name = "if" ; |
18866 | break; |
18867 | case PRAGMA_OACC_CLAUSE_IF_PRESENT: |
18868 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_IF_PRESENT, |
18869 | list: clauses); |
18870 | c_name = "if_present" ; |
18871 | break; |
18872 | case PRAGMA_OACC_CLAUSE_INDEPENDENT: |
18873 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_INDEPENDENT, |
18874 | list: clauses); |
18875 | c_name = "independent" ; |
18876 | break; |
18877 | case PRAGMA_OACC_CLAUSE_LINK: |
18878 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18879 | c_name = "link" ; |
18880 | break; |
18881 | case PRAGMA_OACC_CLAUSE_NO_CREATE: |
18882 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18883 | c_name = "no_create" ; |
18884 | break; |
18885 | case PRAGMA_OACC_CLAUSE_NOHOST: |
18886 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_NOHOST, |
18887 | list: clauses); |
18888 | c_name = "nohost" ; |
18889 | break; |
18890 | case PRAGMA_OACC_CLAUSE_NUM_GANGS: |
18891 | clauses = c_parser_oacc_single_int_clause (parser, |
18892 | code: OMP_CLAUSE_NUM_GANGS, |
18893 | list: clauses); |
18894 | c_name = "num_gangs" ; |
18895 | break; |
18896 | case PRAGMA_OACC_CLAUSE_NUM_WORKERS: |
18897 | clauses = c_parser_oacc_single_int_clause (parser, |
18898 | code: OMP_CLAUSE_NUM_WORKERS, |
18899 | list: clauses); |
18900 | c_name = "num_workers" ; |
18901 | break; |
18902 | case PRAGMA_OACC_CLAUSE_PRESENT: |
18903 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18904 | c_name = "present" ; |
18905 | break; |
18906 | case PRAGMA_OACC_CLAUSE_PRIVATE: |
18907 | clauses = c_parser_omp_clause_private (parser, list: clauses); |
18908 | c_name = "private" ; |
18909 | break; |
18910 | case PRAGMA_OACC_CLAUSE_REDUCTION: |
18911 | clauses |
18912 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_REDUCTION, |
18913 | is_omp: false, list: clauses); |
18914 | c_name = "reduction" ; |
18915 | break; |
18916 | case PRAGMA_OACC_CLAUSE_SELF: |
18917 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST)) == 0) |
18918 | /* OpenACC compute construct */ |
18919 | clauses = c_parser_oacc_compute_clause_self (parser, list: clauses); |
18920 | else |
18921 | /* OpenACC 'update' directive */ |
18922 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
18923 | c_name = "self" ; |
18924 | break; |
18925 | case PRAGMA_OACC_CLAUSE_SEQ: |
18926 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_SEQ, |
18927 | list: clauses); |
18928 | c_name = "seq" ; |
18929 | break; |
18930 | case PRAGMA_OACC_CLAUSE_TILE: |
18931 | clauses = c_parser_oacc_clause_tile (parser, list: clauses); |
18932 | c_name = "tile" ; |
18933 | break; |
18934 | case PRAGMA_OACC_CLAUSE_USE_DEVICE: |
18935 | clauses = c_parser_omp_clause_use_device_ptr (parser, list: clauses); |
18936 | c_name = "use_device" ; |
18937 | break; |
18938 | case PRAGMA_OACC_CLAUSE_VECTOR: |
18939 | c_name = "vector" ; |
18940 | clauses = c_parser_oacc_shape_clause (parser, loc: here, kind: OMP_CLAUSE_VECTOR, |
18941 | str: c_name, list: clauses); |
18942 | break; |
18943 | case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH: |
18944 | clauses = c_parser_oacc_single_int_clause (parser, |
18945 | code: OMP_CLAUSE_VECTOR_LENGTH, |
18946 | list: clauses); |
18947 | c_name = "vector_length" ; |
18948 | break; |
18949 | case PRAGMA_OACC_CLAUSE_WAIT: |
18950 | clauses = c_parser_oacc_clause_wait (parser, list: clauses); |
18951 | c_name = "wait" ; |
18952 | break; |
18953 | case PRAGMA_OACC_CLAUSE_WORKER: |
18954 | c_name = "worker" ; |
18955 | clauses = c_parser_oacc_shape_clause (parser, loc: here, kind: OMP_CLAUSE_WORKER, |
18956 | str: c_name, list: clauses); |
18957 | break; |
18958 | default: |
18959 | c_parser_error (parser, gmsgid: "expected an OpenACC clause" ); |
18960 | goto saw_error; |
18961 | } |
18962 | |
18963 | first = false; |
18964 | |
18965 | if (((mask >> c_kind) & 1) == 0) |
18966 | { |
18967 | /* Remove the invalid clause(s) from the list to avoid |
18968 | confusing the rest of the compiler. */ |
18969 | clauses = prev; |
18970 | error_at (here, "%qs is not valid for %qs" , c_name, where); |
18971 | } |
18972 | } |
18973 | |
18974 | saw_error: |
18975 | c_parser_skip_to_pragma_eol (parser); |
18976 | |
18977 | if (finish_p) |
18978 | return c_finish_omp_clauses (clauses, C_ORT_ACC); |
18979 | |
18980 | return clauses; |
18981 | } |
18982 | |
18983 | /* Parse all OpenMP clauses. The set clauses allowed by the directive |
18984 | is a bitmask in MASK. Return the list of clauses found. |
18985 | FINISH_P set if c_finish_omp_clauses should be called. |
18986 | NESTED non-zero if clauses should be terminated by closing paren instead |
18987 | of end of pragma. If it is 2, additionally commas are required in between |
18988 | the clauses. */ |
18989 | |
18990 | static tree |
18991 | c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, |
18992 | const char *where, bool finish_p = true, |
18993 | int nested = 0) |
18994 | { |
18995 | tree clauses = NULL; |
18996 | bool first = true; |
18997 | |
18998 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
18999 | { |
19000 | location_t here; |
19001 | pragma_omp_clause c_kind; |
19002 | const char *c_name; |
19003 | tree prev = clauses; |
19004 | |
19005 | if (nested && c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
19006 | break; |
19007 | |
19008 | if (!first || nested != 2) |
19009 | { |
19010 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
19011 | c_parser_consume_token (parser); |
19012 | else if (nested == 2) |
19013 | error_at (c_parser_peek_token (parser)->location, |
19014 | "clauses in %<simd%> trait should be separated " |
19015 | "by %<,%>" ); |
19016 | } |
19017 | |
19018 | here = c_parser_peek_token (parser)->location; |
19019 | c_kind = c_parser_omp_clause_name (parser); |
19020 | |
19021 | switch (c_kind) |
19022 | { |
19023 | case PRAGMA_OMP_CLAUSE_BIND: |
19024 | clauses = c_parser_omp_clause_bind (parser, list: clauses); |
19025 | c_name = "bind" ; |
19026 | break; |
19027 | case PRAGMA_OMP_CLAUSE_COLLAPSE: |
19028 | clauses = c_parser_omp_clause_collapse (parser, list: clauses); |
19029 | c_name = "collapse" ; |
19030 | break; |
19031 | case PRAGMA_OMP_CLAUSE_COPYIN: |
19032 | clauses = c_parser_omp_clause_copyin (parser, list: clauses); |
19033 | c_name = "copyin" ; |
19034 | break; |
19035 | case PRAGMA_OMP_CLAUSE_COPYPRIVATE: |
19036 | clauses = c_parser_omp_clause_copyprivate (parser, list: clauses); |
19037 | c_name = "copyprivate" ; |
19038 | break; |
19039 | case PRAGMA_OMP_CLAUSE_DEFAULT: |
19040 | clauses = c_parser_omp_clause_default (parser, list: clauses, is_oacc: false); |
19041 | c_name = "default" ; |
19042 | break; |
19043 | case PRAGMA_OMP_CLAUSE_DETACH: |
19044 | clauses = c_parser_omp_clause_detach (parser, list: clauses); |
19045 | c_name = "detach" ; |
19046 | break; |
19047 | case PRAGMA_OMP_CLAUSE_FILTER: |
19048 | clauses = c_parser_omp_clause_filter (parser, list: clauses); |
19049 | c_name = "filter" ; |
19050 | break; |
19051 | case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: |
19052 | clauses = c_parser_omp_clause_firstprivate (parser, list: clauses); |
19053 | c_name = "firstprivate" ; |
19054 | break; |
19055 | case PRAGMA_OMP_CLAUSE_FINAL: |
19056 | clauses = c_parser_omp_clause_final (parser, list: clauses); |
19057 | c_name = "final" ; |
19058 | break; |
19059 | case PRAGMA_OMP_CLAUSE_GRAINSIZE: |
19060 | clauses = c_parser_omp_clause_grainsize (parser, list: clauses); |
19061 | c_name = "grainsize" ; |
19062 | break; |
19063 | case PRAGMA_OMP_CLAUSE_HINT: |
19064 | clauses = c_parser_omp_clause_hint (parser, list: clauses); |
19065 | c_name = "hint" ; |
19066 | break; |
19067 | case PRAGMA_OMP_CLAUSE_DEFAULTMAP: |
19068 | clauses = c_parser_omp_clause_defaultmap (parser, list: clauses); |
19069 | c_name = "defaultmap" ; |
19070 | break; |
19071 | case PRAGMA_OMP_CLAUSE_IF: |
19072 | clauses = c_parser_omp_clause_if (parser, list: clauses, is_omp: true); |
19073 | c_name = "if" ; |
19074 | break; |
19075 | case PRAGMA_OMP_CLAUSE_IN_REDUCTION: |
19076 | clauses |
19077 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_IN_REDUCTION, |
19078 | is_omp: true, list: clauses); |
19079 | c_name = "in_reduction" ; |
19080 | break; |
19081 | case PRAGMA_OMP_CLAUSE_INDIRECT: |
19082 | clauses = c_parser_omp_clause_indirect (parser, list: clauses); |
19083 | c_name = "indirect" ; |
19084 | break; |
19085 | case PRAGMA_OMP_CLAUSE_LASTPRIVATE: |
19086 | clauses = c_parser_omp_clause_lastprivate (parser, list: clauses); |
19087 | c_name = "lastprivate" ; |
19088 | break; |
19089 | case PRAGMA_OMP_CLAUSE_MERGEABLE: |
19090 | clauses = c_parser_omp_clause_mergeable (parser, list: clauses); |
19091 | c_name = "mergeable" ; |
19092 | break; |
19093 | case PRAGMA_OMP_CLAUSE_NOWAIT: |
19094 | clauses = c_parser_omp_clause_nowait (parser, list: clauses); |
19095 | c_name = "nowait" ; |
19096 | break; |
19097 | case PRAGMA_OMP_CLAUSE_NUM_TASKS: |
19098 | clauses = c_parser_omp_clause_num_tasks (parser, list: clauses); |
19099 | c_name = "num_tasks" ; |
19100 | break; |
19101 | case PRAGMA_OMP_CLAUSE_NUM_THREADS: |
19102 | clauses = c_parser_omp_clause_num_threads (parser, list: clauses); |
19103 | c_name = "num_threads" ; |
19104 | break; |
19105 | case PRAGMA_OMP_CLAUSE_ORDER: |
19106 | clauses = c_parser_omp_clause_order (parser, list: clauses); |
19107 | c_name = "order" ; |
19108 | break; |
19109 | case PRAGMA_OMP_CLAUSE_ORDERED: |
19110 | clauses = c_parser_omp_clause_ordered (parser, list: clauses); |
19111 | c_name = "ordered" ; |
19112 | break; |
19113 | case PRAGMA_OMP_CLAUSE_PRIORITY: |
19114 | clauses = c_parser_omp_clause_priority (parser, list: clauses); |
19115 | c_name = "priority" ; |
19116 | break; |
19117 | case PRAGMA_OMP_CLAUSE_PRIVATE: |
19118 | clauses = c_parser_omp_clause_private (parser, list: clauses); |
19119 | c_name = "private" ; |
19120 | break; |
19121 | case PRAGMA_OMP_CLAUSE_REDUCTION: |
19122 | clauses |
19123 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_REDUCTION, |
19124 | is_omp: true, list: clauses); |
19125 | c_name = "reduction" ; |
19126 | break; |
19127 | case PRAGMA_OMP_CLAUSE_SCHEDULE: |
19128 | clauses = c_parser_omp_clause_schedule (parser, list: clauses); |
19129 | c_name = "schedule" ; |
19130 | break; |
19131 | case PRAGMA_OMP_CLAUSE_SHARED: |
19132 | clauses = c_parser_omp_clause_shared (parser, list: clauses); |
19133 | c_name = "shared" ; |
19134 | break; |
19135 | case PRAGMA_OMP_CLAUSE_TASK_REDUCTION: |
19136 | clauses |
19137 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_TASK_REDUCTION, |
19138 | is_omp: true, list: clauses); |
19139 | c_name = "task_reduction" ; |
19140 | break; |
19141 | case PRAGMA_OMP_CLAUSE_UNTIED: |
19142 | clauses = c_parser_omp_clause_untied (parser, list: clauses); |
19143 | c_name = "untied" ; |
19144 | break; |
19145 | case PRAGMA_OMP_CLAUSE_INBRANCH: |
19146 | clauses = c_parser_omp_clause_branch (parser, code: OMP_CLAUSE_INBRANCH, |
19147 | list: clauses); |
19148 | c_name = "inbranch" ; |
19149 | break; |
19150 | case PRAGMA_OMP_CLAUSE_NONTEMPORAL: |
19151 | clauses = c_parser_omp_clause_nontemporal (parser, list: clauses); |
19152 | c_name = "nontemporal" ; |
19153 | break; |
19154 | case PRAGMA_OMP_CLAUSE_NOTINBRANCH: |
19155 | clauses = c_parser_omp_clause_branch (parser, code: OMP_CLAUSE_NOTINBRANCH, |
19156 | list: clauses); |
19157 | c_name = "notinbranch" ; |
19158 | break; |
19159 | case PRAGMA_OMP_CLAUSE_PARALLEL: |
19160 | clauses |
19161 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_PARALLEL, |
19162 | list: clauses); |
19163 | c_name = "parallel" ; |
19164 | if (!first) |
19165 | { |
19166 | clause_not_first: |
19167 | error_at (here, "%qs must be the first clause of %qs" , |
19168 | c_name, where); |
19169 | clauses = prev; |
19170 | } |
19171 | break; |
19172 | case PRAGMA_OMP_CLAUSE_FOR: |
19173 | clauses |
19174 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_FOR, |
19175 | list: clauses); |
19176 | c_name = "for" ; |
19177 | if (!first) |
19178 | goto clause_not_first; |
19179 | break; |
19180 | case PRAGMA_OMP_CLAUSE_SECTIONS: |
19181 | clauses |
19182 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_SECTIONS, |
19183 | list: clauses); |
19184 | c_name = "sections" ; |
19185 | if (!first) |
19186 | goto clause_not_first; |
19187 | break; |
19188 | case PRAGMA_OMP_CLAUSE_TASKGROUP: |
19189 | clauses |
19190 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_TASKGROUP, |
19191 | list: clauses); |
19192 | c_name = "taskgroup" ; |
19193 | if (!first) |
19194 | goto clause_not_first; |
19195 | break; |
19196 | case PRAGMA_OMP_CLAUSE_LINK: |
19197 | clauses |
19198 | = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_LINK, list: clauses); |
19199 | c_name = "link" ; |
19200 | break; |
19201 | case PRAGMA_OMP_CLAUSE_TO: |
19202 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) |
19203 | { |
19204 | tree nl = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ENTER, |
19205 | list: clauses); |
19206 | for (tree c = nl; c != clauses; c = OMP_CLAUSE_CHAIN (c)) |
19207 | OMP_CLAUSE_ENTER_TO (c) = 1; |
19208 | clauses = nl; |
19209 | } |
19210 | else |
19211 | clauses = c_parser_omp_clause_from_to (parser, kind: OMP_CLAUSE_TO, |
19212 | list: clauses); |
19213 | c_name = "to" ; |
19214 | break; |
19215 | case PRAGMA_OMP_CLAUSE_FROM: |
19216 | clauses = c_parser_omp_clause_from_to (parser, kind: OMP_CLAUSE_FROM, |
19217 | list: clauses); |
19218 | c_name = "from" ; |
19219 | break; |
19220 | case PRAGMA_OMP_CLAUSE_UNIFORM: |
19221 | clauses = c_parser_omp_clause_uniform (parser, list: clauses); |
19222 | c_name = "uniform" ; |
19223 | break; |
19224 | case PRAGMA_OMP_CLAUSE_NUM_TEAMS: |
19225 | clauses = c_parser_omp_clause_num_teams (parser, list: clauses); |
19226 | c_name = "num_teams" ; |
19227 | break; |
19228 | case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: |
19229 | clauses = c_parser_omp_clause_thread_limit (parser, list: clauses); |
19230 | c_name = "thread_limit" ; |
19231 | break; |
19232 | case PRAGMA_OMP_CLAUSE_ALIGNED: |
19233 | clauses = c_parser_omp_clause_aligned (parser, list: clauses); |
19234 | c_name = "aligned" ; |
19235 | break; |
19236 | case PRAGMA_OMP_CLAUSE_ALLOCATE: |
19237 | clauses = c_parser_omp_clause_allocate (parser, list: clauses); |
19238 | c_name = "allocate" ; |
19239 | break; |
19240 | case PRAGMA_OMP_CLAUSE_LINEAR: |
19241 | clauses = c_parser_omp_clause_linear (parser, list: clauses); |
19242 | c_name = "linear" ; |
19243 | break; |
19244 | case PRAGMA_OMP_CLAUSE_AFFINITY: |
19245 | clauses = c_parser_omp_clause_affinity (parser, list: clauses); |
19246 | c_name = "affinity" ; |
19247 | break; |
19248 | case PRAGMA_OMP_CLAUSE_DEPEND: |
19249 | clauses = c_parser_omp_clause_depend (parser, list: clauses); |
19250 | c_name = "depend" ; |
19251 | break; |
19252 | case PRAGMA_OMP_CLAUSE_DOACROSS: |
19253 | clauses = c_parser_omp_clause_doacross (parser, list: clauses); |
19254 | c_name = "doacross" ; |
19255 | break; |
19256 | case PRAGMA_OMP_CLAUSE_MAP: |
19257 | clauses = c_parser_omp_clause_map (parser, list: clauses); |
19258 | c_name = "map" ; |
19259 | break; |
19260 | case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: |
19261 | clauses = c_parser_omp_clause_use_device_ptr (parser, list: clauses); |
19262 | c_name = "use_device_ptr" ; |
19263 | break; |
19264 | case PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR: |
19265 | clauses = c_parser_omp_clause_use_device_addr (parser, list: clauses); |
19266 | c_name = "use_device_addr" ; |
19267 | break; |
19268 | case PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR: |
19269 | clauses = c_parser_omp_clause_has_device_addr (parser, list: clauses); |
19270 | c_name = "has_device_addr" ; |
19271 | break; |
19272 | case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR: |
19273 | clauses = c_parser_omp_clause_is_device_ptr (parser, list: clauses); |
19274 | c_name = "is_device_ptr" ; |
19275 | break; |
19276 | case PRAGMA_OMP_CLAUSE_DEVICE: |
19277 | clauses = c_parser_omp_clause_device (parser, list: clauses); |
19278 | c_name = "device" ; |
19279 | break; |
19280 | case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: |
19281 | clauses = c_parser_omp_clause_dist_schedule (parser, list: clauses); |
19282 | c_name = "dist_schedule" ; |
19283 | break; |
19284 | case PRAGMA_OMP_CLAUSE_PROC_BIND: |
19285 | clauses = c_parser_omp_clause_proc_bind (parser, list: clauses); |
19286 | c_name = "proc_bind" ; |
19287 | break; |
19288 | case PRAGMA_OMP_CLAUSE_DEVICE_TYPE: |
19289 | clauses = c_parser_omp_clause_device_type (parser, list: clauses); |
19290 | c_name = "device_type" ; |
19291 | break; |
19292 | case PRAGMA_OMP_CLAUSE_SAFELEN: |
19293 | clauses = c_parser_omp_clause_safelen (parser, list: clauses); |
19294 | c_name = "safelen" ; |
19295 | break; |
19296 | case PRAGMA_OMP_CLAUSE_SIMDLEN: |
19297 | clauses = c_parser_omp_clause_simdlen (parser, list: clauses); |
19298 | c_name = "simdlen" ; |
19299 | break; |
19300 | case PRAGMA_OMP_CLAUSE_NOGROUP: |
19301 | clauses = c_parser_omp_clause_nogroup (parser, list: clauses); |
19302 | c_name = "nogroup" ; |
19303 | break; |
19304 | case PRAGMA_OMP_CLAUSE_THREADS: |
19305 | clauses |
19306 | = c_parser_omp_clause_orderedkind (parser, code: OMP_CLAUSE_THREADS, |
19307 | list: clauses); |
19308 | c_name = "threads" ; |
19309 | break; |
19310 | case PRAGMA_OMP_CLAUSE_SIMD: |
19311 | clauses |
19312 | = c_parser_omp_clause_orderedkind (parser, code: OMP_CLAUSE_SIMD, |
19313 | list: clauses); |
19314 | c_name = "simd" ; |
19315 | break; |
19316 | case PRAGMA_OMP_CLAUSE_ENTER: |
19317 | clauses |
19318 | = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ENTER, |
19319 | list: clauses); |
19320 | c_name = "enter" ; |
19321 | break; |
19322 | default: |
19323 | c_parser_error (parser, gmsgid: "expected an OpenMP clause" ); |
19324 | goto saw_error; |
19325 | } |
19326 | |
19327 | first = false; |
19328 | |
19329 | if (((mask >> c_kind) & 1) == 0) |
19330 | { |
19331 | /* Remove the invalid clause(s) from the list to avoid |
19332 | confusing the rest of the compiler. */ |
19333 | clauses = prev; |
19334 | error_at (here, "%qs is not valid for %qs" , c_name, where); |
19335 | } |
19336 | } |
19337 | |
19338 | saw_error: |
19339 | if (!nested) |
19340 | c_parser_skip_to_pragma_eol (parser); |
19341 | |
19342 | if (finish_p) |
19343 | { |
19344 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0) |
19345 | return c_finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD); |
19346 | return c_finish_omp_clauses (clauses, C_ORT_OMP); |
19347 | } |
19348 | |
19349 | return clauses; |
19350 | } |
19351 | |
19352 | /* OpenACC 2.0, OpenMP 2.5: |
19353 | structured-block: |
19354 | statement |
19355 | |
19356 | In practice, we're also interested in adding the statement to an |
19357 | outer node. So it is convenient if we work around the fact that |
19358 | c_parser_statement calls add_stmt. */ |
19359 | |
19360 | static tree |
19361 | c_parser_omp_structured_block (c_parser *parser, bool *if_p) |
19362 | { |
19363 | tree stmt = push_stmt_list (); |
19364 | parser->omp_attrs_forbidden_p = true; |
19365 | c_parser_statement (parser, if_p); |
19366 | return pop_stmt_list (stmt); |
19367 | } |
19368 | |
19369 | /* OpenACC 2.0: |
19370 | # pragma acc cache (variable-list) new-line |
19371 | |
19372 | LOC is the location of the #pragma token. |
19373 | */ |
19374 | |
19375 | static tree |
19376 | c_parser_oacc_cache (location_t loc, c_parser *parser) |
19377 | { |
19378 | tree stmt, clauses; |
19379 | |
19380 | clauses = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE__CACHE_, NULL); |
19381 | clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); |
19382 | |
19383 | c_parser_skip_to_pragma_eol (parser); |
19384 | |
19385 | stmt = make_node (OACC_CACHE); |
19386 | TREE_TYPE (stmt) = void_type_node; |
19387 | OACC_CACHE_CLAUSES (stmt) = clauses; |
19388 | SET_EXPR_LOCATION (stmt, loc); |
19389 | add_stmt (stmt); |
19390 | |
19391 | return stmt; |
19392 | } |
19393 | |
19394 | /* OpenACC 2.0: |
19395 | # pragma acc data oacc-data-clause[optseq] new-line |
19396 | structured-block |
19397 | |
19398 | LOC is the location of the #pragma token. |
19399 | */ |
19400 | |
19401 | #define OACC_DATA_CLAUSE_MASK \ |
19402 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
19403 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19404 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19405 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19406 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19407 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
19408 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19409 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19410 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
19411 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) |
19412 | |
19413 | static tree |
19414 | c_parser_oacc_data (location_t loc, c_parser *parser, bool *if_p) |
19415 | { |
19416 | tree stmt, clauses, block; |
19417 | |
19418 | clauses = c_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK, |
19419 | where: "#pragma acc data" ); |
19420 | |
19421 | block = c_begin_omp_parallel (); |
19422 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
19423 | |
19424 | stmt = c_finish_oacc_data (loc, clauses, block); |
19425 | |
19426 | return stmt; |
19427 | } |
19428 | |
19429 | /* OpenACC 2.0: |
19430 | # pragma acc declare oacc-data-clause[optseq] new-line |
19431 | */ |
19432 | |
19433 | #define OACC_DECLARE_CLAUSE_MASK \ |
19434 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19435 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19436 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19437 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19438 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19439 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT) \ |
19440 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_LINK) \ |
19441 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) |
19442 | |
19443 | static void |
19444 | c_parser_oacc_declare (c_parser *parser) |
19445 | { |
19446 | location_t pragma_loc = c_parser_peek_token (parser)->location; |
19447 | tree clauses, stmt, t, decl; |
19448 | |
19449 | bool error = false; |
19450 | |
19451 | c_parser_consume_pragma (parser); |
19452 | |
19453 | clauses = c_parser_oacc_all_clauses (parser, OACC_DECLARE_CLAUSE_MASK, |
19454 | where: "#pragma acc declare" ); |
19455 | if (!clauses) |
19456 | { |
19457 | error_at (pragma_loc, |
19458 | "no valid clauses specified in %<#pragma acc declare%>" ); |
19459 | return; |
19460 | } |
19461 | |
19462 | for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t)) |
19463 | { |
19464 | location_t loc = OMP_CLAUSE_LOCATION (t); |
19465 | decl = OMP_CLAUSE_DECL (t); |
19466 | if (!DECL_P (decl)) |
19467 | { |
19468 | error_at (loc, "array section in %<#pragma acc declare%>" ); |
19469 | error = true; |
19470 | continue; |
19471 | } |
19472 | |
19473 | switch (OMP_CLAUSE_MAP_KIND (t)) |
19474 | { |
19475 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
19476 | case GOMP_MAP_ALLOC: |
19477 | case GOMP_MAP_TO: |
19478 | case GOMP_MAP_FORCE_DEVICEPTR: |
19479 | case GOMP_MAP_DEVICE_RESIDENT: |
19480 | break; |
19481 | |
19482 | case GOMP_MAP_LINK: |
19483 | if (!global_bindings_p () |
19484 | && (TREE_STATIC (decl) |
19485 | || !DECL_EXTERNAL (decl))) |
19486 | { |
19487 | error_at (loc, |
19488 | "%qD must be a global variable in " |
19489 | "%<#pragma acc declare link%>" , |
19490 | decl); |
19491 | error = true; |
19492 | continue; |
19493 | } |
19494 | break; |
19495 | |
19496 | default: |
19497 | if (global_bindings_p ()) |
19498 | { |
19499 | error_at (loc, "invalid OpenACC clause at file scope" ); |
19500 | error = true; |
19501 | continue; |
19502 | } |
19503 | if (DECL_EXTERNAL (decl)) |
19504 | { |
19505 | error_at (loc, |
19506 | "invalid use of %<extern%> variable %qD " |
19507 | "in %<#pragma acc declare%>" , decl); |
19508 | error = true; |
19509 | continue; |
19510 | } |
19511 | else if (TREE_PUBLIC (decl)) |
19512 | { |
19513 | error_at (loc, |
19514 | "invalid use of %<global%> variable %qD " |
19515 | "in %<#pragma acc declare%>" , decl); |
19516 | error = true; |
19517 | continue; |
19518 | } |
19519 | break; |
19520 | } |
19521 | |
19522 | if (!c_check_in_current_scope (decl)) |
19523 | { |
19524 | error_at (loc, |
19525 | "%qD must be a variable declared in the same scope as " |
19526 | "%<#pragma acc declare%>" , decl); |
19527 | error = true; |
19528 | continue; |
19529 | } |
19530 | |
19531 | if (lookup_attribute (attr_name: "omp declare target" , DECL_ATTRIBUTES (decl)) |
19532 | || lookup_attribute (attr_name: "omp declare target link" , |
19533 | DECL_ATTRIBUTES (decl))) |
19534 | { |
19535 | error_at (loc, "variable %qD used more than once with " |
19536 | "%<#pragma acc declare%>" , decl); |
19537 | error = true; |
19538 | continue; |
19539 | } |
19540 | |
19541 | if (!error) |
19542 | { |
19543 | tree id; |
19544 | |
19545 | if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK) |
19546 | id = get_identifier ("omp declare target link" ); |
19547 | else |
19548 | id = get_identifier ("omp declare target" ); |
19549 | |
19550 | DECL_ATTRIBUTES (decl) |
19551 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl)); |
19552 | |
19553 | if (global_bindings_p ()) |
19554 | { |
19555 | symtab_node *node = symtab_node::get (decl); |
19556 | if (node != NULL) |
19557 | { |
19558 | node->offloadable = 1; |
19559 | if (ENABLE_OFFLOADING) |
19560 | { |
19561 | g->have_offload = true; |
19562 | if (is_a <varpool_node *> (p: node)) |
19563 | vec_safe_push (v&: offload_vars, obj: decl); |
19564 | } |
19565 | } |
19566 | } |
19567 | } |
19568 | } |
19569 | |
19570 | if (error || global_bindings_p ()) |
19571 | return; |
19572 | |
19573 | stmt = make_node (OACC_DECLARE); |
19574 | TREE_TYPE (stmt) = void_type_node; |
19575 | OACC_DECLARE_CLAUSES (stmt) = clauses; |
19576 | SET_EXPR_LOCATION (stmt, pragma_loc); |
19577 | |
19578 | add_stmt (stmt); |
19579 | |
19580 | return; |
19581 | } |
19582 | |
19583 | /* OpenACC 2.0: |
19584 | # pragma acc enter data oacc-enter-data-clause[optseq] new-line |
19585 | |
19586 | or |
19587 | |
19588 | # pragma acc exit data oacc-exit-data-clause[optseq] new-line |
19589 | |
19590 | |
19591 | LOC is the location of the #pragma token. |
19592 | */ |
19593 | |
19594 | #define OACC_ENTER_DATA_CLAUSE_MASK \ |
19595 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19596 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
19597 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
19598 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19599 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19600 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
19601 | |
19602 | #define OACC_EXIT_DATA_CLAUSE_MASK \ |
19603 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19604 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
19605 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19606 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ |
19607 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ |
19608 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \ |
19609 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
19610 | |
19611 | static void |
19612 | c_parser_oacc_enter_exit_data (c_parser *parser, bool enter) |
19613 | { |
19614 | location_t loc = c_parser_peek_token (parser)->location; |
19615 | tree clauses, stmt; |
19616 | const char *p = "" ; |
19617 | |
19618 | c_parser_consume_pragma (parser); |
19619 | |
19620 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
19621 | { |
19622 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
19623 | c_parser_consume_token (parser); |
19624 | } |
19625 | |
19626 | if (strcmp (s1: p, s2: "data" ) != 0) |
19627 | { |
19628 | error_at (loc, "expected %<data%> after %<#pragma acc %s%>" , |
19629 | enter ? "enter" : "exit" ); |
19630 | parser->error = true; |
19631 | c_parser_skip_to_pragma_eol (parser); |
19632 | return; |
19633 | } |
19634 | |
19635 | if (enter) |
19636 | clauses = c_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK, |
19637 | where: "#pragma acc enter data" ); |
19638 | else |
19639 | clauses = c_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK, |
19640 | where: "#pragma acc exit data" ); |
19641 | |
19642 | if (omp_find_clause (clauses, kind: OMP_CLAUSE_MAP) == NULL_TREE) |
19643 | { |
19644 | error_at (loc, "%<#pragma acc %s data%> has no data movement clause" , |
19645 | enter ? "enter" : "exit" ); |
19646 | return; |
19647 | } |
19648 | |
19649 | stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA); |
19650 | TREE_TYPE (stmt) = void_type_node; |
19651 | OMP_STANDALONE_CLAUSES (stmt) = clauses; |
19652 | SET_EXPR_LOCATION (stmt, loc); |
19653 | add_stmt (stmt); |
19654 | } |
19655 | |
19656 | |
19657 | /* OpenACC 2.0: |
19658 | # pragma acc host_data oacc-data-clause[optseq] new-line |
19659 | structured-block |
19660 | */ |
19661 | |
19662 | #define OACC_HOST_DATA_CLAUSE_MASK \ |
19663 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_USE_DEVICE) \ |
19664 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19665 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) ) |
19666 | |
19667 | static tree |
19668 | c_parser_oacc_host_data (location_t loc, c_parser *parser, bool *if_p) |
19669 | { |
19670 | tree stmt, clauses, block; |
19671 | |
19672 | clauses = c_parser_oacc_all_clauses (parser, OACC_HOST_DATA_CLAUSE_MASK, |
19673 | where: "#pragma acc host_data" , finish_p: false); |
19674 | if (!omp_find_clause (clauses, kind: OMP_CLAUSE_USE_DEVICE_PTR)) |
19675 | { |
19676 | error_at (loc, "%<host_data%> construct requires %<use_device%> clause" ); |
19677 | return error_mark_node; |
19678 | } |
19679 | clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); |
19680 | block = c_begin_omp_parallel (); |
19681 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
19682 | stmt = c_finish_oacc_host_data (loc, clauses, block); |
19683 | return stmt; |
19684 | } |
19685 | |
19686 | |
19687 | /* OpenACC 2.0: |
19688 | |
19689 | # pragma acc loop oacc-loop-clause[optseq] new-line |
19690 | structured-block |
19691 | |
19692 | LOC is the location of the #pragma token. |
19693 | */ |
19694 | |
19695 | #define OACC_LOOP_CLAUSE_MASK \ |
19696 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \ |
19697 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ |
19698 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ |
19699 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ |
19700 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ |
19701 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ |
19702 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_AUTO) \ |
19703 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_INDEPENDENT) \ |
19704 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ |
19705 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_TILE) ) |
19706 | static tree |
19707 | c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, |
19708 | omp_clause_mask mask, tree *cclauses, bool *if_p) |
19709 | { |
19710 | bool is_parallel = ((mask >> PRAGMA_OACC_CLAUSE_REDUCTION) & 1) == 1; |
19711 | |
19712 | strcat (dest: p_name, src: " loop" ); |
19713 | mask |= OACC_LOOP_CLAUSE_MASK; |
19714 | |
19715 | tree clauses = c_parser_oacc_all_clauses (parser, mask, where: p_name, |
19716 | finish_p: cclauses == NULL); |
19717 | if (cclauses) |
19718 | { |
19719 | clauses = c_oacc_split_loop_clauses (clauses, cclauses, is_parallel); |
19720 | if (*cclauses) |
19721 | *cclauses = c_finish_omp_clauses (*cclauses, C_ORT_ACC); |
19722 | if (clauses) |
19723 | clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); |
19724 | } |
19725 | |
19726 | tree block = c_begin_compound_stmt (true); |
19727 | tree stmt = c_parser_omp_for_loop (loc, parser, OACC_LOOP, clauses, NULL, |
19728 | if_p); |
19729 | block = c_end_compound_stmt (loc, block, true); |
19730 | add_stmt (block); |
19731 | |
19732 | return stmt; |
19733 | } |
19734 | |
19735 | /* OpenACC 2.0: |
19736 | # pragma acc kernels oacc-kernels-clause[optseq] new-line |
19737 | structured-block |
19738 | |
19739 | or |
19740 | |
19741 | # pragma acc parallel oacc-parallel-clause[optseq] new-line |
19742 | structured-block |
19743 | |
19744 | OpenACC 2.6: |
19745 | |
19746 | # pragma acc serial oacc-serial-clause[optseq] new-line |
19747 | structured-block |
19748 | |
19749 | LOC is the location of the #pragma token. |
19750 | */ |
19751 | |
19752 | #define OACC_KERNELS_CLAUSE_MASK \ |
19753 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
19754 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
19755 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19756 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19757 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19758 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19759 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
19760 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19761 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19762 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
19763 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ |
19764 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ |
19765 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ |
19766 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
19767 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ |
19768 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
19769 | |
19770 | #define OACC_PARALLEL_CLAUSE_MASK \ |
19771 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
19772 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
19773 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19774 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19775 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19776 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19777 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
19778 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19779 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19780 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
19781 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ |
19782 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ |
19783 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ |
19784 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ |
19785 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ |
19786 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ |
19787 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
19788 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ |
19789 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
19790 | |
19791 | #define OACC_SERIAL_CLAUSE_MASK \ |
19792 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
19793 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
19794 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19795 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19796 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19797 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19798 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
19799 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19800 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19801 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
19802 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ |
19803 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ |
19804 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ |
19805 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ |
19806 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
19807 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
19808 | |
19809 | static tree |
19810 | c_parser_oacc_compute (location_t loc, c_parser *parser, |
19811 | enum pragma_kind p_kind, char *p_name, bool *if_p) |
19812 | { |
19813 | omp_clause_mask mask; |
19814 | enum tree_code code; |
19815 | switch (p_kind) |
19816 | { |
19817 | case PRAGMA_OACC_KERNELS: |
19818 | strcat (dest: p_name, src: " kernels" ); |
19819 | mask = OACC_KERNELS_CLAUSE_MASK; |
19820 | code = OACC_KERNELS; |
19821 | break; |
19822 | case PRAGMA_OACC_PARALLEL: |
19823 | strcat (dest: p_name, src: " parallel" ); |
19824 | mask = OACC_PARALLEL_CLAUSE_MASK; |
19825 | code = OACC_PARALLEL; |
19826 | break; |
19827 | case PRAGMA_OACC_SERIAL: |
19828 | strcat (dest: p_name, src: " serial" ); |
19829 | mask = OACC_SERIAL_CLAUSE_MASK; |
19830 | code = OACC_SERIAL; |
19831 | break; |
19832 | default: |
19833 | gcc_unreachable (); |
19834 | } |
19835 | |
19836 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
19837 | { |
19838 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
19839 | if (strcmp (s1: p, s2: "loop" ) == 0) |
19840 | { |
19841 | c_parser_consume_token (parser); |
19842 | tree block = c_begin_omp_parallel (); |
19843 | tree clauses; |
19844 | c_parser_oacc_loop (loc, parser, p_name, mask, cclauses: &clauses, if_p); |
19845 | return c_finish_omp_construct (loc, code, block, clauses); |
19846 | } |
19847 | } |
19848 | |
19849 | tree clauses = c_parser_oacc_all_clauses (parser, mask, where: p_name); |
19850 | |
19851 | tree block = c_begin_omp_parallel (); |
19852 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
19853 | |
19854 | return c_finish_omp_construct (loc, code, block, clauses); |
19855 | } |
19856 | |
19857 | /* OpenACC 2.0: |
19858 | # pragma acc routine oacc-routine-clause[optseq] new-line |
19859 | function-definition |
19860 | |
19861 | # pragma acc routine ( name ) oacc-routine-clause[optseq] new-line |
19862 | */ |
19863 | |
19864 | #define OACC_ROUTINE_CLAUSE_MASK \ |
19865 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ |
19866 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ |
19867 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ |
19868 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ |
19869 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) |
19870 | |
19871 | /* Parse an OpenACC routine directive. For named directives, we apply |
19872 | immediately to the named function. For unnamed ones we then parse |
19873 | a declaration or definition, which must be for a function. */ |
19874 | |
19875 | static void |
19876 | c_parser_oacc_routine (c_parser *parser, enum pragma_context context) |
19877 | { |
19878 | gcc_checking_assert (context == pragma_external); |
19879 | |
19880 | oacc_routine_data data; |
19881 | data.error_seen = false; |
19882 | data.fndecl_seen = false; |
19883 | data.loc = c_parser_peek_token (parser)->location; |
19884 | |
19885 | c_parser_consume_pragma (parser); |
19886 | |
19887 | /* Look for optional '( name )'. */ |
19888 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
19889 | { |
19890 | c_parser_consume_token (parser); /* '(' */ |
19891 | |
19892 | tree decl = NULL_TREE; |
19893 | c_token *name_token = c_parser_peek_token (parser); |
19894 | location_t name_loc = name_token->location; |
19895 | if (name_token->type == CPP_NAME |
19896 | && (name_token->id_kind == C_ID_ID |
19897 | || name_token->id_kind == C_ID_TYPENAME)) |
19898 | { |
19899 | decl = lookup_name (name_token->value); |
19900 | if (!decl) |
19901 | error_at (name_loc, |
19902 | "%qE has not been declared" , name_token->value); |
19903 | c_parser_consume_token (parser); |
19904 | } |
19905 | else |
19906 | c_parser_error (parser, gmsgid: "expected function name" ); |
19907 | |
19908 | if (!decl |
19909 | || !c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
19910 | { |
19911 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
19912 | return; |
19913 | } |
19914 | |
19915 | data.clauses |
19916 | = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, |
19917 | where: "#pragma acc routine" ); |
19918 | /* The clauses are in reverse order; fix that to make later diagnostic |
19919 | emission easier. */ |
19920 | data.clauses = nreverse (data.clauses); |
19921 | |
19922 | if (TREE_CODE (decl) != FUNCTION_DECL) |
19923 | { |
19924 | error_at (name_loc, "%qD does not refer to a function" , decl); |
19925 | return; |
19926 | } |
19927 | |
19928 | c_finish_oacc_routine (&data, decl, false); |
19929 | } |
19930 | else /* No optional '( name )'. */ |
19931 | { |
19932 | data.clauses |
19933 | = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, |
19934 | where: "#pragma acc routine" ); |
19935 | /* The clauses are in reverse order; fix that to make later diagnostic |
19936 | emission easier. */ |
19937 | data.clauses = nreverse (data.clauses); |
19938 | |
19939 | /* Emit a helpful diagnostic if there's another pragma following this |
19940 | one. Also don't allow a static assertion declaration, as in the |
19941 | following we'll just parse a *single* "declaration or function |
19942 | definition", and the static assertion counts an one. */ |
19943 | if (c_parser_next_token_is (parser, type: CPP_PRAGMA) |
19944 | || c_parser_next_token_is_keyword (parser, keyword: RID_STATIC_ASSERT)) |
19945 | { |
19946 | error_at (data.loc, |
19947 | "%<#pragma acc routine%> not immediately followed by" |
19948 | " function declaration or definition" ); |
19949 | /* ..., and then just keep going. */ |
19950 | return; |
19951 | } |
19952 | |
19953 | /* We only have to consider the pragma_external case here. */ |
19954 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
19955 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION) |
19956 | { |
19957 | int ext = disable_extension_diagnostics (); |
19958 | do |
19959 | c_parser_consume_token (parser); |
19960 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
19961 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION); |
19962 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
19963 | NULL, NULL, have_attrs: false, NULL, oacc_routine_data: &data); |
19964 | restore_extension_diagnostics (flags: ext); |
19965 | } |
19966 | else |
19967 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
19968 | NULL, NULL, have_attrs: false, NULL, oacc_routine_data: &data); |
19969 | } |
19970 | } |
19971 | |
19972 | /* Finalize an OpenACC routine pragma, applying it to FNDECL. |
19973 | IS_DEFN is true if we're applying it to the definition. */ |
19974 | |
19975 | static void |
19976 | c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, |
19977 | bool is_defn) |
19978 | { |
19979 | /* Keep going if we're in error reporting mode. */ |
19980 | if (data->error_seen |
19981 | || fndecl == error_mark_node) |
19982 | return; |
19983 | |
19984 | if (data->fndecl_seen) |
19985 | { |
19986 | error_at (data->loc, |
19987 | "%<#pragma acc routine%> not immediately followed by" |
19988 | " a single function declaration or definition" ); |
19989 | data->error_seen = true; |
19990 | return; |
19991 | } |
19992 | if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) |
19993 | { |
19994 | error_at (data->loc, |
19995 | "%<#pragma acc routine%> not immediately followed by" |
19996 | " function declaration or definition" ); |
19997 | data->error_seen = true; |
19998 | return; |
19999 | } |
20000 | |
20001 | int compatible |
20002 | = oacc_verify_routine_clauses (fndecl, &data->clauses, data->loc, |
20003 | "#pragma acc routine" ); |
20004 | if (compatible < 0) |
20005 | { |
20006 | data->error_seen = true; |
20007 | return; |
20008 | } |
20009 | if (compatible > 0) |
20010 | { |
20011 | } |
20012 | else |
20013 | { |
20014 | if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) |
20015 | { |
20016 | error_at (data->loc, |
20017 | TREE_USED (fndecl) |
20018 | ? G_("%<#pragma acc routine%> must be applied before use" ) |
20019 | : G_("%<#pragma acc routine%> must be applied before" |
20020 | " definition" )); |
20021 | data->error_seen = true; |
20022 | return; |
20023 | } |
20024 | |
20025 | /* Set the routine's level of parallelism. */ |
20026 | tree dims = oacc_build_routine_dims (clauses: data->clauses); |
20027 | oacc_replace_fn_attrib (fn: fndecl, dims); |
20028 | |
20029 | /* Add an "omp declare target" attribute. */ |
20030 | DECL_ATTRIBUTES (fndecl) |
20031 | = tree_cons (get_identifier ("omp declare target" ), |
20032 | data->clauses, DECL_ATTRIBUTES (fndecl)); |
20033 | } |
20034 | |
20035 | /* Remember that we've used this "#pragma acc routine". */ |
20036 | data->fndecl_seen = true; |
20037 | } |
20038 | |
20039 | /* OpenACC 2.0: |
20040 | # pragma acc update oacc-update-clause[optseq] new-line |
20041 | */ |
20042 | |
20043 | #define OACC_UPDATE_CLAUSE_MASK \ |
20044 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20045 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \ |
20046 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \ |
20047 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20048 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) \ |
20049 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
20050 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20051 | |
20052 | static void |
20053 | c_parser_oacc_update (c_parser *parser) |
20054 | { |
20055 | location_t loc = c_parser_peek_token (parser)->location; |
20056 | |
20057 | c_parser_consume_pragma (parser); |
20058 | |
20059 | tree clauses = c_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK, |
20060 | where: "#pragma acc update" ); |
20061 | if (omp_find_clause (clauses, kind: OMP_CLAUSE_MAP) == NULL_TREE) |
20062 | { |
20063 | error_at (loc, |
20064 | "%<#pragma acc update%> must contain at least one " |
20065 | "%<device%> or %<host%> or %<self%> clause" ); |
20066 | return; |
20067 | } |
20068 | |
20069 | if (parser->error) |
20070 | return; |
20071 | |
20072 | tree stmt = make_node (OACC_UPDATE); |
20073 | TREE_TYPE (stmt) = void_type_node; |
20074 | OACC_UPDATE_CLAUSES (stmt) = clauses; |
20075 | SET_EXPR_LOCATION (stmt, loc); |
20076 | add_stmt (stmt); |
20077 | } |
20078 | |
20079 | /* OpenACC 2.0: |
20080 | # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line |
20081 | |
20082 | LOC is the location of the #pragma token. |
20083 | */ |
20084 | |
20085 | #define OACC_WAIT_CLAUSE_MASK \ |
20086 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) |
20087 | |
20088 | static tree |
20089 | c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) |
20090 | { |
20091 | tree clauses, list = NULL_TREE, stmt = NULL_TREE; |
20092 | |
20093 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
20094 | list = c_parser_oacc_wait_list (parser, clause_loc: loc, list); |
20095 | |
20096 | strcpy (dest: p_name, src: " wait" ); |
20097 | clauses = c_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, where: p_name); |
20098 | stmt = c_finish_oacc_wait (loc, list, clauses); |
20099 | add_stmt (stmt); |
20100 | |
20101 | return stmt; |
20102 | } |
20103 | |
20104 | struct c_omp_loc_tree |
20105 | { |
20106 | location_t loc; |
20107 | tree var; |
20108 | }; |
20109 | |
20110 | /* Check whether the expression used in the allocator clause is declared or |
20111 | modified between the variable declaration and its allocate directive. */ |
20112 | static tree |
20113 | c_check_omp_allocate_allocator_r (tree *tp, int *, void *data) |
20114 | { |
20115 | tree var = ((struct c_omp_loc_tree *) data)->var; |
20116 | location_t loc = ((struct c_omp_loc_tree *) data)->loc; |
20117 | if (TREE_CODE (*tp) == VAR_DECL && c_check_in_current_scope (*tp)) |
20118 | { |
20119 | if (linemap_location_before_p (set: line_table, DECL_SOURCE_LOCATION (var), |
20120 | DECL_SOURCE_LOCATION (*tp))) |
20121 | { |
20122 | error_at (loc, "variable %qD used in the %<allocator%> clause must " |
20123 | "be declared before %qD" , *tp, var); |
20124 | inform (DECL_SOURCE_LOCATION (*tp), "declared here" ); |
20125 | inform (DECL_SOURCE_LOCATION (var), |
20126 | "to be allocated variable declared here" ); |
20127 | return *tp; |
20128 | } |
20129 | else |
20130 | { |
20131 | gcc_assert (cur_stmt_list |
20132 | && TREE_CODE (cur_stmt_list) == STATEMENT_LIST); |
20133 | |
20134 | tree_stmt_iterator l = tsi_last (cur_stmt_list); |
20135 | while (!tsi_end_p (i: l)) |
20136 | { |
20137 | if (linemap_location_before_p (set: line_table, EXPR_LOCATION (*l), |
20138 | DECL_SOURCE_LOCATION (var))) |
20139 | break; |
20140 | if (TREE_CODE (*l) == MODIFY_EXPR |
20141 | && TREE_OPERAND (*l, 0) == *tp) |
20142 | { |
20143 | error_at (loc, |
20144 | "variable %qD used in the %<allocator%> clause " |
20145 | "must not be modified between declaration of %qD " |
20146 | "and its %<allocate%> directive" , *tp, var); |
20147 | inform (EXPR_LOCATION (*l), "modified here" ); |
20148 | inform (DECL_SOURCE_LOCATION (var), |
20149 | "to be allocated variable declared here" ); |
20150 | return *tp; |
20151 | } |
20152 | --l; |
20153 | } |
20154 | } |
20155 | } |
20156 | return NULL_TREE; |
20157 | } |
20158 | |
20159 | /* OpenMP 5.x: |
20160 | # pragma omp allocate (list) clauses |
20161 | |
20162 | OpenMP 5.0 clause: |
20163 | allocator (omp_allocator_handle_t expression) |
20164 | |
20165 | OpenMP 5.1 additional clause: |
20166 | align (constant-expression)] */ |
20167 | |
20168 | static void |
20169 | c_parser_omp_allocate (c_parser *parser) |
20170 | { |
20171 | tree alignment = NULL_TREE; |
20172 | tree allocator = NULL_TREE; |
20173 | c_parser_consume_pragma (parser); |
20174 | location_t loc = c_parser_peek_token (parser)->location; |
20175 | location_t allocator_loc = UNKNOWN_LOCATION; |
20176 | tree nl = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ALLOCATE, NULL_TREE); |
20177 | do |
20178 | { |
20179 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
20180 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
20181 | c_parser_consume_token (parser); |
20182 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
20183 | break; |
20184 | matching_parens parens; |
20185 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20186 | c_parser_consume_token (parser); |
20187 | location_t expr_loc = c_parser_peek_token (parser)->location; |
20188 | if (strcmp (s1: "align" , s2: p) != 0 && strcmp (s1: "allocator" , s2: p) != 0) |
20189 | { |
20190 | error_at (c_parser_peek_token (parser)->location, |
20191 | "expected %<allocator%> or %<align%>" ); |
20192 | break; |
20193 | } |
20194 | if (!parens.require_open (parser)) |
20195 | break; |
20196 | |
20197 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
20198 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
20199 | expr_loc = c_parser_peek_token (parser)->location; |
20200 | if (expr.value == error_mark_node) |
20201 | ; |
20202 | else if (p[2] == 'i' && alignment) |
20203 | { |
20204 | error_at (expr_loc, "too many %qs clauses" , "align" ); |
20205 | break; |
20206 | } |
20207 | else if (p[2] == 'i') |
20208 | { |
20209 | alignment = c_fully_fold (expr.value, false, NULL); |
20210 | if (TREE_CODE (alignment) != INTEGER_CST |
20211 | || !INTEGRAL_TYPE_P (TREE_TYPE (alignment)) |
20212 | || tree_int_cst_sgn (alignment) != 1 |
20213 | || !integer_pow2p (alignment)) |
20214 | { |
20215 | error_at (expr_loc, "%<align%> clause argument needs to be " |
20216 | "positive constant power of two integer " |
20217 | "expression" ); |
20218 | alignment = NULL_TREE; |
20219 | } |
20220 | } |
20221 | else if (allocator) |
20222 | { |
20223 | error_at (expr_loc, "too many %qs clauses" , "allocator" ); |
20224 | break; |
20225 | } |
20226 | else |
20227 | { |
20228 | allocator = c_fully_fold (expr.value, false, NULL); |
20229 | allocator_loc = expr_loc; |
20230 | tree orig_type |
20231 | = expr.original_type ? expr.original_type : TREE_TYPE (allocator); |
20232 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
20233 | if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) |
20234 | || TREE_CODE (orig_type) != ENUMERAL_TYPE |
20235 | || TYPE_NAME (orig_type) |
20236 | != get_identifier ("omp_allocator_handle_t" )) |
20237 | { |
20238 | error_at (expr_loc, |
20239 | "%<allocator%> clause allocator expression has type " |
20240 | "%qT rather than %<omp_allocator_handle_t%>" , |
20241 | TREE_TYPE (allocator)); |
20242 | allocator = NULL_TREE; |
20243 | } |
20244 | } |
20245 | parens.skip_until_found_close (parser); |
20246 | } while (true); |
20247 | c_parser_skip_to_pragma_eol (parser); |
20248 | |
20249 | c_mark_decl_jump_unsafe_in_current_scope (); |
20250 | for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c)) |
20251 | { |
20252 | tree var = OMP_CLAUSE_DECL (c); |
20253 | if (TREE_CODE (var) == PARM_DECL) |
20254 | { |
20255 | error_at (OMP_CLAUSE_LOCATION (nl), |
20256 | "function parameter %qD may not appear as list item in an " |
20257 | "%<allocate%> directive" , var); |
20258 | continue; |
20259 | } |
20260 | if (!c_check_in_current_scope (var)) |
20261 | { |
20262 | error_at (OMP_CLAUSE_LOCATION (nl), |
20263 | "%<allocate%> directive must be in the same scope as %qD" , |
20264 | var); |
20265 | inform (DECL_SOURCE_LOCATION (var), "declared here" ); |
20266 | continue; |
20267 | } |
20268 | if (lookup_attribute (attr_name: "omp allocate" , DECL_ATTRIBUTES (var))) |
20269 | { |
20270 | error_at (OMP_CLAUSE_LOCATION (nl), |
20271 | "%qD already appeared as list item in an " |
20272 | "%<allocate%> directive" , var); |
20273 | continue; |
20274 | } |
20275 | if (TREE_STATIC (var)) |
20276 | { |
20277 | if (allocator == NULL_TREE && allocator_loc == UNKNOWN_LOCATION) |
20278 | error_at (loc, "%<allocator%> clause required for " |
20279 | "static variable %qD" , var); |
20280 | else if (allocator |
20281 | && (wi::to_widest (t: allocator) < 1 |
20282 | || wi::to_widest (t: allocator) > 8)) |
20283 | /* 8 = largest predefined memory allocator. */ |
20284 | error_at (allocator_loc, |
20285 | "%<allocator%> clause requires a predefined allocator as " |
20286 | "%qD is static" , var); |
20287 | else |
20288 | sorry_at (OMP_CLAUSE_LOCATION (nl), |
20289 | "%<#pragma omp allocate%> for static variables like " |
20290 | "%qD not yet supported" , var); |
20291 | continue; |
20292 | } |
20293 | if (allocator) |
20294 | { |
20295 | struct c_omp_loc_tree data |
20296 | = {EXPR_LOC_OR_LOC (allocator, OMP_CLAUSE_LOCATION (nl)), .var: var}; |
20297 | walk_tree (&allocator, c_check_omp_allocate_allocator_r, &data, NULL); |
20298 | } |
20299 | DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("omp allocate" ), |
20300 | build_tree_list (allocator, alignment), |
20301 | DECL_ATTRIBUTES (var)); |
20302 | } |
20303 | } |
20304 | |
20305 | /* OpenMP 2.5: |
20306 | # pragma omp atomic new-line |
20307 | expression-stmt |
20308 | |
20309 | expression-stmt: |
20310 | x binop= expr | x++ | ++x | x-- | --x |
20311 | binop: |
20312 | +, *, -, /, &, ^, |, <<, >> |
20313 | |
20314 | where x is an lvalue expression with scalar type. |
20315 | |
20316 | OpenMP 3.1: |
20317 | # pragma omp atomic new-line |
20318 | update-stmt |
20319 | |
20320 | # pragma omp atomic read new-line |
20321 | read-stmt |
20322 | |
20323 | # pragma omp atomic write new-line |
20324 | write-stmt |
20325 | |
20326 | # pragma omp atomic update new-line |
20327 | update-stmt |
20328 | |
20329 | # pragma omp atomic capture new-line |
20330 | capture-stmt |
20331 | |
20332 | # pragma omp atomic capture new-line |
20333 | capture-block |
20334 | |
20335 | read-stmt: |
20336 | v = x |
20337 | write-stmt: |
20338 | x = expr |
20339 | update-stmt: |
20340 | expression-stmt | x = x binop expr |
20341 | capture-stmt: |
20342 | v = expression-stmt |
20343 | capture-block: |
20344 | { v = x; update-stmt; } | { update-stmt; v = x; } |
20345 | |
20346 | OpenMP 4.0: |
20347 | update-stmt: |
20348 | expression-stmt | x = x binop expr | x = expr binop x |
20349 | capture-stmt: |
20350 | v = update-stmt |
20351 | capture-block: |
20352 | { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } |
20353 | |
20354 | OpenMP 5.1: |
20355 | # pragma omp atomic compare new-line |
20356 | conditional-update-atomic |
20357 | |
20358 | # pragma omp atomic compare capture new-line |
20359 | conditional-update-capture-atomic |
20360 | |
20361 | conditional-update-atomic: |
20362 | cond-expr-stmt | cond-update-stmt |
20363 | cond-expr-stmt: |
20364 | x = expr ordop x ? expr : x; |
20365 | x = x ordop expr ? expr : x; |
20366 | x = x == e ? d : x; |
20367 | cond-update-stmt: |
20368 | if (expr ordop x) { x = expr; } |
20369 | if (x ordop expr) { x = expr; } |
20370 | if (x == e) { x = d; } |
20371 | ordop: |
20372 | <, > |
20373 | conditional-update-capture-atomic: |
20374 | v = cond-expr-stmt |
20375 | { v = x; cond-expr-stmt } |
20376 | { cond-expr-stmt v = x; } |
20377 | { v = x; cond-update-stmt } |
20378 | { cond-update-stmt v = x; } |
20379 | if (x == e) { x = d; } else { v = x; } |
20380 | { r = x == e; if (r) { x = d; } } |
20381 | { r = x == e; if (r) { x = d; } else { v = x; } } |
20382 | |
20383 | where x, r and v are lvalue expressions with scalar type, |
20384 | expr, e and d are expressions with scalar type and e might be |
20385 | the same as v. |
20386 | |
20387 | LOC is the location of the #pragma token. */ |
20388 | |
20389 | static void |
20390 | c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) |
20391 | { |
20392 | tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE; |
20393 | tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; |
20394 | tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; |
20395 | enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; |
20396 | enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; |
20397 | struct c_expr expr; |
20398 | location_t eloc; |
20399 | bool structured_block = false; |
20400 | bool swapped = false; |
20401 | bool non_lvalue_p; |
20402 | tree clauses = NULL_TREE; |
20403 | bool capture = false; |
20404 | bool compare = false; |
20405 | bool weak = false; |
20406 | enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; |
20407 | bool no_semicolon = false; |
20408 | bool = false; |
20409 | |
20410 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
20411 | { |
20412 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
20413 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
20414 | c_parser_consume_token (parser); |
20415 | |
20416 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
20417 | { |
20418 | const char *p |
20419 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20420 | location_t cloc = c_parser_peek_token (parser)->location; |
20421 | enum tree_code new_code = ERROR_MARK; |
20422 | enum omp_memory_order new_memory_order |
20423 | = OMP_MEMORY_ORDER_UNSPECIFIED; |
20424 | bool new_capture = false; |
20425 | bool new_compare = false; |
20426 | bool new_weak = false; |
20427 | enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; |
20428 | |
20429 | if (!strcmp (s1: p, s2: "read" )) |
20430 | new_code = OMP_ATOMIC_READ; |
20431 | else if (!strcmp (s1: p, s2: "write" )) |
20432 | new_code = NOP_EXPR; |
20433 | else if (!strcmp (s1: p, s2: "update" )) |
20434 | new_code = OMP_ATOMIC; |
20435 | else if (openacc && !strcmp (s1: p, s2: "capture" )) |
20436 | new_code = OMP_ATOMIC_CAPTURE_NEW; |
20437 | else if (openacc) |
20438 | { |
20439 | p = NULL; |
20440 | error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " |
20441 | "or %<capture%> clause" ); |
20442 | } |
20443 | else if (!strcmp (s1: p, s2: "capture" )) |
20444 | new_capture = true; |
20445 | else if (!strcmp (s1: p, s2: "compare" )) |
20446 | new_compare = true; |
20447 | else if (!strcmp (s1: p, s2: "weak" )) |
20448 | new_weak = true; |
20449 | else if (!strcmp (s1: p, s2: "fail" )) |
20450 | { |
20451 | matching_parens parens; |
20452 | |
20453 | c_parser_consume_token (parser); |
20454 | if (!parens.require_open (parser)) |
20455 | continue; |
20456 | |
20457 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
20458 | { |
20459 | const char *q |
20460 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20461 | |
20462 | if (!strcmp (s1: q, s2: "seq_cst" )) |
20463 | new_fail = OMP_MEMORY_ORDER_SEQ_CST; |
20464 | else if (!strcmp (s1: q, s2: "acquire" )) |
20465 | new_fail = OMP_MEMORY_ORDER_ACQUIRE; |
20466 | else if (!strcmp (s1: q, s2: "relaxed" )) |
20467 | new_fail = OMP_MEMORY_ORDER_RELAXED; |
20468 | } |
20469 | |
20470 | if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED) |
20471 | { |
20472 | c_parser_consume_token (parser); |
20473 | if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) |
20474 | error_at (cloc, "too many %qs clauses" , "fail" ); |
20475 | else |
20476 | fail = new_fail; |
20477 | } |
20478 | else |
20479 | c_parser_error (parser, gmsgid: "expected %<seq_cst%>, %<acquire%> " |
20480 | "or %<relaxed%>" ); |
20481 | parens.skip_until_found_close (parser); |
20482 | continue; |
20483 | } |
20484 | else if (!strcmp (s1: p, s2: "seq_cst" )) |
20485 | new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
20486 | else if (!strcmp (s1: p, s2: "acq_rel" )) |
20487 | new_memory_order = OMP_MEMORY_ORDER_ACQ_REL; |
20488 | else if (!strcmp (s1: p, s2: "release" )) |
20489 | new_memory_order = OMP_MEMORY_ORDER_RELEASE; |
20490 | else if (!strcmp (s1: p, s2: "acquire" )) |
20491 | new_memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
20492 | else if (!strcmp (s1: p, s2: "relaxed" )) |
20493 | new_memory_order = OMP_MEMORY_ORDER_RELAXED; |
20494 | else if (!strcmp (s1: p, s2: "hint" )) |
20495 | { |
20496 | c_parser_consume_token (parser); |
20497 | clauses = c_parser_omp_clause_hint (parser, list: clauses); |
20498 | continue; |
20499 | } |
20500 | else |
20501 | { |
20502 | p = NULL; |
20503 | error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " |
20504 | "%<capture%>, %<compare%>, %<weak%>, %<fail%>, " |
20505 | "%<seq_cst%>, %<acq_rel%>, %<release%>, " |
20506 | "%<relaxed%> or %<hint%> clause" ); |
20507 | } |
20508 | if (p) |
20509 | { |
20510 | if (new_code != ERROR_MARK) |
20511 | { |
20512 | /* OpenACC permits 'update capture'. */ |
20513 | if (openacc |
20514 | && code == OMP_ATOMIC |
20515 | && new_code == OMP_ATOMIC_CAPTURE_NEW) |
20516 | code = new_code; |
20517 | else if (code != ERROR_MARK) |
20518 | error_at (cloc, "too many atomic clauses" ); |
20519 | else |
20520 | code = new_code; |
20521 | } |
20522 | else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) |
20523 | { |
20524 | if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) |
20525 | error_at (cloc, "too many memory order clauses" ); |
20526 | else |
20527 | memory_order = new_memory_order; |
20528 | } |
20529 | else if (new_capture) |
20530 | { |
20531 | if (capture) |
20532 | error_at (cloc, "too many %qs clauses" , "capture" ); |
20533 | else |
20534 | capture = true; |
20535 | } |
20536 | else if (new_compare) |
20537 | { |
20538 | if (compare) |
20539 | error_at (cloc, "too many %qs clauses" , "compare" ); |
20540 | else |
20541 | compare = true; |
20542 | } |
20543 | else if (new_weak) |
20544 | { |
20545 | if (weak) |
20546 | error_at (cloc, "too many %qs clauses" , "weak" ); |
20547 | else |
20548 | weak = true; |
20549 | } |
20550 | c_parser_consume_token (parser); |
20551 | continue; |
20552 | } |
20553 | } |
20554 | break; |
20555 | } |
20556 | c_parser_skip_to_pragma_eol (parser); |
20557 | |
20558 | if (code == ERROR_MARK) |
20559 | code = OMP_ATOMIC; |
20560 | if (capture) |
20561 | { |
20562 | if (code != OMP_ATOMIC) |
20563 | error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " |
20564 | "clauses" , "capture" ); |
20565 | else |
20566 | code = OMP_ATOMIC_CAPTURE_NEW; |
20567 | } |
20568 | if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW) |
20569 | { |
20570 | error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " |
20571 | "clauses" , "compare" ); |
20572 | compare = false; |
20573 | } |
20574 | if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) |
20575 | { |
20576 | error_at (loc, "%qs clause requires %qs clause" , "fail" , "compare" ); |
20577 | fail = OMP_MEMORY_ORDER_UNSPECIFIED; |
20578 | } |
20579 | if (weak && !compare) |
20580 | { |
20581 | error_at (loc, "%qs clause requires %qs clause" , "weak" , "compare" ); |
20582 | weak = false; |
20583 | } |
20584 | if (openacc) |
20585 | memory_order = OMP_MEMORY_ORDER_RELAXED; |
20586 | else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) |
20587 | { |
20588 | omp_requires_mask |
20589 | = (enum omp_requires) (omp_requires_mask |
20590 | | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED); |
20591 | switch ((enum omp_memory_order) |
20592 | (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER)) |
20593 | { |
20594 | case OMP_MEMORY_ORDER_UNSPECIFIED: |
20595 | case OMP_MEMORY_ORDER_RELAXED: |
20596 | memory_order = OMP_MEMORY_ORDER_RELAXED; |
20597 | break; |
20598 | case OMP_MEMORY_ORDER_SEQ_CST: |
20599 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
20600 | break; |
20601 | case OMP_MEMORY_ORDER_ACQ_REL: |
20602 | switch (code) |
20603 | { |
20604 | case OMP_ATOMIC_READ: |
20605 | memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
20606 | break; |
20607 | case NOP_EXPR: /* atomic write */ |
20608 | memory_order = OMP_MEMORY_ORDER_RELEASE; |
20609 | break; |
20610 | default: |
20611 | memory_order = OMP_MEMORY_ORDER_ACQ_REL; |
20612 | break; |
20613 | } |
20614 | break; |
20615 | default: |
20616 | gcc_unreachable (); |
20617 | } |
20618 | } |
20619 | else |
20620 | switch (code) |
20621 | { |
20622 | case OMP_ATOMIC_READ: |
20623 | if (memory_order == OMP_MEMORY_ORDER_RELEASE) |
20624 | { |
20625 | error_at (loc, "%<#pragma omp atomic read%> incompatible with " |
20626 | "%<release%> clause" ); |
20627 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
20628 | } |
20629 | else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) |
20630 | memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
20631 | break; |
20632 | case NOP_EXPR: /* atomic write */ |
20633 | if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) |
20634 | { |
20635 | error_at (loc, "%<#pragma omp atomic write%> incompatible with " |
20636 | "%<acquire%> clause" ); |
20637 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
20638 | } |
20639 | else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) |
20640 | memory_order = OMP_MEMORY_ORDER_RELEASE; |
20641 | break; |
20642 | default: |
20643 | break; |
20644 | } |
20645 | if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) |
20646 | memory_order |
20647 | = (enum omp_memory_order) (memory_order |
20648 | | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); |
20649 | |
20650 | switch (code) |
20651 | { |
20652 | case OMP_ATOMIC_READ: |
20653 | case NOP_EXPR: /* atomic write */ |
20654 | v = c_parser_cast_expression (parser, NULL).value; |
20655 | non_lvalue_p = !lvalue_p (v); |
20656 | v = c_fully_fold (v, false, NULL, true); |
20657 | if (v == error_mark_node) |
20658 | goto saw_error; |
20659 | if (non_lvalue_p) |
20660 | v = non_lvalue (v); |
20661 | loc = c_parser_peek_token (parser)->location; |
20662 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
20663 | goto saw_error; |
20664 | if (code == NOP_EXPR) |
20665 | { |
20666 | lhs = c_parser_expression (parser).value; |
20667 | lhs = c_fully_fold (lhs, false, NULL); |
20668 | if (lhs == error_mark_node) |
20669 | goto saw_error; |
20670 | } |
20671 | else |
20672 | { |
20673 | lhs = c_parser_cast_expression (parser, NULL).value; |
20674 | non_lvalue_p = !lvalue_p (lhs); |
20675 | lhs = c_fully_fold (lhs, false, NULL, true); |
20676 | if (lhs == error_mark_node) |
20677 | goto saw_error; |
20678 | if (non_lvalue_p) |
20679 | lhs = non_lvalue (lhs); |
20680 | } |
20681 | if (code == NOP_EXPR) |
20682 | { |
20683 | /* atomic write is represented by OMP_ATOMIC with NOP_EXPR |
20684 | opcode. */ |
20685 | code = OMP_ATOMIC; |
20686 | rhs = lhs; |
20687 | lhs = v; |
20688 | v = NULL_TREE; |
20689 | } |
20690 | goto done; |
20691 | case OMP_ATOMIC_CAPTURE_NEW: |
20692 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
20693 | { |
20694 | c_parser_consume_token (parser); |
20695 | structured_block = true; |
20696 | } |
20697 | else if (compare |
20698 | && c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
20699 | break; |
20700 | else |
20701 | { |
20702 | v = c_parser_cast_expression (parser, NULL).value; |
20703 | non_lvalue_p = !lvalue_p (v); |
20704 | v = c_fully_fold (v, false, NULL, true); |
20705 | if (v == error_mark_node) |
20706 | goto saw_error; |
20707 | if (non_lvalue_p) |
20708 | v = non_lvalue (v); |
20709 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
20710 | goto saw_error; |
20711 | if (compare && c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
20712 | { |
20713 | eloc = c_parser_peek_token (parser)->location; |
20714 | error_at (eloc, "expected expression" ); |
20715 | goto saw_error; |
20716 | } |
20717 | } |
20718 | break; |
20719 | default: |
20720 | break; |
20721 | } |
20722 | |
20723 | /* For structured_block case we don't know yet whether |
20724 | old or new x should be captured. */ |
20725 | restart: |
20726 | if (compare && c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
20727 | { |
20728 | c_parser_consume_token (parser); |
20729 | |
20730 | matching_parens parens; |
20731 | if (!parens.require_open (parser)) |
20732 | goto saw_error; |
20733 | eloc = c_parser_peek_token (parser)->location; |
20734 | c_expr cmp_expr; |
20735 | if (r) |
20736 | { |
20737 | cmp_expr = c_parser_cast_expression (parser, NULL); |
20738 | cmp_expr = default_function_array_conversion (eloc, cmp_expr); |
20739 | } |
20740 | else |
20741 | cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node); |
20742 | parens.skip_until_found_close (parser); |
20743 | if (cmp_expr.value == error_mark_node) |
20744 | goto saw_error; |
20745 | if (r) |
20746 | { |
20747 | if (!c_tree_equal (cmp_expr.value, unfolded_lhs)) |
20748 | goto bad_if; |
20749 | cmp_expr.value = rhs1; |
20750 | rhs1 = NULL_TREE; |
20751 | gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR); |
20752 | } |
20753 | if (TREE_CODE (cmp_expr.value) == EQ_EXPR) |
20754 | ; |
20755 | else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) |
20756 | { |
20757 | error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), |
20758 | "expected %<==%> comparison in %<if%> condition" ); |
20759 | goto saw_error; |
20760 | } |
20761 | else if (TREE_CODE (cmp_expr.value) != GT_EXPR |
20762 | && TREE_CODE (cmp_expr.value) != LT_EXPR) |
20763 | { |
20764 | error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), |
20765 | "expected %<==%>, %<<%> or %<>%> comparison in %<if%> " |
20766 | "condition" ); |
20767 | goto saw_error; |
20768 | } |
20769 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
20770 | goto saw_error; |
20771 | |
20772 | extra_scope = true; |
20773 | eloc = c_parser_peek_token (parser)->location; |
20774 | expr = c_parser_cast_expression (parser, NULL); |
20775 | lhs = expr.value; |
20776 | expr = default_function_array_conversion (eloc, expr); |
20777 | unfolded_lhs = expr.value; |
20778 | lhs = c_fully_fold (lhs, false, NULL, true); |
20779 | orig_lhs = lhs; |
20780 | if (lhs == error_mark_node) |
20781 | goto saw_error; |
20782 | if (!lvalue_p (unfolded_lhs)) |
20783 | lhs = non_lvalue (lhs); |
20784 | if (!c_parser_next_token_is (parser, type: CPP_EQ)) |
20785 | { |
20786 | c_parser_error (parser, gmsgid: "expected %<=%>" ); |
20787 | goto saw_error; |
20788 | } |
20789 | c_parser_consume_token (parser); |
20790 | eloc = c_parser_peek_token (parser)->location; |
20791 | expr = c_parser_expr_no_commas (parser, NULL); |
20792 | rhs1 = expr.value; |
20793 | |
20794 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
20795 | goto saw_error; |
20796 | |
20797 | if (!c_parser_require (parser, type: CPP_CLOSE_BRACE, msgid: "expected %<}%>" )) |
20798 | goto saw_error; |
20799 | |
20800 | extra_scope = false; |
20801 | no_semicolon = true; |
20802 | |
20803 | if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs)) |
20804 | { |
20805 | if (TREE_CODE (cmp_expr.value) == EQ_EXPR) |
20806 | { |
20807 | opcode = COND_EXPR; |
20808 | rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), |
20809 | false, NULL, true); |
20810 | rhs1 = c_fully_fold (rhs1, false, NULL, true); |
20811 | } |
20812 | else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1)) |
20813 | { |
20814 | opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR |
20815 | ? MIN_EXPR : MAX_EXPR); |
20816 | rhs = c_fully_fold (rhs1, false, NULL, true); |
20817 | rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0), |
20818 | false, NULL, true); |
20819 | } |
20820 | else |
20821 | goto bad_if; |
20822 | } |
20823 | else if (TREE_CODE (cmp_expr.value) == EQ_EXPR) |
20824 | goto bad_if; |
20825 | else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs) |
20826 | && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1)) |
20827 | { |
20828 | opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR |
20829 | ? MAX_EXPR : MIN_EXPR); |
20830 | rhs = c_fully_fold (rhs1, false, NULL, true); |
20831 | rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), |
20832 | false, NULL, true); |
20833 | } |
20834 | else |
20835 | { |
20836 | bad_if: |
20837 | c_parser_error (parser, |
20838 | gmsgid: "invalid form of %<#pragma omp atomic compare%>" ); |
20839 | goto saw_error; |
20840 | } |
20841 | |
20842 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
20843 | { |
20844 | if (code != OMP_ATOMIC_CAPTURE_NEW |
20845 | || (structured_block && r == NULL_TREE) |
20846 | || TREE_CODE (cmp_expr.value) != EQ_EXPR) |
20847 | { |
20848 | eloc = c_parser_peek_token (parser)->location; |
20849 | error_at (eloc, "unexpected %<else%>" ); |
20850 | goto saw_error; |
20851 | } |
20852 | |
20853 | c_parser_consume_token (parser); |
20854 | |
20855 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
20856 | goto saw_error; |
20857 | |
20858 | extra_scope = true; |
20859 | v = c_parser_cast_expression (parser, NULL).value; |
20860 | non_lvalue_p = !lvalue_p (v); |
20861 | v = c_fully_fold (v, false, NULL, true); |
20862 | if (v == error_mark_node) |
20863 | goto saw_error; |
20864 | if (non_lvalue_p) |
20865 | v = non_lvalue (v); |
20866 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
20867 | goto saw_error; |
20868 | |
20869 | expr = c_parser_expr_no_commas (parser, NULL); |
20870 | |
20871 | if (!c_tree_equal (expr.value, unfolded_lhs)) |
20872 | goto bad_if; |
20873 | |
20874 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
20875 | goto saw_error; |
20876 | |
20877 | if (!c_parser_require (parser, type: CPP_CLOSE_BRACE, msgid: "expected %<}%>" )) |
20878 | goto saw_error; |
20879 | |
20880 | extra_scope = false; |
20881 | code = OMP_ATOMIC_CAPTURE_OLD; |
20882 | if (r == NULL_TREE) |
20883 | /* Signal to c_finish_omp_atomic that in |
20884 | if (x == e) { x = d; } else { v = x; } |
20885 | case the store to v should be conditional. */ |
20886 | r = void_list_node; |
20887 | } |
20888 | else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) |
20889 | { |
20890 | c_parser_require_keyword (parser, keyword: RID_ELSE, msgid: "expected %<else%>" ); |
20891 | goto saw_error; |
20892 | } |
20893 | else if (code == OMP_ATOMIC_CAPTURE_NEW |
20894 | && r != NULL_TREE |
20895 | && v == NULL_TREE) |
20896 | code = OMP_ATOMIC; |
20897 | goto stmt_done; |
20898 | } |
20899 | eloc = c_parser_peek_token (parser)->location; |
20900 | expr = c_parser_cast_expression (parser, NULL); |
20901 | lhs = expr.value; |
20902 | expr = default_function_array_conversion (eloc, expr); |
20903 | unfolded_lhs = expr.value; |
20904 | lhs = c_fully_fold (lhs, false, NULL, true); |
20905 | orig_lhs = lhs; |
20906 | switch (TREE_CODE (lhs)) |
20907 | { |
20908 | invalid_compare: |
20909 | error_at (eloc, "invalid form of %<pragma omp atomic compare%>" ); |
20910 | /* FALLTHRU */ |
20911 | case ERROR_MARK: |
20912 | saw_error: |
20913 | c_parser_skip_to_end_of_block_or_statement (parser); |
20914 | if (extra_scope && c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
20915 | c_parser_consume_token (parser); |
20916 | if (structured_block) |
20917 | { |
20918 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
20919 | c_parser_consume_token (parser); |
20920 | else if (code == OMP_ATOMIC_CAPTURE_NEW) |
20921 | { |
20922 | c_parser_skip_to_end_of_block_or_statement (parser); |
20923 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
20924 | c_parser_consume_token (parser); |
20925 | } |
20926 | } |
20927 | return; |
20928 | |
20929 | case POSTINCREMENT_EXPR: |
20930 | if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) |
20931 | code = OMP_ATOMIC_CAPTURE_OLD; |
20932 | /* FALLTHROUGH */ |
20933 | case PREINCREMENT_EXPR: |
20934 | lhs = TREE_OPERAND (lhs, 0); |
20935 | unfolded_lhs = NULL_TREE; |
20936 | opcode = PLUS_EXPR; |
20937 | rhs = integer_one_node; |
20938 | if (compare) |
20939 | goto invalid_compare; |
20940 | break; |
20941 | |
20942 | case POSTDECREMENT_EXPR: |
20943 | if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) |
20944 | code = OMP_ATOMIC_CAPTURE_OLD; |
20945 | /* FALLTHROUGH */ |
20946 | case PREDECREMENT_EXPR: |
20947 | lhs = TREE_OPERAND (lhs, 0); |
20948 | unfolded_lhs = NULL_TREE; |
20949 | opcode = MINUS_EXPR; |
20950 | rhs = integer_one_node; |
20951 | if (compare) |
20952 | goto invalid_compare; |
20953 | break; |
20954 | |
20955 | case COMPOUND_EXPR: |
20956 | if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR |
20957 | && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR |
20958 | && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR |
20959 | && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) |
20960 | && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND |
20961 | (TREE_OPERAND (lhs, 1), 0), 0)))) |
20962 | /* Undo effects of boolean_increment for post {in,de}crement. */ |
20963 | lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); |
20964 | /* FALLTHRU */ |
20965 | case MODIFY_EXPR: |
20966 | if (TREE_CODE (lhs) == MODIFY_EXPR |
20967 | && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0)))) |
20968 | { |
20969 | /* Undo effects of boolean_increment. */ |
20970 | if (integer_onep (TREE_OPERAND (lhs, 1))) |
20971 | { |
20972 | /* This is pre or post increment. */ |
20973 | rhs = TREE_OPERAND (lhs, 1); |
20974 | lhs = TREE_OPERAND (lhs, 0); |
20975 | unfolded_lhs = NULL_TREE; |
20976 | opcode = NOP_EXPR; |
20977 | if (code == OMP_ATOMIC_CAPTURE_NEW |
20978 | && !structured_block |
20979 | && TREE_CODE (orig_lhs) == COMPOUND_EXPR) |
20980 | code = OMP_ATOMIC_CAPTURE_OLD; |
20981 | if (compare) |
20982 | goto invalid_compare; |
20983 | break; |
20984 | } |
20985 | if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR |
20986 | && TREE_OPERAND (lhs, 0) |
20987 | == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) |
20988 | { |
20989 | /* This is pre or post decrement. */ |
20990 | rhs = TREE_OPERAND (lhs, 1); |
20991 | lhs = TREE_OPERAND (lhs, 0); |
20992 | unfolded_lhs = NULL_TREE; |
20993 | opcode = NOP_EXPR; |
20994 | if (code == OMP_ATOMIC_CAPTURE_NEW |
20995 | && !structured_block |
20996 | && TREE_CODE (orig_lhs) == COMPOUND_EXPR) |
20997 | code = OMP_ATOMIC_CAPTURE_OLD; |
20998 | if (compare) |
20999 | goto invalid_compare; |
21000 | break; |
21001 | } |
21002 | } |
21003 | /* FALLTHRU */ |
21004 | default: |
21005 | if (!lvalue_p (unfolded_lhs)) |
21006 | lhs = non_lvalue (lhs); |
21007 | if (compare && !c_parser_next_token_is (parser, type: CPP_EQ)) |
21008 | { |
21009 | c_parser_error (parser, gmsgid: "expected %<=%>" ); |
21010 | goto saw_error; |
21011 | } |
21012 | switch (c_parser_peek_token (parser)->type) |
21013 | { |
21014 | case CPP_MULT_EQ: |
21015 | opcode = MULT_EXPR; |
21016 | break; |
21017 | case CPP_DIV_EQ: |
21018 | opcode = TRUNC_DIV_EXPR; |
21019 | break; |
21020 | case CPP_PLUS_EQ: |
21021 | opcode = PLUS_EXPR; |
21022 | break; |
21023 | case CPP_MINUS_EQ: |
21024 | opcode = MINUS_EXPR; |
21025 | break; |
21026 | case CPP_LSHIFT_EQ: |
21027 | opcode = LSHIFT_EXPR; |
21028 | break; |
21029 | case CPP_RSHIFT_EQ: |
21030 | opcode = RSHIFT_EXPR; |
21031 | break; |
21032 | case CPP_AND_EQ: |
21033 | opcode = BIT_AND_EXPR; |
21034 | break; |
21035 | case CPP_OR_EQ: |
21036 | opcode = BIT_IOR_EXPR; |
21037 | break; |
21038 | case CPP_XOR_EQ: |
21039 | opcode = BIT_XOR_EXPR; |
21040 | break; |
21041 | case CPP_EQ: |
21042 | c_parser_consume_token (parser); |
21043 | eloc = c_parser_peek_token (parser)->location; |
21044 | expr = c_parser_expr_no_commas (parser, NULL, omp_atomic_lhs: unfolded_lhs); |
21045 | rhs1 = expr.value; |
21046 | switch (TREE_CODE (rhs1)) |
21047 | { |
21048 | case MULT_EXPR: |
21049 | case TRUNC_DIV_EXPR: |
21050 | case RDIV_EXPR: |
21051 | case PLUS_EXPR: |
21052 | case MINUS_EXPR: |
21053 | case LSHIFT_EXPR: |
21054 | case RSHIFT_EXPR: |
21055 | case BIT_AND_EXPR: |
21056 | case BIT_IOR_EXPR: |
21057 | case BIT_XOR_EXPR: |
21058 | if (compare) |
21059 | break; |
21060 | if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) |
21061 | { |
21062 | opcode = TREE_CODE (rhs1); |
21063 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21064 | true); |
21065 | rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, |
21066 | true); |
21067 | goto stmt_done; |
21068 | } |
21069 | if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) |
21070 | { |
21071 | opcode = TREE_CODE (rhs1); |
21072 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, |
21073 | true); |
21074 | rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21075 | true); |
21076 | swapped = !commutative_tree_code (opcode); |
21077 | goto stmt_done; |
21078 | } |
21079 | break; |
21080 | case COND_EXPR: |
21081 | if (!compare) |
21082 | break; |
21083 | if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR |
21084 | && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR |
21085 | && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR) |
21086 | break; |
21087 | if (!TREE_OPERAND (rhs1, 1)) |
21088 | break; |
21089 | if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs)) |
21090 | break; |
21091 | if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), |
21092 | unfolded_lhs)) |
21093 | { |
21094 | if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) |
21095 | { |
21096 | opcode = COND_EXPR; |
21097 | rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, |
21098 | 0), 1), |
21099 | false, NULL, true); |
21100 | rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, |
21101 | NULL, true); |
21102 | goto stmt_done; |
21103 | } |
21104 | if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), |
21105 | TREE_OPERAND (rhs1, 1))) |
21106 | { |
21107 | opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR |
21108 | ? MIN_EXPR : MAX_EXPR); |
21109 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21110 | true); |
21111 | rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, |
21112 | 0), 0), |
21113 | false, NULL, true); |
21114 | goto stmt_done; |
21115 | } |
21116 | } |
21117 | else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) |
21118 | break; |
21119 | else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), |
21120 | unfolded_lhs)) |
21121 | { |
21122 | if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), |
21123 | TREE_OPERAND (rhs1, 1))) |
21124 | { |
21125 | opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR |
21126 | ? MAX_EXPR : MIN_EXPR); |
21127 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21128 | true); |
21129 | rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, |
21130 | 0), 1), |
21131 | false, NULL, true); |
21132 | goto stmt_done; |
21133 | } |
21134 | } |
21135 | break; |
21136 | case EQ_EXPR: |
21137 | if (!compare |
21138 | || code != OMP_ATOMIC_CAPTURE_NEW |
21139 | || !structured_block |
21140 | || v |
21141 | || r) |
21142 | break; |
21143 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
21144 | && c_parser_peek_2nd_token (parser)->keyword == RID_IF) |
21145 | { |
21146 | r = lhs; |
21147 | lhs = NULL_TREE; |
21148 | c_parser_consume_token (parser); |
21149 | goto restart; |
21150 | } |
21151 | break; |
21152 | case ERROR_MARK: |
21153 | goto saw_error; |
21154 | default: |
21155 | break; |
21156 | } |
21157 | if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) |
21158 | { |
21159 | if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) |
21160 | { |
21161 | code = OMP_ATOMIC_CAPTURE_OLD; |
21162 | v = lhs; |
21163 | lhs = NULL_TREE; |
21164 | expr = default_function_array_read_conversion (eloc, expr); |
21165 | unfolded_lhs1 = expr.value; |
21166 | lhs1 = c_fully_fold (unfolded_lhs1, false, NULL, true); |
21167 | rhs1 = NULL_TREE; |
21168 | c_parser_consume_token (parser); |
21169 | goto restart; |
21170 | } |
21171 | if (structured_block && !compare) |
21172 | { |
21173 | opcode = NOP_EXPR; |
21174 | expr = default_function_array_read_conversion (eloc, expr); |
21175 | rhs = c_fully_fold (expr.value, false, NULL, true); |
21176 | rhs1 = NULL_TREE; |
21177 | goto stmt_done; |
21178 | } |
21179 | } |
21180 | c_parser_error (parser, gmsgid: "invalid form of %<#pragma omp atomic%>" ); |
21181 | goto saw_error; |
21182 | default: |
21183 | c_parser_error (parser, |
21184 | gmsgid: "invalid operator for %<#pragma omp atomic%>" ); |
21185 | goto saw_error; |
21186 | } |
21187 | |
21188 | /* Arrange to pass the location of the assignment operator to |
21189 | c_finish_omp_atomic. */ |
21190 | loc = c_parser_peek_token (parser)->location; |
21191 | c_parser_consume_token (parser); |
21192 | eloc = c_parser_peek_token (parser)->location; |
21193 | expr = c_parser_expression (parser); |
21194 | expr = default_function_array_read_conversion (eloc, expr); |
21195 | rhs = expr.value; |
21196 | rhs = c_fully_fold (rhs, false, NULL, true); |
21197 | break; |
21198 | } |
21199 | stmt_done: |
21200 | if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE) |
21201 | { |
21202 | if (!no_semicolon |
21203 | && !c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
21204 | goto saw_error; |
21205 | no_semicolon = false; |
21206 | v = c_parser_cast_expression (parser, NULL).value; |
21207 | non_lvalue_p = !lvalue_p (v); |
21208 | v = c_fully_fold (v, false, NULL, true); |
21209 | if (v == error_mark_node) |
21210 | goto saw_error; |
21211 | if (non_lvalue_p) |
21212 | v = non_lvalue (v); |
21213 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
21214 | goto saw_error; |
21215 | eloc = c_parser_peek_token (parser)->location; |
21216 | expr = c_parser_cast_expression (parser, NULL); |
21217 | lhs1 = expr.value; |
21218 | expr = default_function_array_read_conversion (eloc, expr); |
21219 | unfolded_lhs1 = expr.value; |
21220 | lhs1 = c_fully_fold (lhs1, false, NULL, true); |
21221 | if (lhs1 == error_mark_node) |
21222 | goto saw_error; |
21223 | if (!lvalue_p (unfolded_lhs1)) |
21224 | lhs1 = non_lvalue (lhs1); |
21225 | } |
21226 | if (structured_block) |
21227 | { |
21228 | if (!no_semicolon) |
21229 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
21230 | c_parser_require (parser, type: CPP_CLOSE_BRACE, msgid: "expected %<}%>" ); |
21231 | } |
21232 | done: |
21233 | if (weak && opcode != COND_EXPR) |
21234 | { |
21235 | error_at (loc, "%<weak%> clause requires atomic equality comparison" ); |
21236 | weak = false; |
21237 | } |
21238 | if (unfolded_lhs && unfolded_lhs1 |
21239 | && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) |
21240 | { |
21241 | error ("%<#pragma omp atomic capture%> uses two different " |
21242 | "expressions for memory" ); |
21243 | stmt = error_mark_node; |
21244 | } |
21245 | else |
21246 | stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r, |
21247 | swapped, memory_order, weak); |
21248 | if (stmt != error_mark_node) |
21249 | add_stmt (stmt); |
21250 | |
21251 | if (!structured_block && !no_semicolon) |
21252 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
21253 | } |
21254 | |
21255 | |
21256 | /* OpenMP 2.5: |
21257 | # pragma omp barrier new-line |
21258 | */ |
21259 | |
21260 | static void |
21261 | c_parser_omp_barrier (c_parser *parser) |
21262 | { |
21263 | location_t loc = c_parser_peek_token (parser)->location; |
21264 | c_parser_consume_pragma (parser); |
21265 | c_parser_skip_to_pragma_eol (parser); |
21266 | |
21267 | c_finish_omp_barrier (loc); |
21268 | } |
21269 | |
21270 | /* OpenMP 2.5: |
21271 | # pragma omp critical [(name)] new-line |
21272 | structured-block |
21273 | |
21274 | OpenMP 4.5: |
21275 | # pragma omp critical [(name) [hint(expression)]] new-line |
21276 | |
21277 | LOC is the location of the #pragma itself. */ |
21278 | |
21279 | #define OMP_CRITICAL_CLAUSE_MASK \ |
21280 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) ) |
21281 | |
21282 | static tree |
21283 | c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p) |
21284 | { |
21285 | tree stmt, name = NULL_TREE, clauses = NULL_TREE; |
21286 | |
21287 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
21288 | { |
21289 | c_parser_consume_token (parser); |
21290 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21291 | { |
21292 | name = c_parser_peek_token (parser)->value; |
21293 | c_parser_consume_token (parser); |
21294 | c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" ); |
21295 | } |
21296 | else |
21297 | c_parser_error (parser, gmsgid: "expected identifier" ); |
21298 | |
21299 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
21300 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
21301 | c_parser_consume_token (parser); |
21302 | } |
21303 | clauses = c_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK, |
21304 | where: "#pragma omp critical" ); |
21305 | stmt = c_parser_omp_structured_block (parser, if_p); |
21306 | return c_finish_omp_critical (loc, stmt, name, clauses); |
21307 | } |
21308 | |
21309 | /* OpenMP 5.0: |
21310 | # pragma omp depobj ( depobj ) depobj-clause new-line |
21311 | |
21312 | depobj-clause: |
21313 | depend (dependence-type : locator) |
21314 | destroy |
21315 | update (dependence-type) |
21316 | |
21317 | dependence-type: |
21318 | in |
21319 | out |
21320 | inout |
21321 | mutexinout */ |
21322 | |
21323 | static void |
21324 | c_parser_omp_depobj (c_parser *parser) |
21325 | { |
21326 | location_t loc = c_parser_peek_token (parser)->location; |
21327 | c_parser_consume_pragma (parser); |
21328 | matching_parens parens; |
21329 | if (!parens.require_open (parser)) |
21330 | { |
21331 | c_parser_skip_to_pragma_eol (parser); |
21332 | return; |
21333 | } |
21334 | |
21335 | tree depobj = c_parser_expr_no_commas (parser, NULL).value; |
21336 | if (depobj != error_mark_node) |
21337 | { |
21338 | if (!lvalue_p (depobj)) |
21339 | { |
21340 | error_at (EXPR_LOC_OR_LOC (depobj, loc), |
21341 | "%<depobj%> expression is not lvalue expression" ); |
21342 | depobj = error_mark_node; |
21343 | } |
21344 | else |
21345 | { |
21346 | tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR, |
21347 | depobj, false); |
21348 | if (addr == error_mark_node) |
21349 | depobj = error_mark_node; |
21350 | else |
21351 | depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc), |
21352 | addr, RO_UNARY_STAR); |
21353 | } |
21354 | } |
21355 | |
21356 | parens.skip_until_found_close (parser); |
21357 | tree clause = NULL_TREE; |
21358 | enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID; |
21359 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
21360 | c_parser_consume_token (parser); |
21361 | location_t c_loc = c_parser_peek_token (parser)->location; |
21362 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21363 | { |
21364 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21365 | |
21366 | c_parser_consume_token (parser); |
21367 | if (!strcmp (s1: "depend" , s2: p)) |
21368 | { |
21369 | clause = c_parser_omp_clause_depend (parser, NULL_TREE); |
21370 | clause = c_finish_omp_clauses (clause, C_ORT_OMP); |
21371 | if (!clause) |
21372 | clause = error_mark_node; |
21373 | } |
21374 | else if (!strcmp (s1: "destroy" , s2: p)) |
21375 | kind = OMP_CLAUSE_DEPEND_LAST; |
21376 | else if (!strcmp (s1: "update" , s2: p)) |
21377 | { |
21378 | matching_parens c_parens; |
21379 | if (c_parens.require_open (parser)) |
21380 | { |
21381 | location_t c2_loc = c_parser_peek_token (parser)->location; |
21382 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21383 | { |
21384 | const char *p2 |
21385 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21386 | |
21387 | c_parser_consume_token (parser); |
21388 | if (!strcmp (s1: "in" , s2: p2)) |
21389 | kind = OMP_CLAUSE_DEPEND_IN; |
21390 | else if (!strcmp (s1: "out" , s2: p2)) |
21391 | kind = OMP_CLAUSE_DEPEND_OUT; |
21392 | else if (!strcmp (s1: "inout" , s2: p2)) |
21393 | kind = OMP_CLAUSE_DEPEND_INOUT; |
21394 | else if (!strcmp (s1: "mutexinoutset" , s2: p2)) |
21395 | kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; |
21396 | else if (!strcmp (s1: "inoutset" , s2: p2)) |
21397 | kind = OMP_CLAUSE_DEPEND_INOUTSET; |
21398 | } |
21399 | if (kind == OMP_CLAUSE_DEPEND_INVALID) |
21400 | { |
21401 | clause = error_mark_node; |
21402 | error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%>, " |
21403 | "%<mutexinoutset%> or %<inoutset%>" ); |
21404 | } |
21405 | c_parens.skip_until_found_close (parser); |
21406 | } |
21407 | else |
21408 | clause = error_mark_node; |
21409 | } |
21410 | } |
21411 | if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID) |
21412 | { |
21413 | clause = error_mark_node; |
21414 | error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause" ); |
21415 | } |
21416 | c_parser_skip_to_pragma_eol (parser); |
21417 | |
21418 | c_finish_omp_depobj (loc, depobj, kind, clause); |
21419 | } |
21420 | |
21421 | |
21422 | /* OpenMP 2.5: |
21423 | # pragma omp flush flush-vars[opt] new-line |
21424 | |
21425 | flush-vars: |
21426 | ( variable-list ) |
21427 | |
21428 | OpenMP 5.0: |
21429 | # pragma omp flush memory-order-clause new-line */ |
21430 | |
21431 | static void |
21432 | c_parser_omp_flush (c_parser *parser) |
21433 | { |
21434 | location_t loc = c_parser_peek_token (parser)->location; |
21435 | c_parser_consume_pragma (parser); |
21436 | enum memmodel mo = MEMMODEL_LAST; |
21437 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
21438 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
21439 | c_parser_consume_token (parser); |
21440 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21441 | { |
21442 | const char *p |
21443 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21444 | |
21445 | if (!strcmp (s1: p, s2: "seq_cst" )) |
21446 | mo = MEMMODEL_SEQ_CST; |
21447 | else if (!strcmp (s1: p, s2: "acq_rel" )) |
21448 | mo = MEMMODEL_ACQ_REL; |
21449 | else if (!strcmp (s1: p, s2: "release" )) |
21450 | mo = MEMMODEL_RELEASE; |
21451 | else if (!strcmp (s1: p, s2: "acquire" )) |
21452 | mo = MEMMODEL_ACQUIRE; |
21453 | else |
21454 | error_at (c_parser_peek_token (parser)->location, |
21455 | "expected %<seq_cst%>, %<acq_rel%>, %<release%> or " |
21456 | "%<acquire%>" ); |
21457 | c_parser_consume_token (parser); |
21458 | } |
21459 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
21460 | { |
21461 | if (mo != MEMMODEL_LAST) |
21462 | error_at (c_parser_peek_token (parser)->location, |
21463 | "%<flush%> list specified together with memory order " |
21464 | "clause" ); |
21465 | c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ERROR, NULL); |
21466 | } |
21467 | else if (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
21468 | c_parser_error (parser, gmsgid: "expected %<(%> or end of line" ); |
21469 | c_parser_skip_to_pragma_eol (parser); |
21470 | |
21471 | c_finish_omp_flush (loc, mo); |
21472 | } |
21473 | |
21474 | /* Return true if next tokens contain a standard attribute that contains |
21475 | omp::directive (DIRECTIVE). */ |
21476 | |
21477 | static bool |
21478 | c_parser_omp_section_scan (c_parser *parser, const char *directive, |
21479 | bool tentative) |
21480 | { |
21481 | if (!c_parser_nth_token_starts_std_attributes (parser, n: 1)) |
21482 | return false; |
21483 | unsigned int n = 3; |
21484 | if (!c_parser_check_balanced_raw_token_sequence (parser, n: &n)) |
21485 | return false; |
21486 | c_token *token = c_parser_peek_nth_token_raw (parser, n); |
21487 | if (token->type != CPP_CLOSE_SQUARE) |
21488 | return false; |
21489 | token = c_parser_peek_nth_token_raw (parser, n: n + 1); |
21490 | if (token->type != CPP_CLOSE_SQUARE) |
21491 | return false; |
21492 | if (n < 9) |
21493 | return false; |
21494 | if (c_parser_peek_nth_token_raw (parser, n: 3)->type == CPP_NAME |
21495 | && c_parser_peek_nth_token_raw (parser, n: 4)->type == CPP_OPEN_PAREN |
21496 | && c_parser_peek_nth_token_raw (parser, n: 5)->type == CPP_NAME) |
21497 | { |
21498 | tree first = c_parser_peek_nth_token_raw (parser, n: 3)->value; |
21499 | tree second = c_parser_peek_nth_token_raw (parser, n: 5)->value; |
21500 | if (strcmp (IDENTIFIER_POINTER (first), s2: "directive" ) |
21501 | && strcmp (IDENTIFIER_POINTER (first), s2: "__directive__" )) |
21502 | return false; |
21503 | if (strcmp (IDENTIFIER_POINTER (second), s2: directive)) |
21504 | return false; |
21505 | } |
21506 | if (tentative) |
21507 | return true; |
21508 | location_t first_loc = c_parser_peek_token (parser)->location; |
21509 | location_t last_loc = c_parser_peek_nth_token_raw (parser, n: n + 1)->location; |
21510 | location_t middle_loc = UNKNOWN_LOCATION; |
21511 | tree std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
21512 | bool seen = false; |
21513 | int cnt = 0; |
21514 | for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr)) |
21515 | if (is_attribute_namespace_p (attr_ns: "omp" , attr) |
21516 | && is_attribute_p (attr_name: "directive" , ident: get_attribute_name (attr))) |
21517 | { |
21518 | for (tree a = TREE_VALUE (attr); a; a = TREE_CHAIN (a)) |
21519 | { |
21520 | tree d = TREE_VALUE (a); |
21521 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
21522 | c_token *first = C_TOKEN_VEC_TOKENS (d)->address (); |
21523 | cnt++; |
21524 | if (first->type == CPP_NAME |
21525 | && strcmp (IDENTIFIER_POINTER (first->value), |
21526 | s2: directive) == 0) |
21527 | { |
21528 | seen = true; |
21529 | if (middle_loc == UNKNOWN_LOCATION) |
21530 | middle_loc = first->location; |
21531 | } |
21532 | } |
21533 | } |
21534 | if (!seen) |
21535 | return false; |
21536 | if (cnt != 1 || TREE_CHAIN (std_attrs)) |
21537 | { |
21538 | error_at (make_location (caret: first_loc, start: last_loc, finish: middle_loc), |
21539 | "%<[[omp::directive(%s)]]%> must be the only specified " |
21540 | "attribute on a statement" , directive); |
21541 | return false; |
21542 | } |
21543 | c_parser_handle_statement_omp_attributes (parser, attrs&: std_attrs, NULL); |
21544 | return true; |
21545 | } |
21546 | |
21547 | /* Parse an OpenMP structured block sequence. KIND is the corresponding |
21548 | separating directive. */ |
21549 | |
21550 | static tree |
21551 | c_parser_omp_structured_block_sequence (c_parser *parser, |
21552 | enum pragma_kind kind) |
21553 | { |
21554 | tree stmt = push_stmt_list (); |
21555 | c_parser_statement (parser, NULL); |
21556 | do |
21557 | { |
21558 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
21559 | break; |
21560 | if (c_parser_next_token_is (parser, type: CPP_EOF)) |
21561 | break; |
21562 | |
21563 | if (kind != PRAGMA_NONE |
21564 | && c_parser_peek_token (parser)->pragma_kind == kind) |
21565 | break; |
21566 | |
21567 | if (kind != PRAGMA_NONE |
21568 | && c_parser_omp_section_scan (parser, |
21569 | directive: kind == PRAGMA_OMP_SCAN |
21570 | ? "scan" : "section" , tentative: false)) |
21571 | break; |
21572 | |
21573 | c_parser_statement (parser, NULL); |
21574 | } |
21575 | while (1); |
21576 | return pop_stmt_list (stmt); |
21577 | } |
21578 | |
21579 | /* OpenMP 5.0: |
21580 | |
21581 | scan-loop-body: |
21582 | { structured-block scan-directive structured-block } */ |
21583 | |
21584 | static void |
21585 | c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) |
21586 | { |
21587 | tree substmt; |
21588 | location_t loc; |
21589 | tree clauses = NULL_TREE; |
21590 | bool found_scan = false; |
21591 | |
21592 | loc = c_parser_peek_token (parser)->location; |
21593 | if (!open_brace_parsed |
21594 | && !c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
21595 | { |
21596 | /* Avoid skipping until the end of the block. */ |
21597 | parser->error = false; |
21598 | return; |
21599 | } |
21600 | |
21601 | if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SCAN) |
21602 | substmt = c_parser_omp_structured_block_sequence (parser, kind: PRAGMA_OMP_SCAN); |
21603 | else |
21604 | { |
21605 | warning_at (c_parser_peek_token (parser)->location, 0, |
21606 | "%<#pragma omp scan%> with zero preceding executable " |
21607 | "statements" ); |
21608 | substmt = build_empty_stmt (loc); |
21609 | } |
21610 | substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); |
21611 | SET_EXPR_LOCATION (substmt, loc); |
21612 | add_stmt (substmt); |
21613 | |
21614 | loc = c_parser_peek_token (parser)->location; |
21615 | if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SCAN) |
21616 | { |
21617 | enum omp_clause_code clause = OMP_CLAUSE_ERROR; |
21618 | found_scan = true; |
21619 | |
21620 | c_parser_consume_pragma (parser); |
21621 | |
21622 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
21623 | c_parser_consume_token (parser); |
21624 | |
21625 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21626 | { |
21627 | const char *p |
21628 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21629 | if (strcmp (s1: p, s2: "inclusive" ) == 0) |
21630 | clause = OMP_CLAUSE_INCLUSIVE; |
21631 | else if (strcmp (s1: p, s2: "exclusive" ) == 0) |
21632 | clause = OMP_CLAUSE_EXCLUSIVE; |
21633 | } |
21634 | if (clause != OMP_CLAUSE_ERROR) |
21635 | { |
21636 | c_parser_consume_token (parser); |
21637 | clauses = c_parser_omp_var_list_parens (parser, kind: clause, NULL_TREE); |
21638 | } |
21639 | else |
21640 | c_parser_error (parser, gmsgid: "expected %<inclusive%> or " |
21641 | "%<exclusive%> clause" ); |
21642 | c_parser_skip_to_pragma_eol (parser); |
21643 | } |
21644 | else |
21645 | error ("expected %<#pragma omp scan%>" ); |
21646 | |
21647 | clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); |
21648 | if (!c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
21649 | substmt = c_parser_omp_structured_block_sequence (parser, kind: PRAGMA_NONE); |
21650 | else |
21651 | { |
21652 | if (found_scan) |
21653 | warning_at (loc, 0, "%<#pragma omp scan%> with zero succeeding " |
21654 | "executable statements" ); |
21655 | substmt = build_empty_stmt (loc); |
21656 | } |
21657 | substmt = build2 (OMP_SCAN, void_type_node, substmt, clauses); |
21658 | SET_EXPR_LOCATION (substmt, loc); |
21659 | add_stmt (substmt); |
21660 | |
21661 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, |
21662 | msgid: "expected %<}%>" ); |
21663 | } |
21664 | |
21665 | |
21666 | /* This function parses a single level of a loop nest, invoking itself |
21667 | recursively if necessary. |
21668 | |
21669 | loop-nest :: for (...) loop-body |
21670 | loop-body :: loop-nest |
21671 | | { [intervening-code] loop-body [intervening-code] } |
21672 | | final-loop-body |
21673 | intervening-code :: structured-block-sequence |
21674 | final-loop-body :: structured-block |
21675 | |
21676 | For a collapsed loop nest, only a single OMP_FOR is built, pulling out |
21677 | all the iterator information from the inner loops into the |
21678 | parser->omp_for_parse_state structure. |
21679 | |
21680 | The iterator decl, init, cond, and incr are stored in vectors. |
21681 | |
21682 | Initialization code for iterator variables is collected into |
21683 | parser->omp_for_parse_state->pre_body and ends up inserted directly |
21684 | into the OMP_FOR structure. */ |
21685 | |
21686 | static tree |
21687 | c_parser_omp_loop_nest (c_parser *parser, bool *if_p) |
21688 | { |
21689 | tree decl, cond, incr, init; |
21690 | tree body = NULL_TREE; |
21691 | matching_parens parens; |
21692 | bool moreloops; |
21693 | unsigned char save_in_statement; |
21694 | tree loop_scope; |
21695 | location_t loc; |
21696 | struct omp_for_parse_data *omp_for_parse_state |
21697 | = parser->omp_for_parse_state; |
21698 | gcc_assert (omp_for_parse_state); |
21699 | int depth = omp_for_parse_state->depth; |
21700 | |
21701 | /* We have already matched the FOR token but not consumed it yet. */ |
21702 | loc = c_parser_peek_token (parser)->location; |
21703 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); |
21704 | c_parser_consume_token (parser); |
21705 | |
21706 | /* Forbid break/continue in the loop initializer, condition, and |
21707 | increment expressions. */ |
21708 | save_in_statement = in_statement; |
21709 | in_statement = IN_OMP_BLOCK; |
21710 | |
21711 | /* We are not in intervening code now. */ |
21712 | omp_for_parse_state->in_intervening_code = false; |
21713 | |
21714 | if (!parens.require_open (parser)) |
21715 | { |
21716 | omp_for_parse_state->fail = true; |
21717 | return NULL_TREE; |
21718 | } |
21719 | |
21720 | /* An implicit scope block surrounds each level of FOR loop, for |
21721 | declarations of iteration variables at this loop depth. */ |
21722 | loop_scope = c_begin_compound_stmt (true); |
21723 | |
21724 | /* Parse the initialization declaration or expression. */ |
21725 | if (c_parser_next_tokens_start_declaration (parser)) |
21726 | { |
21727 | /* This is a declaration, which must be added to the pre_body code. */ |
21728 | tree this_pre_body = push_stmt_list (); |
21729 | c_in_omp_for = true; |
21730 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, start_attr_ok: true); |
21731 | c_in_omp_for = false; |
21732 | this_pre_body = pop_stmt_list (this_pre_body); |
21733 | append_to_statement_list_force (this_pre_body, |
21734 | &(omp_for_parse_state->pre_body)); |
21735 | decl = check_for_loop_decls (omp_for_parse_state->for_loc, flag_isoc99); |
21736 | if (decl == NULL) |
21737 | goto error_init; |
21738 | if (DECL_INITIAL (decl) == error_mark_node) |
21739 | decl = error_mark_node; |
21740 | init = decl; |
21741 | } |
21742 | else if (c_parser_next_token_is (parser, type: CPP_NAME) |
21743 | && c_parser_peek_2nd_token (parser)->type == CPP_EQ) |
21744 | { |
21745 | struct c_expr decl_exp; |
21746 | struct c_expr init_exp; |
21747 | location_t init_loc; |
21748 | |
21749 | decl_exp = c_parser_postfix_expression (parser); |
21750 | decl = decl_exp.value; |
21751 | |
21752 | c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" ); |
21753 | |
21754 | init_loc = c_parser_peek_token (parser)->location; |
21755 | init_exp = c_parser_expr_no_commas (parser, NULL); |
21756 | init_exp = default_function_array_read_conversion (init_loc, |
21757 | init_exp); |
21758 | c_in_omp_for = true; |
21759 | init = build_modify_expr (init_loc, decl, decl_exp.original_type, |
21760 | NOP_EXPR, init_loc, init_exp.value, |
21761 | init_exp.original_type); |
21762 | c_in_omp_for = false; |
21763 | init = c_process_expr_stmt (init_loc, init); |
21764 | |
21765 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
21766 | } |
21767 | else |
21768 | { |
21769 | error_init: |
21770 | c_parser_error (parser, |
21771 | gmsgid: "expected iteration declaration or initialization" ); |
21772 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
21773 | msgid: "expected %<)%>" ); |
21774 | omp_for_parse_state->fail = true; |
21775 | goto parse_next; |
21776 | } |
21777 | |
21778 | /* Parse the loop condition. */ |
21779 | cond = NULL_TREE; |
21780 | if (c_parser_next_token_is_not (parser, type: CPP_SEMICOLON)) |
21781 | { |
21782 | location_t cond_loc = c_parser_peek_token (parser)->location; |
21783 | c_in_omp_for = true; |
21784 | struct c_expr cond_expr |
21785 | = c_parser_binary_expression (parser, NULL, NULL_TREE); |
21786 | c_in_omp_for = false; |
21787 | |
21788 | cond = cond_expr.value; |
21789 | cond = c_objc_common_truthvalue_conversion (cond_loc, cond); |
21790 | switch (cond_expr.original_code) |
21791 | { |
21792 | case GT_EXPR: |
21793 | case GE_EXPR: |
21794 | case LT_EXPR: |
21795 | case LE_EXPR: |
21796 | break; |
21797 | case NE_EXPR: |
21798 | if (omp_for_parse_state->code != OACC_LOOP) |
21799 | break; |
21800 | /* FALLTHRU. */ |
21801 | default: |
21802 | /* Can't be cond = error_mark_node, because we want to preserve |
21803 | the location until c_finish_omp_for. */ |
21804 | cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); |
21805 | break; |
21806 | } |
21807 | protected_set_expr_location (cond, cond_loc); |
21808 | } |
21809 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
21810 | |
21811 | /* Parse the increment expression. */ |
21812 | incr = NULL_TREE; |
21813 | if (c_parser_next_token_is_not (parser, type: CPP_CLOSE_PAREN)) |
21814 | { |
21815 | location_t incr_loc = c_parser_peek_token (parser)->location; |
21816 | |
21817 | incr = c_process_expr_stmt (incr_loc, |
21818 | c_parser_expression (parser).value); |
21819 | } |
21820 | parens.skip_until_found_close (parser); |
21821 | |
21822 | if (decl == NULL || decl == error_mark_node || init == error_mark_node) |
21823 | omp_for_parse_state->fail = true; |
21824 | else |
21825 | { |
21826 | TREE_VEC_ELT (omp_for_parse_state->declv, depth) = decl; |
21827 | TREE_VEC_ELT (omp_for_parse_state->initv, depth) = init; |
21828 | TREE_VEC_ELT (omp_for_parse_state->condv, depth) = cond; |
21829 | TREE_VEC_ELT (omp_for_parse_state->incrv, depth) = incr; |
21830 | } |
21831 | |
21832 | parse_next: |
21833 | moreloops = depth < omp_for_parse_state->count - 1; |
21834 | omp_for_parse_state->want_nested_loop = moreloops; |
21835 | if (moreloops && c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
21836 | { |
21837 | omp_for_parse_state->depth++; |
21838 | body = c_parser_omp_loop_nest (parser, if_p); |
21839 | omp_for_parse_state->depth--; |
21840 | } |
21841 | else if (moreloops && c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
21842 | { |
21843 | /* This is the open brace in the loop-body grammar production. Rather |
21844 | than trying to special-case braces, just parse it as a compound |
21845 | statement and handle the nested loop-body case there. Note that |
21846 | when we see a further open brace inside the compound statement |
21847 | loop-body, we don't know whether it is the start of intervening |
21848 | code that is a compound statement, or a level of braces |
21849 | surrounding a nested loop-body. Use the WANT_NESTED_LOOP state |
21850 | bit to ensure we have only one nested loop at each level. */ |
21851 | omp_for_parse_state->in_intervening_code = true; |
21852 | body = c_parser_compound_statement (parser, NULL); |
21853 | omp_for_parse_state->in_intervening_code = false; |
21854 | if (omp_for_parse_state->want_nested_loop) |
21855 | { |
21856 | /* We have already parsed the whole loop body and not found a |
21857 | nested loop. */ |
21858 | error_at (omp_for_parse_state->for_loc, |
21859 | "not enough nested loops" ); |
21860 | omp_for_parse_state->fail = true; |
21861 | } |
21862 | if_p = NULL; |
21863 | } |
21864 | else |
21865 | { |
21866 | /* This is the final-loop-body case in the grammar: we have |
21867 | something that is not a FOR and not an open brace. */ |
21868 | if (moreloops) |
21869 | { |
21870 | /* If we were expecting a nested loop, give an error and mark |
21871 | that parsing has failed, and try to recover by parsing the |
21872 | body as regular code without further collapsing. */ |
21873 | error_at (omp_for_parse_state->for_loc, |
21874 | "not enough nested loops" ); |
21875 | omp_for_parse_state->fail = true; |
21876 | } |
21877 | in_statement = IN_OMP_FOR; |
21878 | parser->omp_for_parse_state = NULL; |
21879 | body = push_stmt_list (); |
21880 | if (omp_for_parse_state->inscan) |
21881 | c_parser_omp_scan_loop_body (parser, open_brace_parsed: false); |
21882 | else |
21883 | add_stmt (c_parser_c99_block_statement (parser, if_p)); |
21884 | body = pop_stmt_list (body); |
21885 | parser->omp_for_parse_state = omp_for_parse_state; |
21886 | } |
21887 | in_statement = save_in_statement; |
21888 | omp_for_parse_state->want_nested_loop = false; |
21889 | omp_for_parse_state->in_intervening_code = true; |
21890 | |
21891 | /* Pop and return the implicit scope surrounding this level of loop. |
21892 | If the iteration variable at this depth was bound in the for loop, |
21893 | pull out and save the binding. Later in c_parser_omp_for_loop, |
21894 | these bindings will be moved to the scope surrounding the entire |
21895 | OMP_FOR. That keeps the gimplifier happy later on, and meanwhile |
21896 | we have already resolved all references to the iteration variable |
21897 | in its true scope. */ |
21898 | add_stmt (body); |
21899 | body = c_end_compound_stmt (loc, loop_scope, true); |
21900 | if (decl && TREE_CODE (body) == BIND_EXPR) |
21901 | { |
21902 | tree t = BIND_EXPR_VARS (body); |
21903 | tree prev = NULL_TREE, next = NULL_TREE; |
21904 | while (t) |
21905 | { |
21906 | next = DECL_CHAIN (t); |
21907 | if (t == decl) |
21908 | { |
21909 | if (prev) |
21910 | DECL_CHAIN (prev) = next; |
21911 | else |
21912 | { |
21913 | BIND_EXPR_VARS (body) = next; |
21914 | BLOCK_VARS (BIND_EXPR_BLOCK (body)) = next; |
21915 | } |
21916 | DECL_CHAIN (t) = omp_for_parse_state->bindings; |
21917 | omp_for_parse_state->bindings = t; |
21918 | break; |
21919 | } |
21920 | else |
21921 | { |
21922 | prev = t; |
21923 | t = next; |
21924 | } |
21925 | } |
21926 | if (BIND_EXPR_VARS (body) == NULL_TREE) |
21927 | body = BIND_EXPR_BODY (body); |
21928 | } |
21929 | |
21930 | return body; |
21931 | } |
21932 | |
21933 | /* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. |
21934 | The real trick here is to determine the loop control variable early |
21935 | so that we can push a new decl if necessary to make it private. |
21936 | LOC is the location of the "acc" or "omp" in "#pragma acc" or "#pragma omp", |
21937 | respectively. */ |
21938 | |
21939 | static tree |
21940 | c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, |
21941 | tree clauses, tree *cclauses, bool *if_p) |
21942 | { |
21943 | tree body, stmt, cl; |
21944 | tree ret = NULL_TREE; |
21945 | tree ordered_cl = NULL_TREE; |
21946 | int i, collapse = 1, ordered = 0, count; |
21947 | bool tiling = false; |
21948 | bool inscan = false; |
21949 | struct omp_for_parse_data data; |
21950 | struct omp_for_parse_data *save_data = parser->omp_for_parse_state; |
21951 | |
21952 | for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) |
21953 | if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) |
21954 | collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); |
21955 | else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_TILE) |
21956 | { |
21957 | tiling = true; |
21958 | collapse = list_length (OMP_CLAUSE_TILE_LIST (cl)); |
21959 | } |
21960 | else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED |
21961 | && OMP_CLAUSE_ORDERED_EXPR (cl)) |
21962 | { |
21963 | ordered_cl = cl; |
21964 | ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl)); |
21965 | } |
21966 | else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_REDUCTION |
21967 | && OMP_CLAUSE_REDUCTION_INSCAN (cl) |
21968 | && (code == OMP_SIMD || code == OMP_FOR)) |
21969 | inscan = true; |
21970 | |
21971 | if (ordered && ordered < collapse) |
21972 | { |
21973 | error_at (OMP_CLAUSE_LOCATION (ordered_cl), |
21974 | "%<ordered%> clause parameter is less than %<collapse%>" ); |
21975 | OMP_CLAUSE_ORDERED_EXPR (ordered_cl) |
21976 | = build_int_cst (NULL_TREE, collapse); |
21977 | ordered = collapse; |
21978 | } |
21979 | |
21980 | gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); |
21981 | count = ordered ? ordered : collapse; |
21982 | |
21983 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
21984 | { |
21985 | c_parser_error (parser, gmsgid: "for statement expected" ); |
21986 | return NULL; |
21987 | } |
21988 | |
21989 | /* Initialize parse state for recursive descent. */ |
21990 | data.declv = make_tree_vec (count); |
21991 | data.initv = make_tree_vec (count); |
21992 | data.condv = make_tree_vec (count); |
21993 | data.incrv = make_tree_vec (count); |
21994 | data.pre_body = NULL_TREE;; |
21995 | data.bindings = NULL_TREE; |
21996 | data.for_loc = c_parser_peek_token (parser)->location; |
21997 | data.count = count; |
21998 | data.depth = 0; |
21999 | data.want_nested_loop = true; |
22000 | data.ordered = ordered > 0; |
22001 | data.in_intervening_code = false; |
22002 | data.perfect_nesting_fail = false; |
22003 | data.fail = false; |
22004 | data.inscan = inscan; |
22005 | data.saw_intervening_code = false; |
22006 | data.code = code; |
22007 | parser->omp_for_parse_state = &data; |
22008 | |
22009 | body = c_parser_omp_loop_nest (parser, if_p); |
22010 | |
22011 | /* Add saved bindings for iteration variables that were declared in |
22012 | the nested for loop to the scope surrounding the entire loop. */ |
22013 | for (tree t = data.bindings; t; ) |
22014 | { |
22015 | tree n = TREE_CHAIN (t); |
22016 | TREE_CHAIN (t) = NULL_TREE; |
22017 | pushdecl (t); |
22018 | t = n; |
22019 | } |
22020 | |
22021 | /* Only bother calling c_finish_omp_for if we haven't already generated |
22022 | an error from the initialization parsing. */ |
22023 | if (!data.fail) |
22024 | { |
22025 | c_in_omp_for = true; |
22026 | stmt = c_finish_omp_for (loc, code, data.declv, NULL, data.initv, |
22027 | data.condv, data.incrv, |
22028 | body, data.pre_body, true); |
22029 | c_in_omp_for = false; |
22030 | |
22031 | /* Check for iterators appearing in lb, b or incr expressions. */ |
22032 | if (stmt && !c_omp_check_loop_iv (stmt, data.declv, NULL)) |
22033 | stmt = NULL_TREE; |
22034 | |
22035 | /* Check for errors involving lb/ub/incr expressions referencing |
22036 | variables declared in intervening code. */ |
22037 | if (data.saw_intervening_code |
22038 | && !c_omp_check_loop_binding_exprs (stmt, NULL)) |
22039 | stmt = NULL_TREE; |
22040 | |
22041 | if (stmt) |
22042 | { |
22043 | add_stmt (stmt); |
22044 | |
22045 | for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++) |
22046 | { |
22047 | tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i); |
22048 | gcc_assert (TREE_CODE (init) == MODIFY_EXPR); |
22049 | tree decl = TREE_OPERAND (init, 0); |
22050 | tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i); |
22051 | gcc_assert (COMPARISON_CLASS_P (cond)); |
22052 | gcc_assert (TREE_OPERAND (cond, 0) == decl); |
22053 | |
22054 | tree op0 = TREE_OPERAND (init, 1); |
22055 | if (!OMP_FOR_NON_RECTANGULAR (stmt) |
22056 | || TREE_CODE (op0) != TREE_VEC) |
22057 | TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL); |
22058 | else |
22059 | { |
22060 | TREE_VEC_ELT (op0, 1) |
22061 | = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL); |
22062 | TREE_VEC_ELT (op0, 2) |
22063 | = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL); |
22064 | } |
22065 | |
22066 | tree op1 = TREE_OPERAND (cond, 1); |
22067 | if (!OMP_FOR_NON_RECTANGULAR (stmt) |
22068 | || TREE_CODE (op1) != TREE_VEC) |
22069 | TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL); |
22070 | else |
22071 | { |
22072 | TREE_VEC_ELT (op1, 1) |
22073 | = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL); |
22074 | TREE_VEC_ELT (op1, 2) |
22075 | = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL); |
22076 | } |
22077 | } |
22078 | |
22079 | if (cclauses != NULL |
22080 | && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL) |
22081 | { |
22082 | tree *c; |
22083 | for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) |
22084 | if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE |
22085 | && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) |
22086 | c = &OMP_CLAUSE_CHAIN (*c); |
22087 | else |
22088 | { |
22089 | for (i = 0; i < count; i++) |
22090 | if (TREE_VEC_ELT (data.declv, i) == OMP_CLAUSE_DECL (*c)) |
22091 | break; |
22092 | if (i == count) |
22093 | c = &OMP_CLAUSE_CHAIN (*c); |
22094 | else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) |
22095 | { |
22096 | error_at (loc, |
22097 | "iteration variable %qD should not be firstprivate" , |
22098 | OMP_CLAUSE_DECL (*c)); |
22099 | *c = OMP_CLAUSE_CHAIN (*c); |
22100 | } |
22101 | else |
22102 | { |
22103 | /* Move lastprivate (decl) clause to |
22104 | OMP_FOR_CLAUSES. */ |
22105 | tree l = *c; |
22106 | *c = OMP_CLAUSE_CHAIN (*c); |
22107 | if (code == OMP_SIMD) |
22108 | { |
22109 | OMP_CLAUSE_CHAIN (l) |
22110 | = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; |
22111 | cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l; |
22112 | } |
22113 | else |
22114 | { |
22115 | OMP_CLAUSE_CHAIN (l) = clauses; |
22116 | clauses = l; |
22117 | } |
22118 | } |
22119 | } |
22120 | } |
22121 | OMP_FOR_CLAUSES (stmt) = clauses; |
22122 | } |
22123 | ret = stmt; |
22124 | } |
22125 | |
22126 | parser->omp_for_parse_state = save_data; |
22127 | return ret; |
22128 | } |
22129 | |
22130 | /* Helper function for OpenMP parsing, split clauses and call |
22131 | finish_omp_clauses on each of the set of clauses afterwards. */ |
22132 | |
22133 | static void |
22134 | omp_split_clauses (location_t loc, enum tree_code code, |
22135 | omp_clause_mask mask, tree clauses, tree *cclauses) |
22136 | { |
22137 | int i; |
22138 | c_omp_split_clauses (loc, code, mask, clauses, cclauses); |
22139 | for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) |
22140 | if (cclauses[i]) |
22141 | cclauses[i] = c_finish_omp_clauses (cclauses[i], |
22142 | i == C_OMP_CLAUSE_SPLIT_TARGET |
22143 | ? C_ORT_OMP_TARGET : C_ORT_OMP); |
22144 | } |
22145 | |
22146 | /* OpenMP 5.0: |
22147 | #pragma omp loop loop-clause[optseq] new-line |
22148 | for-loop |
22149 | |
22150 | LOC is the location of the #pragma token. |
22151 | */ |
22152 | |
22153 | #define OMP_LOOP_CLAUSE_MASK \ |
22154 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22155 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22156 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22157 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
22158 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_BIND) \ |
22159 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
22160 | |
22161 | static tree |
22162 | c_parser_omp_loop (location_t loc, c_parser *parser, |
22163 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22164 | bool *if_p) |
22165 | { |
22166 | tree block, clauses, ret; |
22167 | |
22168 | strcat (dest: p_name, src: " loop" ); |
22169 | mask |= OMP_LOOP_CLAUSE_MASK; |
22170 | |
22171 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22172 | if (cclauses) |
22173 | { |
22174 | omp_split_clauses (loc, code: OMP_LOOP, mask, clauses, cclauses); |
22175 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_LOOP]; |
22176 | } |
22177 | |
22178 | block = c_begin_compound_stmt (true); |
22179 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_LOOP, clauses, cclauses, if_p); |
22180 | block = c_end_compound_stmt (loc, block, true); |
22181 | add_stmt (block); |
22182 | |
22183 | return ret; |
22184 | } |
22185 | |
22186 | /* OpenMP 4.0: |
22187 | #pragma omp simd simd-clause[optseq] new-line |
22188 | for-loop |
22189 | |
22190 | LOC is the location of the #pragma token. |
22191 | */ |
22192 | |
22193 | #define OMP_SIMD_CLAUSE_MASK \ |
22194 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ |
22195 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ |
22196 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ |
22197 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ |
22198 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22199 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22200 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22201 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
22202 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
22203 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL) \ |
22204 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
22205 | |
22206 | static tree |
22207 | c_parser_omp_simd (location_t loc, c_parser *parser, |
22208 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22209 | bool *if_p) |
22210 | { |
22211 | tree block, clauses, ret; |
22212 | |
22213 | strcat (dest: p_name, src: " simd" ); |
22214 | mask |= OMP_SIMD_CLAUSE_MASK; |
22215 | |
22216 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22217 | if (cclauses) |
22218 | { |
22219 | omp_split_clauses (loc, code: OMP_SIMD, mask, clauses, cclauses); |
22220 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; |
22221 | } |
22222 | |
22223 | block = c_begin_compound_stmt (true); |
22224 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_SIMD, clauses, cclauses, if_p); |
22225 | block = c_end_compound_stmt (loc, block, true); |
22226 | add_stmt (block); |
22227 | |
22228 | return ret; |
22229 | } |
22230 | |
22231 | /* OpenMP 2.5: |
22232 | #pragma omp for for-clause[optseq] new-line |
22233 | for-loop |
22234 | |
22235 | OpenMP 4.0: |
22236 | #pragma omp for simd for-simd-clause[optseq] new-line |
22237 | for-loop |
22238 | |
22239 | LOC is the location of the #pragma token. |
22240 | */ |
22241 | |
22242 | #define OMP_FOR_CLAUSE_MASK \ |
22243 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22244 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22245 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22246 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ |
22247 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22248 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ |
22249 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ |
22250 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
22251 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ |
22252 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22253 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
22254 | |
22255 | static tree |
22256 | c_parser_omp_for (location_t loc, c_parser *parser, |
22257 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22258 | bool *if_p) |
22259 | { |
22260 | tree block, clauses, ret; |
22261 | |
22262 | strcat (dest: p_name, src: " for" ); |
22263 | mask |= OMP_FOR_CLAUSE_MASK; |
22264 | /* parallel for{, simd} disallows nowait clause, but for |
22265 | target {teams distribute ,}parallel for{, simd} it should be accepted. */ |
22266 | if (cclauses && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) == 0) |
22267 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); |
22268 | /* Composite distribute parallel for{, simd} disallows ordered clause. */ |
22269 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) |
22270 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); |
22271 | |
22272 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22273 | { |
22274 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22275 | |
22276 | if (strcmp (s1: p, s2: "simd" ) == 0) |
22277 | { |
22278 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22279 | if (cclauses == NULL) |
22280 | cclauses = cclauses_buf; |
22281 | |
22282 | c_parser_consume_token (parser); |
22283 | if (!flag_openmp) /* flag_openmp_simd */ |
22284 | return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
22285 | if_p); |
22286 | block = c_begin_compound_stmt (true); |
22287 | ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); |
22288 | block = c_end_compound_stmt (loc, block, true); |
22289 | if (ret == NULL_TREE) |
22290 | return ret; |
22291 | ret = make_node (OMP_FOR); |
22292 | TREE_TYPE (ret) = void_type_node; |
22293 | OMP_FOR_BODY (ret) = block; |
22294 | OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; |
22295 | SET_EXPR_LOCATION (ret, loc); |
22296 | add_stmt (ret); |
22297 | return ret; |
22298 | } |
22299 | } |
22300 | if (!flag_openmp) /* flag_openmp_simd */ |
22301 | { |
22302 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22303 | return NULL_TREE; |
22304 | } |
22305 | |
22306 | /* Composite distribute parallel for disallows linear clause. */ |
22307 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) |
22308 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR); |
22309 | |
22310 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22311 | if (cclauses) |
22312 | { |
22313 | omp_split_clauses (loc, code: OMP_FOR, mask, clauses, cclauses); |
22314 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; |
22315 | } |
22316 | |
22317 | block = c_begin_compound_stmt (true); |
22318 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_FOR, clauses, cclauses, if_p); |
22319 | block = c_end_compound_stmt (loc, block, true); |
22320 | add_stmt (block); |
22321 | |
22322 | return ret; |
22323 | } |
22324 | |
22325 | static tree c_parser_omp_taskloop (location_t, c_parser *, char *, |
22326 | omp_clause_mask, tree *, bool *); |
22327 | |
22328 | /* OpenMP 2.5: |
22329 | # pragma omp master new-line |
22330 | structured-block |
22331 | |
22332 | LOC is the location of the #pragma token. |
22333 | */ |
22334 | |
22335 | static tree |
22336 | c_parser_omp_master (location_t loc, c_parser *parser, |
22337 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22338 | bool *if_p) |
22339 | { |
22340 | tree block, clauses, ret; |
22341 | |
22342 | strcat (dest: p_name, src: " master" ); |
22343 | |
22344 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22345 | { |
22346 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22347 | |
22348 | if (strcmp (s1: p, s2: "taskloop" ) == 0) |
22349 | { |
22350 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22351 | if (cclauses == NULL) |
22352 | cclauses = cclauses_buf; |
22353 | |
22354 | c_parser_consume_token (parser); |
22355 | if (!flag_openmp) /* flag_openmp_simd */ |
22356 | return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22357 | if_p); |
22358 | block = c_begin_compound_stmt (true); |
22359 | ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22360 | if_p); |
22361 | block = c_end_compound_stmt (loc, block, true); |
22362 | if (ret == NULL_TREE) |
22363 | return ret; |
22364 | ret = c_finish_omp_master (loc, block); |
22365 | OMP_MASTER_COMBINED (ret) = 1; |
22366 | return ret; |
22367 | } |
22368 | } |
22369 | if (!flag_openmp) /* flag_openmp_simd */ |
22370 | { |
22371 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22372 | return NULL_TREE; |
22373 | } |
22374 | |
22375 | if (cclauses) |
22376 | { |
22377 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: false); |
22378 | omp_split_clauses (loc, code: OMP_MASTER, mask, clauses, cclauses); |
22379 | } |
22380 | else |
22381 | c_parser_skip_to_pragma_eol (parser); |
22382 | |
22383 | return c_finish_omp_master (loc, c_parser_omp_structured_block (parser, |
22384 | if_p)); |
22385 | } |
22386 | |
22387 | /* OpenMP 5.1: |
22388 | # pragma omp masked masked-clauses new-line |
22389 | structured-block |
22390 | |
22391 | LOC is the location of the #pragma token. |
22392 | */ |
22393 | |
22394 | #define OMP_MASKED_CLAUSE_MASK \ |
22395 | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) |
22396 | |
22397 | static tree |
22398 | c_parser_omp_masked (location_t loc, c_parser *parser, |
22399 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22400 | bool *if_p) |
22401 | { |
22402 | tree block, clauses, ret; |
22403 | |
22404 | strcat (dest: p_name, src: " masked" ); |
22405 | mask |= OMP_MASKED_CLAUSE_MASK; |
22406 | |
22407 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22408 | { |
22409 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22410 | |
22411 | if (strcmp (s1: p, s2: "taskloop" ) == 0) |
22412 | { |
22413 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22414 | if (cclauses == NULL) |
22415 | cclauses = cclauses_buf; |
22416 | |
22417 | c_parser_consume_token (parser); |
22418 | if (!flag_openmp) /* flag_openmp_simd */ |
22419 | return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22420 | if_p); |
22421 | block = c_begin_compound_stmt (true); |
22422 | ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22423 | if_p); |
22424 | block = c_end_compound_stmt (loc, block, true); |
22425 | if (ret == NULL_TREE) |
22426 | return ret; |
22427 | ret = c_finish_omp_masked (loc, block, |
22428 | cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); |
22429 | OMP_MASKED_COMBINED (ret) = 1; |
22430 | return ret; |
22431 | } |
22432 | } |
22433 | if (!flag_openmp) /* flag_openmp_simd */ |
22434 | { |
22435 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22436 | return NULL_TREE; |
22437 | } |
22438 | |
22439 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22440 | if (cclauses) |
22441 | { |
22442 | omp_split_clauses (loc, code: OMP_MASKED, mask, clauses, cclauses); |
22443 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; |
22444 | } |
22445 | |
22446 | return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, |
22447 | if_p), |
22448 | clauses); |
22449 | } |
22450 | |
22451 | /* OpenMP 2.5: |
22452 | # pragma omp ordered new-line |
22453 | structured-block |
22454 | |
22455 | OpenMP 4.5: |
22456 | # pragma omp ordered ordered-clauses new-line |
22457 | structured-block |
22458 | |
22459 | # pragma omp ordered depend-clauses new-line |
22460 | |
22461 | OpenMP 5.2 |
22462 | # pragma omp ordered doacross-clauses new-line */ |
22463 | |
22464 | #define OMP_ORDERED_CLAUSE_MASK \ |
22465 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ |
22466 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) |
22467 | |
22468 | #define OMP_ORDERED_DEPEND_CLAUSE_MASK \ |
22469 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
22470 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS)) |
22471 | |
22472 | static bool |
22473 | c_parser_omp_ordered (c_parser *parser, enum pragma_context context, |
22474 | bool *if_p) |
22475 | { |
22476 | location_t loc = c_parser_peek_token (parser)->location; |
22477 | c_parser_consume_pragma (parser); |
22478 | |
22479 | if (context != pragma_stmt && context != pragma_compound) |
22480 | { |
22481 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
22482 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22483 | return false; |
22484 | } |
22485 | |
22486 | int n = 1; |
22487 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
22488 | n = 2; |
22489 | |
22490 | if (c_parser_peek_nth_token (parser, n)->type == CPP_NAME) |
22491 | { |
22492 | const char *p |
22493 | = IDENTIFIER_POINTER (c_parser_peek_nth_token (parser, n)->value); |
22494 | |
22495 | if (!strcmp (s1: "depend" , s2: p) || !strcmp (s1: "doacross" , s2: p)) |
22496 | { |
22497 | if (!flag_openmp) /* flag_openmp_simd */ |
22498 | { |
22499 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22500 | return false; |
22501 | } |
22502 | if (context == pragma_stmt) |
22503 | { |
22504 | error_at (loc, |
22505 | "%<#pragma omp ordered%> with %qs clause may " |
22506 | "only be used in compound statements" , p); |
22507 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22508 | return true; |
22509 | } |
22510 | |
22511 | tree clauses |
22512 | = c_parser_omp_all_clauses (parser, |
22513 | OMP_ORDERED_DEPEND_CLAUSE_MASK, |
22514 | where: "#pragma omp ordered" ); |
22515 | c_finish_omp_ordered (loc, clauses, NULL_TREE); |
22516 | return false; |
22517 | } |
22518 | } |
22519 | |
22520 | tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK, |
22521 | where: "#pragma omp ordered" ); |
22522 | |
22523 | if (!flag_openmp /* flag_openmp_simd */ |
22524 | && omp_find_clause (clauses, kind: OMP_CLAUSE_SIMD) == NULL_TREE) |
22525 | return false; |
22526 | |
22527 | c_finish_omp_ordered (loc, clauses, |
22528 | c_parser_omp_structured_block (parser, if_p)); |
22529 | return true; |
22530 | } |
22531 | |
22532 | /* OpenMP 2.5: |
22533 | |
22534 | section-scope: |
22535 | { section-sequence } |
22536 | |
22537 | section-sequence: |
22538 | section-directive[opt] structured-block |
22539 | section-sequence section-directive structured-block |
22540 | |
22541 | OpenMP 5.1 allows structured-block-sequence instead of structured-block. |
22542 | |
22543 | SECTIONS_LOC is the location of the #pragma omp sections. */ |
22544 | |
22545 | static tree |
22546 | c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) |
22547 | { |
22548 | tree stmt, substmt; |
22549 | bool error_suppress = false; |
22550 | location_t loc; |
22551 | |
22552 | loc = c_parser_peek_token (parser)->location; |
22553 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
22554 | { |
22555 | /* Avoid skipping until the end of the block. */ |
22556 | parser->error = false; |
22557 | return NULL_TREE; |
22558 | } |
22559 | |
22560 | stmt = push_stmt_list (); |
22561 | |
22562 | if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION |
22563 | && !c_parser_omp_section_scan (parser, directive: "section" , tentative: true)) |
22564 | { |
22565 | substmt = c_parser_omp_structured_block_sequence (parser, |
22566 | kind: PRAGMA_OMP_SECTION); |
22567 | substmt = build1 (OMP_SECTION, void_type_node, substmt); |
22568 | SET_EXPR_LOCATION (substmt, loc); |
22569 | add_stmt (substmt); |
22570 | } |
22571 | |
22572 | while (1) |
22573 | { |
22574 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
22575 | break; |
22576 | if (c_parser_next_token_is (parser, type: CPP_EOF)) |
22577 | break; |
22578 | |
22579 | loc = c_parser_peek_token (parser)->location; |
22580 | c_parser_omp_section_scan (parser, directive: "section" , tentative: false); |
22581 | if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) |
22582 | { |
22583 | c_parser_consume_pragma (parser); |
22584 | c_parser_skip_to_pragma_eol (parser); |
22585 | error_suppress = false; |
22586 | } |
22587 | else if (!error_suppress) |
22588 | { |
22589 | error_at (loc, "expected %<#pragma omp section%> or %<}%>" ); |
22590 | error_suppress = true; |
22591 | } |
22592 | |
22593 | substmt = c_parser_omp_structured_block_sequence (parser, |
22594 | kind: PRAGMA_OMP_SECTION); |
22595 | substmt = build1 (OMP_SECTION, void_type_node, substmt); |
22596 | SET_EXPR_LOCATION (substmt, loc); |
22597 | add_stmt (substmt); |
22598 | } |
22599 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, |
22600 | msgid: "expected %<#pragma omp section%> or %<}%>" ); |
22601 | |
22602 | substmt = pop_stmt_list (stmt); |
22603 | |
22604 | stmt = make_node (OMP_SECTIONS); |
22605 | SET_EXPR_LOCATION (stmt, sections_loc); |
22606 | TREE_TYPE (stmt) = void_type_node; |
22607 | OMP_SECTIONS_BODY (stmt) = substmt; |
22608 | |
22609 | return add_stmt (stmt); |
22610 | } |
22611 | |
22612 | /* OpenMP 2.5: |
22613 | # pragma omp sections sections-clause[optseq] newline |
22614 | sections-scope |
22615 | |
22616 | LOC is the location of the #pragma token. |
22617 | */ |
22618 | |
22619 | #define OMP_SECTIONS_CLAUSE_MASK \ |
22620 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22621 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22622 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22623 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22624 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22625 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
22626 | |
22627 | static tree |
22628 | c_parser_omp_sections (location_t loc, c_parser *parser, |
22629 | char *p_name, omp_clause_mask mask, tree *cclauses) |
22630 | { |
22631 | tree block, clauses, ret; |
22632 | |
22633 | strcat (dest: p_name, src: " sections" ); |
22634 | mask |= OMP_SECTIONS_CLAUSE_MASK; |
22635 | if (cclauses) |
22636 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); |
22637 | |
22638 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22639 | if (cclauses) |
22640 | { |
22641 | omp_split_clauses (loc, code: OMP_SECTIONS, mask, clauses, cclauses); |
22642 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; |
22643 | } |
22644 | |
22645 | block = c_begin_compound_stmt (true); |
22646 | ret = c_parser_omp_sections_scope (sections_loc: loc, parser); |
22647 | if (ret) |
22648 | OMP_SECTIONS_CLAUSES (ret) = clauses; |
22649 | block = c_end_compound_stmt (loc, block, true); |
22650 | add_stmt (block); |
22651 | |
22652 | return ret; |
22653 | } |
22654 | |
22655 | /* OpenMP 2.5: |
22656 | # pragma omp parallel parallel-clause[optseq] new-line |
22657 | structured-block |
22658 | # pragma omp parallel for parallel-for-clause[optseq] new-line |
22659 | structured-block |
22660 | # pragma omp parallel sections parallel-sections-clause[optseq] new-line |
22661 | structured-block |
22662 | |
22663 | OpenMP 4.0: |
22664 | # pragma omp parallel for simd parallel-for-simd-clause[optseq] new-line |
22665 | structured-block |
22666 | |
22667 | LOC is the location of the #pragma token. |
22668 | */ |
22669 | |
22670 | #define OMP_PARALLEL_CLAUSE_MASK \ |
22671 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
22672 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22673 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22674 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
22675 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
22676 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ |
22677 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22678 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ |
22679 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22680 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) |
22681 | |
22682 | static tree |
22683 | c_parser_omp_parallel (location_t loc, c_parser *parser, |
22684 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22685 | bool *if_p) |
22686 | { |
22687 | tree stmt, clauses, block; |
22688 | |
22689 | strcat (dest: p_name, src: " parallel" ); |
22690 | mask |= OMP_PARALLEL_CLAUSE_MASK; |
22691 | /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */ |
22692 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0 |
22693 | && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) |
22694 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN); |
22695 | |
22696 | if (c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
22697 | { |
22698 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22699 | if (cclauses == NULL) |
22700 | cclauses = cclauses_buf; |
22701 | |
22702 | c_parser_consume_token (parser); |
22703 | if (!flag_openmp) /* flag_openmp_simd */ |
22704 | return c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); |
22705 | block = c_begin_omp_parallel (); |
22706 | tree ret = c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); |
22707 | stmt |
22708 | = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
22709 | block); |
22710 | if (ret == NULL_TREE) |
22711 | return ret; |
22712 | OMP_PARALLEL_COMBINED (stmt) = 1; |
22713 | return stmt; |
22714 | } |
22715 | /* When combined with distribute, parallel has to be followed by for. |
22716 | #pragma omp target parallel is allowed though. */ |
22717 | else if (cclauses |
22718 | && (mask & (OMP_CLAUSE_MASK_1 |
22719 | << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) |
22720 | { |
22721 | error_at (loc, "expected %<for%> after %qs" , p_name); |
22722 | c_parser_skip_to_pragma_eol (parser); |
22723 | return NULL_TREE; |
22724 | } |
22725 | else if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22726 | { |
22727 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22728 | if (cclauses == NULL && strcmp (s1: p, s2: "masked" ) == 0) |
22729 | { |
22730 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22731 | cclauses = cclauses_buf; |
22732 | |
22733 | c_parser_consume_token (parser); |
22734 | if (!flag_openmp) /* flag_openmp_simd */ |
22735 | return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, |
22736 | if_p); |
22737 | block = c_begin_omp_parallel (); |
22738 | tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, |
22739 | if_p); |
22740 | stmt = c_finish_omp_parallel (loc, |
22741 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
22742 | block); |
22743 | if (ret == NULL) |
22744 | return ret; |
22745 | /* masked does have just filter clause, but during gimplification |
22746 | isn't represented by a gimplification omp context, so for |
22747 | #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, |
22748 | so that |
22749 | #pragma omp parallel masked |
22750 | #pragma omp taskloop simd lastprivate (x) |
22751 | isn't confused with |
22752 | #pragma omp parallel masked taskloop simd lastprivate (x) */ |
22753 | if (OMP_MASKED_COMBINED (ret)) |
22754 | OMP_PARALLEL_COMBINED (stmt) = 1; |
22755 | return stmt; |
22756 | } |
22757 | else if (cclauses == NULL && strcmp (s1: p, s2: "master" ) == 0) |
22758 | { |
22759 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22760 | cclauses = cclauses_buf; |
22761 | |
22762 | c_parser_consume_token (parser); |
22763 | if (!flag_openmp) /* flag_openmp_simd */ |
22764 | return c_parser_omp_master (loc, parser, p_name, mask, cclauses, |
22765 | if_p); |
22766 | block = c_begin_omp_parallel (); |
22767 | tree ret = c_parser_omp_master (loc, parser, p_name, mask, cclauses, |
22768 | if_p); |
22769 | stmt = c_finish_omp_parallel (loc, |
22770 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
22771 | block); |
22772 | if (ret == NULL) |
22773 | return ret; |
22774 | /* master doesn't have any clauses and during gimplification |
22775 | isn't represented by a gimplification omp context, so for |
22776 | #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, |
22777 | so that |
22778 | #pragma omp parallel master |
22779 | #pragma omp taskloop simd lastprivate (x) |
22780 | isn't confused with |
22781 | #pragma omp parallel master taskloop simd lastprivate (x) */ |
22782 | if (OMP_MASTER_COMBINED (ret)) |
22783 | OMP_PARALLEL_COMBINED (stmt) = 1; |
22784 | return stmt; |
22785 | } |
22786 | else if (strcmp (s1: p, s2: "loop" ) == 0) |
22787 | { |
22788 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22789 | if (cclauses == NULL) |
22790 | cclauses = cclauses_buf; |
22791 | |
22792 | c_parser_consume_token (parser); |
22793 | if (!flag_openmp) /* flag_openmp_simd */ |
22794 | return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, |
22795 | if_p); |
22796 | block = c_begin_omp_parallel (); |
22797 | tree ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, |
22798 | if_p); |
22799 | stmt |
22800 | = c_finish_omp_parallel (loc, |
22801 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
22802 | block); |
22803 | if (ret == NULL_TREE) |
22804 | return ret; |
22805 | OMP_PARALLEL_COMBINED (stmt) = 1; |
22806 | return stmt; |
22807 | } |
22808 | else if (!flag_openmp) /* flag_openmp_simd */ |
22809 | { |
22810 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22811 | return NULL_TREE; |
22812 | } |
22813 | else if (cclauses == NULL && strcmp (s1: p, s2: "sections" ) == 0) |
22814 | { |
22815 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22816 | cclauses = cclauses_buf; |
22817 | |
22818 | c_parser_consume_token (parser); |
22819 | block = c_begin_omp_parallel (); |
22820 | c_parser_omp_sections (loc, parser, p_name, mask, cclauses); |
22821 | stmt = c_finish_omp_parallel (loc, |
22822 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
22823 | block); |
22824 | OMP_PARALLEL_COMBINED (stmt) = 1; |
22825 | return stmt; |
22826 | } |
22827 | } |
22828 | else if (!flag_openmp) /* flag_openmp_simd */ |
22829 | { |
22830 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22831 | return NULL_TREE; |
22832 | } |
22833 | |
22834 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22835 | if (cclauses) |
22836 | { |
22837 | omp_split_clauses (loc, code: OMP_PARALLEL, mask, clauses, cclauses); |
22838 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; |
22839 | } |
22840 | |
22841 | block = c_begin_omp_parallel (); |
22842 | parser->omp_attrs_forbidden_p = true; |
22843 | c_parser_statement (parser, if_p); |
22844 | stmt = c_finish_omp_parallel (loc, clauses, block); |
22845 | |
22846 | return stmt; |
22847 | } |
22848 | |
22849 | /* OpenMP 2.5: |
22850 | # pragma omp single single-clause[optseq] new-line |
22851 | structured-block |
22852 | |
22853 | LOC is the location of the #pragma. |
22854 | */ |
22855 | |
22856 | #define OMP_SINGLE_CLAUSE_MASK \ |
22857 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22858 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22859 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ |
22860 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22861 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
22862 | |
22863 | static tree |
22864 | c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) |
22865 | { |
22866 | tree stmt = make_node (OMP_SINGLE); |
22867 | SET_EXPR_LOCATION (stmt, loc); |
22868 | TREE_TYPE (stmt) = void_type_node; |
22869 | |
22870 | OMP_SINGLE_CLAUSES (stmt) |
22871 | = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, |
22872 | where: "#pragma omp single" ); |
22873 | OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); |
22874 | |
22875 | return add_stmt (stmt); |
22876 | } |
22877 | |
22878 | /* OpenMP 5.1: |
22879 | # pragma omp scope scope-clause[optseq] new-line |
22880 | structured-block |
22881 | |
22882 | LOC is the location of the #pragma. |
22883 | */ |
22884 | |
22885 | #define OMP_SCOPE_CLAUSE_MASK \ |
22886 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22887 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22888 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22889 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22890 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
22891 | |
22892 | static tree |
22893 | c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) |
22894 | { |
22895 | tree stmt = make_node (OMP_SCOPE); |
22896 | SET_EXPR_LOCATION (stmt, loc); |
22897 | TREE_TYPE (stmt) = void_type_node; |
22898 | |
22899 | OMP_SCOPE_CLAUSES (stmt) |
22900 | = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, |
22901 | where: "#pragma omp scope" ); |
22902 | OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); |
22903 | |
22904 | return add_stmt (stmt); |
22905 | } |
22906 | |
22907 | /* OpenMP 3.0: |
22908 | # pragma omp task task-clause[optseq] new-line |
22909 | |
22910 | LOC is the location of the #pragma. |
22911 | */ |
22912 | |
22913 | #define OMP_TASK_CLAUSE_MASK \ |
22914 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
22915 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ |
22916 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
22917 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22918 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22919 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
22920 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ |
22921 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ |
22922 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
22923 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ |
22924 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22925 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ |
22926 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ |
22927 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) |
22928 | |
22929 | static tree |
22930 | c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) |
22931 | { |
22932 | tree clauses, block; |
22933 | |
22934 | clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, |
22935 | where: "#pragma omp task" ); |
22936 | |
22937 | block = c_begin_omp_task (); |
22938 | parser->omp_attrs_forbidden_p = true; |
22939 | c_parser_statement (parser, if_p); |
22940 | return c_finish_omp_task (loc, clauses, block); |
22941 | } |
22942 | |
22943 | /* OpenMP 3.0: |
22944 | # pragma omp taskwait new-line |
22945 | |
22946 | OpenMP 5.0: |
22947 | # pragma omp taskwait taskwait-clause[optseq] new-line |
22948 | */ |
22949 | |
22950 | #define OMP_TASKWAIT_CLAUSE_MASK \ |
22951 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
22952 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
22953 | |
22954 | static void |
22955 | c_parser_omp_taskwait (c_parser *parser) |
22956 | { |
22957 | location_t loc = c_parser_peek_token (parser)->location; |
22958 | c_parser_consume_pragma (parser); |
22959 | |
22960 | tree clauses |
22961 | = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK, |
22962 | where: "#pragma omp taskwait" ); |
22963 | |
22964 | if (clauses) |
22965 | { |
22966 | tree stmt = make_node (OMP_TASK); |
22967 | TREE_TYPE (stmt) = void_node; |
22968 | OMP_TASK_CLAUSES (stmt) = clauses; |
22969 | OMP_TASK_BODY (stmt) = NULL_TREE; |
22970 | SET_EXPR_LOCATION (stmt, loc); |
22971 | add_stmt (stmt); |
22972 | } |
22973 | else |
22974 | c_finish_omp_taskwait (loc); |
22975 | } |
22976 | |
22977 | /* OpenMP 3.1: |
22978 | # pragma omp taskyield new-line |
22979 | */ |
22980 | |
22981 | static void |
22982 | c_parser_omp_taskyield (c_parser *parser) |
22983 | { |
22984 | location_t loc = c_parser_peek_token (parser)->location; |
22985 | c_parser_consume_pragma (parser); |
22986 | c_parser_skip_to_pragma_eol (parser); |
22987 | |
22988 | c_finish_omp_taskyield (loc); |
22989 | } |
22990 | |
22991 | /* OpenMP 4.0: |
22992 | # pragma omp taskgroup new-line |
22993 | |
22994 | OpenMP 5.0: |
22995 | # pragma omp taskgroup taskgroup-clause[optseq] new-line |
22996 | */ |
22997 | |
22998 | #define OMP_TASKGROUP_CLAUSE_MASK \ |
22999 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23000 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) |
23001 | |
23002 | static tree |
23003 | c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p) |
23004 | { |
23005 | tree clauses = c_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK, |
23006 | where: "#pragma omp taskgroup" ); |
23007 | |
23008 | tree body = c_parser_omp_structured_block (parser, if_p); |
23009 | return c_finish_omp_taskgroup (loc, body, clauses); |
23010 | } |
23011 | |
23012 | /* OpenMP 4.0: |
23013 | # pragma omp cancel cancel-clause[optseq] new-line |
23014 | |
23015 | LOC is the location of the #pragma. |
23016 | */ |
23017 | |
23018 | #define OMP_CANCEL_CLAUSE_MASK \ |
23019 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ |
23020 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ |
23021 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ |
23022 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ |
23023 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) |
23024 | |
23025 | static void |
23026 | c_parser_omp_cancel (c_parser *parser) |
23027 | { |
23028 | location_t loc = c_parser_peek_token (parser)->location; |
23029 | |
23030 | c_parser_consume_pragma (parser); |
23031 | tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, |
23032 | where: "#pragma omp cancel" ); |
23033 | |
23034 | c_finish_omp_cancel (loc, clauses); |
23035 | } |
23036 | |
23037 | /* OpenMP 4.0: |
23038 | # pragma omp cancellation point cancelpt-clause[optseq] new-line |
23039 | |
23040 | LOC is the location of the #pragma. |
23041 | */ |
23042 | |
23043 | #define OMP_CANCELLATION_POINT_CLAUSE_MASK \ |
23044 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ |
23045 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ |
23046 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ |
23047 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) |
23048 | |
23049 | static bool |
23050 | c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) |
23051 | { |
23052 | location_t loc = c_parser_peek_token (parser)->location; |
23053 | tree clauses; |
23054 | bool point_seen = false; |
23055 | |
23056 | c_parser_consume_pragma (parser); |
23057 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23058 | { |
23059 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23060 | if (strcmp (s1: p, s2: "point" ) == 0) |
23061 | { |
23062 | c_parser_consume_token (parser); |
23063 | point_seen = true; |
23064 | } |
23065 | } |
23066 | if (!point_seen) |
23067 | { |
23068 | c_parser_error (parser, gmsgid: "expected %<point%>" ); |
23069 | c_parser_skip_to_pragma_eol (parser); |
23070 | return false; |
23071 | } |
23072 | |
23073 | if (context != pragma_compound) |
23074 | { |
23075 | if (context == pragma_stmt) |
23076 | error_at (loc, |
23077 | "%<#pragma %s%> may only be used in compound statements" , |
23078 | "omp cancellation point" ); |
23079 | else |
23080 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
23081 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23082 | return true; |
23083 | } |
23084 | |
23085 | clauses |
23086 | = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, |
23087 | where: "#pragma omp cancellation point" ); |
23088 | |
23089 | c_finish_omp_cancellation_point (loc, clauses); |
23090 | return true; |
23091 | } |
23092 | |
23093 | /* OpenMP 4.0: |
23094 | #pragma omp distribute distribute-clause[optseq] new-line |
23095 | for-loop */ |
23096 | |
23097 | #define OMP_DISTRIBUTE_CLAUSE_MASK \ |
23098 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23099 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23100 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
23101 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ |
23102 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23103 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
23104 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
23105 | |
23106 | static tree |
23107 | c_parser_omp_distribute (location_t loc, c_parser *parser, |
23108 | char *p_name, omp_clause_mask mask, tree *cclauses, |
23109 | bool *if_p) |
23110 | { |
23111 | tree clauses, block, ret; |
23112 | |
23113 | strcat (dest: p_name, src: " distribute" ); |
23114 | mask |= OMP_DISTRIBUTE_CLAUSE_MASK; |
23115 | |
23116 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23117 | { |
23118 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23119 | bool simd = false; |
23120 | bool parallel = false; |
23121 | |
23122 | if (strcmp (s1: p, s2: "simd" ) == 0) |
23123 | simd = true; |
23124 | else |
23125 | parallel = strcmp (s1: p, s2: "parallel" ) == 0; |
23126 | if (parallel || simd) |
23127 | { |
23128 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23129 | if (cclauses == NULL) |
23130 | cclauses = cclauses_buf; |
23131 | c_parser_consume_token (parser); |
23132 | if (!flag_openmp) /* flag_openmp_simd */ |
23133 | { |
23134 | if (simd) |
23135 | return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
23136 | if_p); |
23137 | else |
23138 | return c_parser_omp_parallel (loc, parser, p_name, mask, |
23139 | cclauses, if_p); |
23140 | } |
23141 | block = c_begin_compound_stmt (true); |
23142 | if (simd) |
23143 | ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
23144 | if_p); |
23145 | else |
23146 | ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses, |
23147 | if_p); |
23148 | block = c_end_compound_stmt (loc, block, true); |
23149 | if (ret == NULL) |
23150 | return ret; |
23151 | ret = make_node (OMP_DISTRIBUTE); |
23152 | TREE_TYPE (ret) = void_type_node; |
23153 | OMP_FOR_BODY (ret) = block; |
23154 | OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; |
23155 | SET_EXPR_LOCATION (ret, loc); |
23156 | add_stmt (ret); |
23157 | return ret; |
23158 | } |
23159 | } |
23160 | if (!flag_openmp) /* flag_openmp_simd */ |
23161 | { |
23162 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23163 | return NULL_TREE; |
23164 | } |
23165 | |
23166 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
23167 | if (cclauses) |
23168 | { |
23169 | omp_split_clauses (loc, code: OMP_DISTRIBUTE, mask, clauses, cclauses); |
23170 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; |
23171 | } |
23172 | |
23173 | block = c_begin_compound_stmt (true); |
23174 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_DISTRIBUTE, clauses, NULL, |
23175 | if_p); |
23176 | block = c_end_compound_stmt (loc, block, true); |
23177 | add_stmt (block); |
23178 | |
23179 | return ret; |
23180 | } |
23181 | |
23182 | /* OpenMP 4.0: |
23183 | # pragma omp teams teams-clause[optseq] new-line |
23184 | structured-block */ |
23185 | |
23186 | #define OMP_TEAMS_CLAUSE_MASK \ |
23187 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23188 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23189 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
23190 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
23191 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ |
23192 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ |
23193 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23194 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) |
23195 | |
23196 | static tree |
23197 | c_parser_omp_teams (location_t loc, c_parser *parser, |
23198 | char *p_name, omp_clause_mask mask, tree *cclauses, |
23199 | bool *if_p) |
23200 | { |
23201 | tree clauses, block, ret; |
23202 | |
23203 | strcat (dest: p_name, src: " teams" ); |
23204 | mask |= OMP_TEAMS_CLAUSE_MASK; |
23205 | |
23206 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23207 | { |
23208 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23209 | if (strcmp (s1: p, s2: "distribute" ) == 0) |
23210 | { |
23211 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23212 | if (cclauses == NULL) |
23213 | cclauses = cclauses_buf; |
23214 | |
23215 | c_parser_consume_token (parser); |
23216 | if (!flag_openmp) /* flag_openmp_simd */ |
23217 | return c_parser_omp_distribute (loc, parser, p_name, mask, |
23218 | cclauses, if_p); |
23219 | block = c_begin_omp_parallel (); |
23220 | ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses, |
23221 | if_p); |
23222 | block = c_end_compound_stmt (loc, block, true); |
23223 | if (ret == NULL) |
23224 | return ret; |
23225 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23226 | ret = make_node (OMP_TEAMS); |
23227 | TREE_TYPE (ret) = void_type_node; |
23228 | OMP_TEAMS_CLAUSES (ret) = clauses; |
23229 | OMP_TEAMS_BODY (ret) = block; |
23230 | OMP_TEAMS_COMBINED (ret) = 1; |
23231 | SET_EXPR_LOCATION (ret, loc); |
23232 | return add_stmt (ret); |
23233 | } |
23234 | else if (strcmp (s1: p, s2: "loop" ) == 0) |
23235 | { |
23236 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23237 | if (cclauses == NULL) |
23238 | cclauses = cclauses_buf; |
23239 | |
23240 | c_parser_consume_token (parser); |
23241 | if (!flag_openmp) /* flag_openmp_simd */ |
23242 | return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, |
23243 | if_p); |
23244 | block = c_begin_omp_parallel (); |
23245 | ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, if_p); |
23246 | block = c_end_compound_stmt (loc, block, true); |
23247 | if (ret == NULL) |
23248 | return ret; |
23249 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23250 | ret = make_node (OMP_TEAMS); |
23251 | TREE_TYPE (ret) = void_type_node; |
23252 | OMP_TEAMS_CLAUSES (ret) = clauses; |
23253 | OMP_TEAMS_BODY (ret) = block; |
23254 | OMP_TEAMS_COMBINED (ret) = 1; |
23255 | SET_EXPR_LOCATION (ret, loc); |
23256 | return add_stmt (ret); |
23257 | } |
23258 | } |
23259 | if (!flag_openmp) /* flag_openmp_simd */ |
23260 | { |
23261 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23262 | return NULL_TREE; |
23263 | } |
23264 | |
23265 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
23266 | if (cclauses) |
23267 | { |
23268 | omp_split_clauses (loc, code: OMP_TEAMS, mask, clauses, cclauses); |
23269 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23270 | } |
23271 | |
23272 | tree stmt = make_node (OMP_TEAMS); |
23273 | TREE_TYPE (stmt) = void_type_node; |
23274 | OMP_TEAMS_CLAUSES (stmt) = clauses; |
23275 | block = c_begin_omp_parallel (); |
23276 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
23277 | OMP_TEAMS_BODY (stmt) = c_end_compound_stmt (loc, block, true); |
23278 | SET_EXPR_LOCATION (stmt, loc); |
23279 | |
23280 | return add_stmt (stmt); |
23281 | } |
23282 | |
23283 | /* OpenMP 4.0: |
23284 | # pragma omp target data target-data-clause[optseq] new-line |
23285 | structured-block */ |
23286 | |
23287 | #define OMP_TARGET_DATA_CLAUSE_MASK \ |
23288 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23289 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
23290 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23291 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR) \ |
23292 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR)) |
23293 | |
23294 | static tree |
23295 | c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) |
23296 | { |
23297 | if (flag_openmp) |
23298 | omp_requires_mask |
23299 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23300 | |
23301 | tree clauses |
23302 | = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, |
23303 | where: "#pragma omp target data" ); |
23304 | c_omp_adjust_map_clauses (clauses, false); |
23305 | int map_seen = 0; |
23306 | for (tree *pc = &clauses; *pc;) |
23307 | { |
23308 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
23309 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
23310 | { |
23311 | case GOMP_MAP_TO: |
23312 | case GOMP_MAP_ALWAYS_TO: |
23313 | case GOMP_MAP_PRESENT_TO: |
23314 | case GOMP_MAP_ALWAYS_PRESENT_TO: |
23315 | case GOMP_MAP_FROM: |
23316 | case GOMP_MAP_ALWAYS_FROM: |
23317 | case GOMP_MAP_PRESENT_FROM: |
23318 | case GOMP_MAP_ALWAYS_PRESENT_FROM: |
23319 | case GOMP_MAP_TOFROM: |
23320 | case GOMP_MAP_ALWAYS_TOFROM: |
23321 | case GOMP_MAP_PRESENT_TOFROM: |
23322 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
23323 | case GOMP_MAP_ALLOC: |
23324 | case GOMP_MAP_PRESENT_ALLOC: |
23325 | map_seen = 3; |
23326 | break; |
23327 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
23328 | case GOMP_MAP_ALWAYS_POINTER: |
23329 | case GOMP_MAP_ATTACH_DETACH: |
23330 | break; |
23331 | default: |
23332 | map_seen |= 1; |
23333 | error_at (OMP_CLAUSE_LOCATION (*pc), |
23334 | "%<#pragma omp target data%> with map-type other " |
23335 | "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> " |
23336 | "on %<map%> clause" ); |
23337 | *pc = OMP_CLAUSE_CHAIN (*pc); |
23338 | continue; |
23339 | } |
23340 | else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR |
23341 | || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR) |
23342 | map_seen = 3; |
23343 | pc = &OMP_CLAUSE_CHAIN (*pc); |
23344 | } |
23345 | |
23346 | if (map_seen != 3) |
23347 | { |
23348 | if (map_seen == 0) |
23349 | error_at (loc, |
23350 | "%<#pragma omp target data%> must contain at least " |
23351 | "one %<map%>, %<use_device_ptr%> or %<use_device_addr%> " |
23352 | "clause" ); |
23353 | return NULL_TREE; |
23354 | } |
23355 | |
23356 | tree stmt = make_node (OMP_TARGET_DATA); |
23357 | TREE_TYPE (stmt) = void_type_node; |
23358 | OMP_TARGET_DATA_CLAUSES (stmt) = clauses; |
23359 | keep_next_level (); |
23360 | tree block = c_begin_compound_stmt (true); |
23361 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
23362 | OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true); |
23363 | |
23364 | SET_EXPR_LOCATION (stmt, loc); |
23365 | return add_stmt (stmt); |
23366 | } |
23367 | |
23368 | /* OpenMP 4.0: |
23369 | # pragma omp target update target-update-clause[optseq] new-line */ |
23370 | |
23371 | #define OMP_TARGET_UPDATE_CLAUSE_MASK \ |
23372 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ |
23373 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ |
23374 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23375 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23376 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23377 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23378 | |
23379 | static bool |
23380 | c_parser_omp_target_update (location_t loc, c_parser *parser, |
23381 | enum pragma_context context) |
23382 | { |
23383 | if (context == pragma_stmt) |
23384 | { |
23385 | error_at (loc, "%<#pragma %s%> may only be used in compound statements" , |
23386 | "omp target update" ); |
23387 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23388 | return true; |
23389 | } |
23390 | |
23391 | tree clauses |
23392 | = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, |
23393 | where: "#pragma omp target update" ); |
23394 | if (omp_find_clause (clauses, kind: OMP_CLAUSE_TO) == NULL_TREE |
23395 | && omp_find_clause (clauses, kind: OMP_CLAUSE_FROM) == NULL_TREE) |
23396 | { |
23397 | error_at (loc, |
23398 | "%<#pragma omp target update%> must contain at least one " |
23399 | "%<from%> or %<to%> clauses" ); |
23400 | return false; |
23401 | } |
23402 | |
23403 | if (flag_openmp) |
23404 | omp_requires_mask |
23405 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23406 | |
23407 | tree stmt = make_node (OMP_TARGET_UPDATE); |
23408 | TREE_TYPE (stmt) = void_type_node; |
23409 | OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; |
23410 | SET_EXPR_LOCATION (stmt, loc); |
23411 | add_stmt (stmt); |
23412 | return false; |
23413 | } |
23414 | |
23415 | /* OpenMP 4.5: |
23416 | # pragma omp target enter data target-data-clause[optseq] new-line */ |
23417 | |
23418 | #define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \ |
23419 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23420 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
23421 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23422 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23423 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23424 | |
23425 | static bool |
23426 | c_parser_omp_target_enter_data (location_t loc, c_parser *parser, |
23427 | enum pragma_context context) |
23428 | { |
23429 | bool data_seen = false; |
23430 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23431 | { |
23432 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23433 | if (strcmp (s1: p, s2: "data" ) == 0) |
23434 | { |
23435 | c_parser_consume_token (parser); |
23436 | data_seen = true; |
23437 | } |
23438 | } |
23439 | if (!data_seen) |
23440 | { |
23441 | c_parser_error (parser, gmsgid: "expected %<data%>" ); |
23442 | c_parser_skip_to_pragma_eol (parser); |
23443 | return false; |
23444 | } |
23445 | |
23446 | if (context == pragma_stmt) |
23447 | { |
23448 | error_at (loc, "%<#pragma %s%> may only be used in compound statements" , |
23449 | "omp target enter data" ); |
23450 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23451 | return true; |
23452 | } |
23453 | |
23454 | if (flag_openmp) |
23455 | omp_requires_mask |
23456 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23457 | |
23458 | tree clauses |
23459 | = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, |
23460 | where: "#pragma omp target enter data" ); |
23461 | c_omp_adjust_map_clauses (clauses, false); |
23462 | int map_seen = 0; |
23463 | for (tree *pc = &clauses; *pc;) |
23464 | { |
23465 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
23466 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
23467 | { |
23468 | case GOMP_MAP_TO: |
23469 | case GOMP_MAP_ALWAYS_TO: |
23470 | case GOMP_MAP_PRESENT_TO: |
23471 | case GOMP_MAP_ALWAYS_PRESENT_TO: |
23472 | case GOMP_MAP_ALLOC: |
23473 | case GOMP_MAP_PRESENT_ALLOC: |
23474 | map_seen = 3; |
23475 | break; |
23476 | case GOMP_MAP_TOFROM: |
23477 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_TO); |
23478 | map_seen = 3; |
23479 | break; |
23480 | case GOMP_MAP_ALWAYS_TOFROM: |
23481 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_TO); |
23482 | map_seen = 3; |
23483 | break; |
23484 | case GOMP_MAP_PRESENT_TOFROM: |
23485 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_TO); |
23486 | map_seen = 3; |
23487 | break; |
23488 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
23489 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_TO); |
23490 | map_seen = 3; |
23491 | break; |
23492 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
23493 | case GOMP_MAP_ALWAYS_POINTER: |
23494 | case GOMP_MAP_ATTACH_DETACH: |
23495 | break; |
23496 | default: |
23497 | map_seen |= 1; |
23498 | error_at (OMP_CLAUSE_LOCATION (*pc), |
23499 | "%<#pragma omp target enter data%> with map-type other " |
23500 | "than %<to%>, %<tofrom%> or %<alloc%> on %<map%> clause" ); |
23501 | *pc = OMP_CLAUSE_CHAIN (*pc); |
23502 | continue; |
23503 | } |
23504 | pc = &OMP_CLAUSE_CHAIN (*pc); |
23505 | } |
23506 | |
23507 | if (map_seen != 3) |
23508 | { |
23509 | if (map_seen == 0) |
23510 | error_at (loc, |
23511 | "%<#pragma omp target enter data%> must contain at least " |
23512 | "one %<map%> clause" ); |
23513 | return true; |
23514 | } |
23515 | |
23516 | tree stmt = make_node (OMP_TARGET_ENTER_DATA); |
23517 | TREE_TYPE (stmt) = void_type_node; |
23518 | OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; |
23519 | SET_EXPR_LOCATION (stmt, loc); |
23520 | add_stmt (stmt); |
23521 | return true; |
23522 | } |
23523 | |
23524 | /* OpenMP 4.5: |
23525 | # pragma omp target exit data target-data-clause[optseq] new-line */ |
23526 | |
23527 | #define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \ |
23528 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23529 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
23530 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23531 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23532 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23533 | |
23534 | static bool |
23535 | c_parser_omp_target_exit_data (location_t loc, c_parser *parser, |
23536 | enum pragma_context context) |
23537 | { |
23538 | bool data_seen = false; |
23539 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23540 | { |
23541 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23542 | if (strcmp (s1: p, s2: "data" ) == 0) |
23543 | { |
23544 | c_parser_consume_token (parser); |
23545 | data_seen = true; |
23546 | } |
23547 | } |
23548 | if (!data_seen) |
23549 | { |
23550 | c_parser_error (parser, gmsgid: "expected %<data%>" ); |
23551 | c_parser_skip_to_pragma_eol (parser); |
23552 | return false; |
23553 | } |
23554 | |
23555 | if (context == pragma_stmt) |
23556 | { |
23557 | error_at (loc, "%<#pragma %s%> may only be used in compound statements" , |
23558 | "omp target exit data" ); |
23559 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23560 | return true; |
23561 | } |
23562 | |
23563 | if (flag_openmp) |
23564 | omp_requires_mask |
23565 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23566 | |
23567 | tree clauses |
23568 | = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, |
23569 | where: "#pragma omp target exit data" ); |
23570 | c_omp_adjust_map_clauses (clauses, false); |
23571 | int map_seen = 0; |
23572 | for (tree *pc = &clauses; *pc;) |
23573 | { |
23574 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
23575 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
23576 | { |
23577 | case GOMP_MAP_FROM: |
23578 | case GOMP_MAP_ALWAYS_FROM: |
23579 | case GOMP_MAP_PRESENT_FROM: |
23580 | case GOMP_MAP_ALWAYS_PRESENT_FROM: |
23581 | case GOMP_MAP_RELEASE: |
23582 | case GOMP_MAP_DELETE: |
23583 | map_seen = 3; |
23584 | break; |
23585 | case GOMP_MAP_TOFROM: |
23586 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_FROM); |
23587 | map_seen = 3; |
23588 | break; |
23589 | case GOMP_MAP_ALWAYS_TOFROM: |
23590 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_FROM); |
23591 | map_seen = 3; |
23592 | break; |
23593 | case GOMP_MAP_PRESENT_TOFROM: |
23594 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_FROM); |
23595 | map_seen = 3; |
23596 | break; |
23597 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
23598 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_FROM); |
23599 | map_seen = 3; |
23600 | break; |
23601 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
23602 | case GOMP_MAP_ALWAYS_POINTER: |
23603 | case GOMP_MAP_ATTACH_DETACH: |
23604 | break; |
23605 | default: |
23606 | map_seen |= 1; |
23607 | error_at (OMP_CLAUSE_LOCATION (*pc), |
23608 | "%<#pragma omp target exit data%> with map-type other " |
23609 | "than %<from%>, %<tofrom%>, %<release%> or %<delete%> " |
23610 | "on %<map%> clause" ); |
23611 | *pc = OMP_CLAUSE_CHAIN (*pc); |
23612 | continue; |
23613 | } |
23614 | pc = &OMP_CLAUSE_CHAIN (*pc); |
23615 | } |
23616 | |
23617 | if (map_seen != 3) |
23618 | { |
23619 | if (map_seen == 0) |
23620 | error_at (loc, |
23621 | "%<#pragma omp target exit data%> must contain at least one " |
23622 | "%<map%> clause" ); |
23623 | return true; |
23624 | } |
23625 | |
23626 | tree stmt = make_node (OMP_TARGET_EXIT_DATA); |
23627 | TREE_TYPE (stmt) = void_type_node; |
23628 | OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; |
23629 | SET_EXPR_LOCATION (stmt, loc); |
23630 | add_stmt (stmt); |
23631 | return true; |
23632 | } |
23633 | |
23634 | /* OpenMP 4.0: |
23635 | # pragma omp target target-clause[optseq] new-line |
23636 | structured-block */ |
23637 | |
23638 | #define OMP_TARGET_CLAUSE_MASK \ |
23639 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23640 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
23641 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23642 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23643 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ |
23644 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23645 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23646 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23647 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ |
23648 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ |
23649 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ |
23650 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)\ |
23651 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR)) |
23652 | |
23653 | static bool |
23654 | c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) |
23655 | { |
23656 | location_t loc = c_parser_peek_token (parser)->location; |
23657 | c_parser_consume_pragma (parser); |
23658 | tree *pc = NULL, stmt, block; |
23659 | |
23660 | if (context != pragma_stmt && context != pragma_compound) |
23661 | { |
23662 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
23663 | c_parser_skip_to_pragma_eol (parser); |
23664 | return false; |
23665 | } |
23666 | |
23667 | if (flag_openmp) |
23668 | omp_requires_mask |
23669 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23670 | |
23671 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23672 | { |
23673 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23674 | enum tree_code ccode = ERROR_MARK; |
23675 | |
23676 | if (strcmp (s1: p, s2: "teams" ) == 0) |
23677 | ccode = OMP_TEAMS; |
23678 | else if (strcmp (s1: p, s2: "parallel" ) == 0) |
23679 | ccode = OMP_PARALLEL; |
23680 | else if (strcmp (s1: p, s2: "simd" ) == 0) |
23681 | ccode = OMP_SIMD; |
23682 | if (ccode != ERROR_MARK) |
23683 | { |
23684 | tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; |
23685 | char p_name[sizeof ("#pragma omp target teams distribute " |
23686 | "parallel for simd" )]; |
23687 | |
23688 | c_parser_consume_token (parser); |
23689 | strcpy (dest: p_name, src: "#pragma omp target" ); |
23690 | if (!flag_openmp) /* flag_openmp_simd */ |
23691 | { |
23692 | tree stmt; |
23693 | switch (ccode) |
23694 | { |
23695 | case OMP_TEAMS: |
23696 | stmt = c_parser_omp_teams (loc, parser, p_name, |
23697 | OMP_TARGET_CLAUSE_MASK, |
23698 | cclauses, if_p); |
23699 | break; |
23700 | case OMP_PARALLEL: |
23701 | stmt = c_parser_omp_parallel (loc, parser, p_name, |
23702 | OMP_TARGET_CLAUSE_MASK, |
23703 | cclauses, if_p); |
23704 | break; |
23705 | case OMP_SIMD: |
23706 | stmt = c_parser_omp_simd (loc, parser, p_name, |
23707 | OMP_TARGET_CLAUSE_MASK, |
23708 | cclauses, if_p); |
23709 | break; |
23710 | default: |
23711 | gcc_unreachable (); |
23712 | } |
23713 | return stmt != NULL_TREE; |
23714 | } |
23715 | keep_next_level (); |
23716 | tree block = c_begin_compound_stmt (true), ret; |
23717 | switch (ccode) |
23718 | { |
23719 | case OMP_TEAMS: |
23720 | ret = c_parser_omp_teams (loc, parser, p_name, |
23721 | OMP_TARGET_CLAUSE_MASK, cclauses, |
23722 | if_p); |
23723 | break; |
23724 | case OMP_PARALLEL: |
23725 | ret = c_parser_omp_parallel (loc, parser, p_name, |
23726 | OMP_TARGET_CLAUSE_MASK, cclauses, |
23727 | if_p); |
23728 | break; |
23729 | case OMP_SIMD: |
23730 | ret = c_parser_omp_simd (loc, parser, p_name, |
23731 | OMP_TARGET_CLAUSE_MASK, cclauses, |
23732 | if_p); |
23733 | break; |
23734 | default: |
23735 | gcc_unreachable (); |
23736 | } |
23737 | block = c_end_compound_stmt (loc, block, true); |
23738 | if (ret == NULL_TREE) |
23739 | return false; |
23740 | if (ccode == OMP_TEAMS) |
23741 | /* For combined target teams, ensure the num_teams and |
23742 | thread_limit clause expressions are evaluated on the host, |
23743 | before entering the target construct. */ |
23744 | for (tree c = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23745 | c; c = OMP_CLAUSE_CHAIN (c)) |
23746 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS |
23747 | || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT) |
23748 | for (int i = 0; |
23749 | i <= (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS); ++i) |
23750 | if (OMP_CLAUSE_OPERAND (c, i) |
23751 | && TREE_CODE (OMP_CLAUSE_OPERAND (c, i)) != INTEGER_CST) |
23752 | { |
23753 | tree expr = OMP_CLAUSE_OPERAND (c, i); |
23754 | tree tmp = create_tmp_var_raw (TREE_TYPE (expr)); |
23755 | expr = build4 (TARGET_EXPR, TREE_TYPE (expr), tmp, |
23756 | expr, NULL_TREE, NULL_TREE); |
23757 | add_stmt (expr); |
23758 | OMP_CLAUSE_OPERAND (c, i) = expr; |
23759 | tree tc = build_omp_clause (OMP_CLAUSE_LOCATION (c), |
23760 | OMP_CLAUSE_FIRSTPRIVATE); |
23761 | OMP_CLAUSE_DECL (tc) = tmp; |
23762 | OMP_CLAUSE_CHAIN (tc) |
23763 | = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; |
23764 | cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = tc; |
23765 | } |
23766 | tree stmt = make_node (OMP_TARGET); |
23767 | TREE_TYPE (stmt) = void_type_node; |
23768 | OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; |
23769 | c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); |
23770 | OMP_TARGET_BODY (stmt) = block; |
23771 | OMP_TARGET_COMBINED (stmt) = 1; |
23772 | SET_EXPR_LOCATION (stmt, loc); |
23773 | add_stmt (stmt); |
23774 | pc = &OMP_TARGET_CLAUSES (stmt); |
23775 | goto check_clauses; |
23776 | } |
23777 | else if (!flag_openmp) /* flag_openmp_simd */ |
23778 | { |
23779 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23780 | return false; |
23781 | } |
23782 | else if (strcmp (s1: p, s2: "data" ) == 0) |
23783 | { |
23784 | c_parser_consume_token (parser); |
23785 | c_parser_omp_target_data (loc, parser, if_p); |
23786 | return true; |
23787 | } |
23788 | else if (strcmp (s1: p, s2: "enter" ) == 0) |
23789 | { |
23790 | c_parser_consume_token (parser); |
23791 | return c_parser_omp_target_enter_data (loc, parser, context); |
23792 | } |
23793 | else if (strcmp (s1: p, s2: "exit" ) == 0) |
23794 | { |
23795 | c_parser_consume_token (parser); |
23796 | return c_parser_omp_target_exit_data (loc, parser, context); |
23797 | } |
23798 | else if (strcmp (s1: p, s2: "update" ) == 0) |
23799 | { |
23800 | c_parser_consume_token (parser); |
23801 | return c_parser_omp_target_update (loc, parser, context); |
23802 | } |
23803 | } |
23804 | if (!flag_openmp) /* flag_openmp_simd */ |
23805 | { |
23806 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23807 | return false; |
23808 | } |
23809 | |
23810 | stmt = make_node (OMP_TARGET); |
23811 | TREE_TYPE (stmt) = void_type_node; |
23812 | |
23813 | OMP_TARGET_CLAUSES (stmt) |
23814 | = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, |
23815 | where: "#pragma omp target" , finish_p: false); |
23816 | for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) |
23817 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) |
23818 | { |
23819 | tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); |
23820 | OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); |
23821 | OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); |
23822 | OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); |
23823 | OMP_CLAUSE_CHAIN (c) = nc; |
23824 | } |
23825 | OMP_TARGET_CLAUSES (stmt) |
23826 | = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); |
23827 | c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); |
23828 | |
23829 | pc = &OMP_TARGET_CLAUSES (stmt); |
23830 | keep_next_level (); |
23831 | block = c_begin_compound_stmt (true); |
23832 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
23833 | OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); |
23834 | |
23835 | SET_EXPR_LOCATION (stmt, loc); |
23836 | add_stmt (stmt); |
23837 | |
23838 | check_clauses: |
23839 | while (*pc) |
23840 | { |
23841 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
23842 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
23843 | { |
23844 | case GOMP_MAP_TO: |
23845 | case GOMP_MAP_ALWAYS_TO: |
23846 | case GOMP_MAP_PRESENT_TO: |
23847 | case GOMP_MAP_ALWAYS_PRESENT_TO: |
23848 | case GOMP_MAP_FROM: |
23849 | case GOMP_MAP_ALWAYS_FROM: |
23850 | case GOMP_MAP_PRESENT_FROM: |
23851 | case GOMP_MAP_ALWAYS_PRESENT_FROM: |
23852 | case GOMP_MAP_TOFROM: |
23853 | case GOMP_MAP_ALWAYS_TOFROM: |
23854 | case GOMP_MAP_PRESENT_TOFROM: |
23855 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
23856 | case GOMP_MAP_ALLOC: |
23857 | case GOMP_MAP_PRESENT_ALLOC: |
23858 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
23859 | case GOMP_MAP_ALWAYS_POINTER: |
23860 | case GOMP_MAP_ATTACH_DETACH: |
23861 | break; |
23862 | default: |
23863 | error_at (OMP_CLAUSE_LOCATION (*pc), |
23864 | "%<#pragma omp target%> with map-type other " |
23865 | "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> " |
23866 | "on %<map%> clause" ); |
23867 | *pc = OMP_CLAUSE_CHAIN (*pc); |
23868 | continue; |
23869 | } |
23870 | pc = &OMP_CLAUSE_CHAIN (*pc); |
23871 | } |
23872 | cfun->has_omp_target = true; |
23873 | return true; |
23874 | } |
23875 | |
23876 | /* OpenMP 4.0: |
23877 | # pragma omp declare simd declare-simd-clauses[optseq] new-line |
23878 | |
23879 | OpenMP 5.0: |
23880 | # pragma omp declare variant (identifier) match(context-selector) new-line |
23881 | */ |
23882 | |
23883 | #define OMP_DECLARE_SIMD_CLAUSE_MASK \ |
23884 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ |
23885 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ |
23886 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ |
23887 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ |
23888 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ |
23889 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) |
23890 | |
23891 | static void |
23892 | c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) |
23893 | { |
23894 | c_token *token = c_parser_peek_token (parser); |
23895 | gcc_assert (token->type == CPP_NAME); |
23896 | tree kind = token->value; |
23897 | gcc_assert (strcmp (IDENTIFIER_POINTER (kind), "simd" ) == 0 |
23898 | || strcmp (IDENTIFIER_POINTER (kind), "variant" ) == 0); |
23899 | |
23900 | auto_vec<c_token> clauses; |
23901 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
23902 | { |
23903 | c_token *token = c_parser_peek_token (parser); |
23904 | if (token->type == CPP_EOF) |
23905 | { |
23906 | c_parser_skip_to_pragma_eol (parser); |
23907 | return; |
23908 | } |
23909 | clauses.safe_push (obj: *token); |
23910 | c_parser_consume_token (parser); |
23911 | } |
23912 | clauses.safe_push (obj: *c_parser_peek_token (parser)); |
23913 | c_parser_skip_to_pragma_eol (parser); |
23914 | |
23915 | while (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
23916 | { |
23917 | if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_DECLARE |
23918 | || c_parser_peek_2nd_token (parser)->type != CPP_NAME |
23919 | || c_parser_peek_2nd_token (parser)->value != kind) |
23920 | { |
23921 | error ("%<#pragma omp declare %s%> must be followed by " |
23922 | "function declaration or definition or another " |
23923 | "%<#pragma omp declare %s%>" , |
23924 | IDENTIFIER_POINTER (kind), IDENTIFIER_POINTER (kind)); |
23925 | return; |
23926 | } |
23927 | c_parser_consume_pragma (parser); |
23928 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
23929 | { |
23930 | c_token *token = c_parser_peek_token (parser); |
23931 | if (token->type == CPP_EOF) |
23932 | { |
23933 | c_parser_skip_to_pragma_eol (parser); |
23934 | return; |
23935 | } |
23936 | clauses.safe_push (obj: *token); |
23937 | c_parser_consume_token (parser); |
23938 | } |
23939 | clauses.safe_push (obj: *c_parser_peek_token (parser)); |
23940 | c_parser_skip_to_pragma_eol (parser); |
23941 | } |
23942 | |
23943 | /* Make sure nothing tries to read past the end of the tokens. */ |
23944 | c_token eof_token; |
23945 | memset (s: &eof_token, c: 0, n: sizeof (eof_token)); |
23946 | eof_token.type = CPP_EOF; |
23947 | clauses.safe_push (obj: eof_token); |
23948 | clauses.safe_push (obj: eof_token); |
23949 | |
23950 | switch (context) |
23951 | { |
23952 | case pragma_external: |
23953 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
23954 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION) |
23955 | { |
23956 | int ext = disable_extension_diagnostics (); |
23957 | do |
23958 | c_parser_consume_token (parser); |
23959 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
23960 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION); |
23961 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
23962 | NULL, omp_declare_simd_clauses: &clauses); |
23963 | restore_extension_diagnostics (flags: ext); |
23964 | } |
23965 | else |
23966 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
23967 | NULL, omp_declare_simd_clauses: &clauses); |
23968 | break; |
23969 | case pragma_struct: |
23970 | case pragma_param: |
23971 | case pragma_stmt: |
23972 | error ("%<#pragma omp declare %s%> must be followed by " |
23973 | "function declaration or definition" , |
23974 | IDENTIFIER_POINTER (kind)); |
23975 | break; |
23976 | case pragma_compound: |
23977 | bool have_std_attrs; |
23978 | tree std_attrs; |
23979 | have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, n: 1); |
23980 | if (have_std_attrs) |
23981 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
23982 | else |
23983 | std_attrs = NULL_TREE; |
23984 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
23985 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION) |
23986 | { |
23987 | int ext = disable_extension_diagnostics (); |
23988 | do |
23989 | c_parser_consume_token (parser); |
23990 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
23991 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION); |
23992 | if (c_parser_next_tokens_start_declaration (parser) |
23993 | || c_parser_nth_token_starts_std_attributes (parser, n: 1)) |
23994 | { |
23995 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, |
23996 | start_attr_ok: true, NULL, omp_declare_simd_clauses: &clauses, |
23997 | have_attrs: have_std_attrs, attrs: std_attrs); |
23998 | restore_extension_diagnostics (flags: ext); |
23999 | break; |
24000 | } |
24001 | restore_extension_diagnostics (flags: ext); |
24002 | } |
24003 | else if (c_parser_next_tokens_start_declaration (parser)) |
24004 | { |
24005 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, start_attr_ok: true, |
24006 | NULL, omp_declare_simd_clauses: &clauses, have_attrs: have_std_attrs, |
24007 | attrs: std_attrs); |
24008 | break; |
24009 | } |
24010 | error ("%<#pragma omp declare %s%> must be followed by " |
24011 | "function declaration or definition" , |
24012 | IDENTIFIER_POINTER (kind)); |
24013 | break; |
24014 | default: |
24015 | gcc_unreachable (); |
24016 | } |
24017 | } |
24018 | |
24019 | static const char *const omp_construct_selectors[] = { |
24020 | "simd" , "target" , "teams" , "parallel" , "for" , NULL }; |
24021 | static const char *const omp_device_selectors[] = { |
24022 | "kind" , "isa" , "arch" , NULL }; |
24023 | static const char *const omp_implementation_selectors[] = { |
24024 | "vendor" , "extension" , "atomic_default_mem_order" , "unified_address" , |
24025 | "unified_shared_memory" , "dynamic_allocators" , "reverse_offload" , NULL }; |
24026 | static const char *const omp_user_selectors[] = { |
24027 | "condition" , NULL }; |
24028 | |
24029 | /* OpenMP 5.0: |
24030 | |
24031 | trait-selector: |
24032 | trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])] |
24033 | |
24034 | trait-score: |
24035 | score(score-expression) */ |
24036 | |
24037 | static tree |
24038 | c_parser_omp_context_selector (c_parser *parser, tree set, tree parms) |
24039 | { |
24040 | tree ret = NULL_TREE; |
24041 | do |
24042 | { |
24043 | tree selector; |
24044 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24045 | || c_parser_next_token_is (parser, type: CPP_NAME)) |
24046 | selector = c_parser_peek_token (parser)->value; |
24047 | else |
24048 | { |
24049 | c_parser_error (parser, gmsgid: "expected trait selector name" ); |
24050 | return error_mark_node; |
24051 | } |
24052 | |
24053 | tree properties = NULL_TREE; |
24054 | const char *const *selectors = NULL; |
24055 | bool allow_score = true; |
24056 | bool allow_user = false; |
24057 | int property_limit = 0; |
24058 | enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST, |
24059 | CTX_PROPERTY_ID, CTX_PROPERTY_EXPR, |
24060 | CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE; |
24061 | switch (IDENTIFIER_POINTER (set)[0]) |
24062 | { |
24063 | case 'c': /* construct */ |
24064 | selectors = omp_construct_selectors; |
24065 | allow_score = false; |
24066 | property_limit = 1; |
24067 | property_kind = CTX_PROPERTY_SIMD; |
24068 | break; |
24069 | case 'd': /* device */ |
24070 | selectors = omp_device_selectors; |
24071 | allow_score = false; |
24072 | allow_user = true; |
24073 | property_limit = 3; |
24074 | property_kind = CTX_PROPERTY_NAME_LIST; |
24075 | break; |
24076 | case 'i': /* implementation */ |
24077 | selectors = omp_implementation_selectors; |
24078 | allow_user = true; |
24079 | property_limit = 3; |
24080 | property_kind = CTX_PROPERTY_NAME_LIST; |
24081 | break; |
24082 | case 'u': /* user */ |
24083 | selectors = omp_user_selectors; |
24084 | property_limit = 1; |
24085 | property_kind = CTX_PROPERTY_EXPR; |
24086 | break; |
24087 | default: |
24088 | gcc_unreachable (); |
24089 | } |
24090 | for (int i = 0; ; i++) |
24091 | { |
24092 | if (selectors[i] == NULL) |
24093 | { |
24094 | if (allow_user) |
24095 | { |
24096 | property_kind = CTX_PROPERTY_USER; |
24097 | break; |
24098 | } |
24099 | else |
24100 | { |
24101 | error_at (c_parser_peek_token (parser)->location, |
24102 | "selector %qs not allowed for context selector " |
24103 | "set %qs" , IDENTIFIER_POINTER (selector), |
24104 | IDENTIFIER_POINTER (set)); |
24105 | c_parser_consume_token (parser); |
24106 | return error_mark_node; |
24107 | } |
24108 | } |
24109 | if (i == property_limit) |
24110 | property_kind = CTX_PROPERTY_NONE; |
24111 | if (strcmp (s1: selectors[i], IDENTIFIER_POINTER (selector)) == 0) |
24112 | break; |
24113 | } |
24114 | if (property_kind == CTX_PROPERTY_NAME_LIST |
24115 | && IDENTIFIER_POINTER (set)[0] == 'i' |
24116 | && strcmp (IDENTIFIER_POINTER (selector), |
24117 | s2: "atomic_default_mem_order" ) == 0) |
24118 | property_kind = CTX_PROPERTY_ID; |
24119 | |
24120 | c_parser_consume_token (parser); |
24121 | |
24122 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
24123 | { |
24124 | if (property_kind == CTX_PROPERTY_NONE) |
24125 | { |
24126 | error_at (c_parser_peek_token (parser)->location, |
24127 | "selector %qs does not accept any properties" , |
24128 | IDENTIFIER_POINTER (selector)); |
24129 | return error_mark_node; |
24130 | } |
24131 | |
24132 | matching_parens parens; |
24133 | parens.require_open (parser); |
24134 | |
24135 | c_token *token = c_parser_peek_token (parser); |
24136 | if (allow_score |
24137 | && c_parser_next_token_is (parser, type: CPP_NAME) |
24138 | && strcmp (IDENTIFIER_POINTER (token->value), s2: "score" ) == 0 |
24139 | && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
24140 | { |
24141 | c_parser_consume_token (parser); |
24142 | |
24143 | matching_parens parens2; |
24144 | parens2.require_open (parser); |
24145 | tree score = c_parser_expr_no_commas (parser, NULL).value; |
24146 | parens2.skip_until_found_close (parser); |
24147 | c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" ); |
24148 | if (score != error_mark_node) |
24149 | { |
24150 | mark_exp_read (score); |
24151 | score = c_fully_fold (score, false, NULL); |
24152 | if (!INTEGRAL_TYPE_P (TREE_TYPE (score)) |
24153 | || TREE_CODE (score) != INTEGER_CST) |
24154 | error_at (token->location, "score argument must be " |
24155 | "constant integer expression" ); |
24156 | else if (tree_int_cst_sgn (score) < 0) |
24157 | error_at (token->location, "score argument must be " |
24158 | "non-negative" ); |
24159 | else |
24160 | properties = tree_cons (get_identifier (" score" ), |
24161 | score, properties); |
24162 | } |
24163 | token = c_parser_peek_token (parser); |
24164 | } |
24165 | |
24166 | switch (property_kind) |
24167 | { |
24168 | tree t; |
24169 | case CTX_PROPERTY_USER: |
24170 | do |
24171 | { |
24172 | t = c_parser_expr_no_commas (parser, NULL).value; |
24173 | if (TREE_CODE (t) == STRING_CST) |
24174 | properties = tree_cons (NULL_TREE, t, properties); |
24175 | else if (t != error_mark_node) |
24176 | { |
24177 | mark_exp_read (t); |
24178 | t = c_fully_fold (t, false, NULL); |
24179 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
24180 | || !tree_fits_shwi_p (t)) |
24181 | error_at (token->location, "property must be " |
24182 | "constant integer expression or string " |
24183 | "literal" ); |
24184 | else |
24185 | properties = tree_cons (NULL_TREE, t, properties); |
24186 | } |
24187 | else |
24188 | return error_mark_node; |
24189 | |
24190 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24191 | c_parser_consume_token (parser); |
24192 | else |
24193 | break; |
24194 | } |
24195 | while (1); |
24196 | break; |
24197 | case CTX_PROPERTY_ID: |
24198 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24199 | || c_parser_next_token_is (parser, type: CPP_NAME)) |
24200 | { |
24201 | tree prop = c_parser_peek_token (parser)->value; |
24202 | c_parser_consume_token (parser); |
24203 | properties = tree_cons (prop, NULL_TREE, properties); |
24204 | } |
24205 | else |
24206 | { |
24207 | c_parser_error (parser, gmsgid: "expected identifier" ); |
24208 | return error_mark_node; |
24209 | } |
24210 | break; |
24211 | case CTX_PROPERTY_NAME_LIST: |
24212 | do |
24213 | { |
24214 | tree prop = NULL_TREE, value = NULL_TREE; |
24215 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24216 | || c_parser_next_token_is (parser, type: CPP_NAME)) |
24217 | { |
24218 | prop = c_parser_peek_token (parser)->value; |
24219 | c_parser_consume_token (parser); |
24220 | } |
24221 | else if (c_parser_next_token_is (parser, type: CPP_STRING)) |
24222 | value = c_parser_string_literal (parser, translate: false, |
24223 | wide_ok: false).value; |
24224 | else |
24225 | { |
24226 | c_parser_error (parser, gmsgid: "expected identifier or " |
24227 | "string literal" ); |
24228 | return error_mark_node; |
24229 | } |
24230 | |
24231 | properties = tree_cons (prop, value, properties); |
24232 | |
24233 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24234 | c_parser_consume_token (parser); |
24235 | else |
24236 | break; |
24237 | } |
24238 | while (1); |
24239 | break; |
24240 | case CTX_PROPERTY_EXPR: |
24241 | t = c_parser_expr_no_commas (parser, NULL).value; |
24242 | if (t != error_mark_node) |
24243 | { |
24244 | mark_exp_read (t); |
24245 | t = c_fully_fold (t, false, NULL); |
24246 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
24247 | || !tree_fits_shwi_p (t)) |
24248 | error_at (token->location, "property must be " |
24249 | "constant integer expression" ); |
24250 | else |
24251 | properties = tree_cons (NULL_TREE, t, properties); |
24252 | } |
24253 | else |
24254 | return error_mark_node; |
24255 | break; |
24256 | case CTX_PROPERTY_SIMD: |
24257 | if (parms == NULL_TREE) |
24258 | { |
24259 | error_at (token->location, "properties for %<simd%> " |
24260 | "selector may not be specified in " |
24261 | "%<metadirective%>" ); |
24262 | return error_mark_node; |
24263 | } |
24264 | tree c; |
24265 | c = c_parser_omp_all_clauses (parser, |
24266 | OMP_DECLARE_SIMD_CLAUSE_MASK, |
24267 | where: "simd" , finish_p: true, nested: 2); |
24268 | c = c_omp_declare_simd_clauses_to_numbers (parms |
24269 | == error_mark_node |
24270 | ? NULL_TREE : parms, |
24271 | c); |
24272 | properties = c; |
24273 | break; |
24274 | default: |
24275 | gcc_unreachable (); |
24276 | } |
24277 | |
24278 | parens.skip_until_found_close (parser); |
24279 | properties = nreverse (properties); |
24280 | } |
24281 | else if (property_kind == CTX_PROPERTY_NAME_LIST |
24282 | || property_kind == CTX_PROPERTY_ID |
24283 | || property_kind == CTX_PROPERTY_EXPR) |
24284 | { |
24285 | c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" ); |
24286 | return error_mark_node; |
24287 | } |
24288 | |
24289 | ret = tree_cons (selector, properties, ret); |
24290 | |
24291 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24292 | c_parser_consume_token (parser); |
24293 | else |
24294 | break; |
24295 | } |
24296 | while (1); |
24297 | |
24298 | return nreverse (ret); |
24299 | } |
24300 | |
24301 | /* OpenMP 5.0: |
24302 | |
24303 | trait-set-selector[,trait-set-selector[,...]] |
24304 | |
24305 | trait-set-selector: |
24306 | trait-set-selector-name = { trait-selector[, trait-selector[, ...]] } |
24307 | |
24308 | trait-set-selector-name: |
24309 | constructor |
24310 | device |
24311 | implementation |
24312 | user */ |
24313 | |
24314 | static tree |
24315 | c_parser_omp_context_selector_specification (c_parser *parser, tree parms) |
24316 | { |
24317 | tree ret = NULL_TREE; |
24318 | do |
24319 | { |
24320 | const char *setp = "" ; |
24321 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24322 | setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24323 | switch (setp[0]) |
24324 | { |
24325 | case 'c': |
24326 | if (strcmp (s1: setp, s2: "construct" ) == 0) |
24327 | setp = NULL; |
24328 | break; |
24329 | case 'd': |
24330 | if (strcmp (s1: setp, s2: "device" ) == 0) |
24331 | setp = NULL; |
24332 | break; |
24333 | case 'i': |
24334 | if (strcmp (s1: setp, s2: "implementation" ) == 0) |
24335 | setp = NULL; |
24336 | break; |
24337 | case 'u': |
24338 | if (strcmp (s1: setp, s2: "user" ) == 0) |
24339 | setp = NULL; |
24340 | break; |
24341 | default: |
24342 | break; |
24343 | } |
24344 | if (setp) |
24345 | { |
24346 | c_parser_error (parser, gmsgid: "expected %<construct%>, %<device%>, " |
24347 | "%<implementation%> or %<user%>" ); |
24348 | return error_mark_node; |
24349 | } |
24350 | |
24351 | tree set = c_parser_peek_token (parser)->value; |
24352 | c_parser_consume_token (parser); |
24353 | |
24354 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
24355 | return error_mark_node; |
24356 | |
24357 | matching_braces braces; |
24358 | if (!braces.require_open (parser)) |
24359 | return error_mark_node; |
24360 | |
24361 | tree selectors = c_parser_omp_context_selector (parser, set, parms); |
24362 | if (selectors == error_mark_node) |
24363 | ret = error_mark_node; |
24364 | else if (ret != error_mark_node) |
24365 | ret = tree_cons (set, selectors, ret); |
24366 | |
24367 | braces.skip_until_found_close (parser); |
24368 | |
24369 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24370 | c_parser_consume_token (parser); |
24371 | else |
24372 | break; |
24373 | } |
24374 | while (1); |
24375 | |
24376 | if (ret == error_mark_node) |
24377 | return ret; |
24378 | return nreverse (ret); |
24379 | } |
24380 | |
24381 | /* Finalize #pragma omp declare variant after FNDECL has been parsed, and put |
24382 | that into "omp declare variant base" attribute. */ |
24383 | |
24384 | static void |
24385 | c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) |
24386 | { |
24387 | matching_parens parens; |
24388 | if (!parens.require_open (parser)) |
24389 | { |
24390 | fail: |
24391 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
24392 | return; |
24393 | } |
24394 | |
24395 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
24396 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
24397 | { |
24398 | c_parser_error (parser, gmsgid: "expected identifier" ); |
24399 | goto fail; |
24400 | } |
24401 | |
24402 | c_token *token = c_parser_peek_token (parser); |
24403 | tree variant = lookup_name (token->value); |
24404 | |
24405 | if (variant == NULL_TREE) |
24406 | { |
24407 | undeclared_variable (token->location, token->value); |
24408 | variant = error_mark_node; |
24409 | } |
24410 | |
24411 | c_parser_consume_token (parser); |
24412 | |
24413 | parens.require_close (parser); |
24414 | |
24415 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
24416 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
24417 | c_parser_consume_token (parser); |
24418 | |
24419 | const char *clause = "" ; |
24420 | location_t match_loc = c_parser_peek_token (parser)->location; |
24421 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24422 | clause = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24423 | if (strcmp (s1: clause, s2: "match" )) |
24424 | { |
24425 | c_parser_error (parser, gmsgid: "expected %<match%>" ); |
24426 | goto fail; |
24427 | } |
24428 | |
24429 | c_parser_consume_token (parser); |
24430 | |
24431 | if (!parens.require_open (parser)) |
24432 | goto fail; |
24433 | |
24434 | if (parms == NULL_TREE) |
24435 | parms = error_mark_node; |
24436 | |
24437 | tree ctx = c_parser_omp_context_selector_specification (parser, parms); |
24438 | if (ctx == error_mark_node) |
24439 | goto fail; |
24440 | ctx = omp_check_context_selector (loc: match_loc, ctx); |
24441 | if (ctx != error_mark_node && variant != error_mark_node) |
24442 | { |
24443 | if (TREE_CODE (variant) != FUNCTION_DECL) |
24444 | { |
24445 | error_at (token->location, "variant %qD is not a function" , variant); |
24446 | variant = error_mark_node; |
24447 | } |
24448 | else if (omp_get_context_selector (ctx, "construct" , "simd" ) == NULL_TREE |
24449 | && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant))) |
24450 | { |
24451 | error_at (token->location, "variant %qD and base %qD have " |
24452 | "incompatible types" , variant, fndecl); |
24453 | variant = error_mark_node; |
24454 | } |
24455 | else if (fndecl_built_in_p (node: variant) |
24456 | && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), |
24457 | s2: "__builtin_" , n: strlen (s: "__builtin_" )) == 0 |
24458 | || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), |
24459 | s2: "__sync_" , n: strlen (s: "__sync_" )) == 0 |
24460 | || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), |
24461 | s2: "__atomic_" , n: strlen (s: "__atomic_" )) == 0)) |
24462 | { |
24463 | error_at (token->location, "variant %qD is a built-in" , variant); |
24464 | variant = error_mark_node; |
24465 | } |
24466 | if (variant != error_mark_node) |
24467 | { |
24468 | C_DECL_USED (variant) = 1; |
24469 | tree construct = omp_get_context_selector (ctx, "construct" , NULL); |
24470 | omp_mark_declare_variant (loc: match_loc, variant, construct); |
24471 | if (omp_context_selector_matches (ctx)) |
24472 | { |
24473 | tree attr |
24474 | = tree_cons (get_identifier ("omp declare variant base" ), |
24475 | build_tree_list (variant, ctx), |
24476 | DECL_ATTRIBUTES (fndecl)); |
24477 | DECL_ATTRIBUTES (fndecl) = attr; |
24478 | } |
24479 | } |
24480 | } |
24481 | |
24482 | parens.require_close (parser); |
24483 | c_parser_skip_to_pragma_eol (parser); |
24484 | } |
24485 | |
24486 | /* Finalize #pragma omp declare simd or #pragma omp declare variant |
24487 | clauses after FNDECL has been parsed, and put that into "omp declare simd" |
24488 | or "omp declare variant base" attribute. */ |
24489 | |
24490 | static void |
24491 | c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, |
24492 | vec<c_token> *pclauses) |
24493 | { |
24494 | vec<c_token> &clauses = *pclauses; |
24495 | |
24496 | /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there |
24497 | indicates error has been reported and CPP_PRAGMA that |
24498 | c_finish_omp_declare_simd has already processed the tokens. */ |
24499 | if (clauses.exists () && clauses[0].type == CPP_EOF) |
24500 | return; |
24501 | const char *kind = "simd" ; |
24502 | if (clauses.exists () |
24503 | && (clauses[0].type == CPP_NAME || clauses[0].type == CPP_PRAGMA)) |
24504 | kind = IDENTIFIER_POINTER (clauses[0].value); |
24505 | gcc_assert (strcmp (kind, "simd" ) == 0 || strcmp (kind, "variant" ) == 0); |
24506 | if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) |
24507 | { |
24508 | error ("%<#pragma omp declare %s%> not immediately followed by " |
24509 | "a function declaration or definition" , kind); |
24510 | clauses[0].type = CPP_EOF; |
24511 | return; |
24512 | } |
24513 | if (clauses.exists () && clauses[0].type != CPP_NAME) |
24514 | { |
24515 | error_at (DECL_SOURCE_LOCATION (fndecl), |
24516 | "%<#pragma omp declare %s%> not immediately followed by " |
24517 | "a single function declaration or definition" , kind); |
24518 | clauses[0].type = CPP_EOF; |
24519 | return; |
24520 | } |
24521 | |
24522 | if (parms == NULL_TREE) |
24523 | parms = DECL_ARGUMENTS (fndecl); |
24524 | |
24525 | unsigned int tokens_avail = parser->tokens_avail; |
24526 | gcc_assert (parser->tokens == &parser->tokens_buf[0]); |
24527 | |
24528 | parser->tokens = clauses.address (); |
24529 | parser->tokens_avail = clauses.length (); |
24530 | |
24531 | /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */ |
24532 | while (parser->tokens_avail > 3) |
24533 | { |
24534 | c_token *token = c_parser_peek_token (parser); |
24535 | gcc_assert (token->type == CPP_NAME); |
24536 | kind = IDENTIFIER_POINTER (token->value); |
24537 | c_parser_consume_token (parser); |
24538 | parser->in_pragma = true; |
24539 | |
24540 | if (strcmp (s1: kind, s2: "simd" ) == 0) |
24541 | { |
24542 | tree c; |
24543 | c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, |
24544 | where: "#pragma omp declare simd" ); |
24545 | c = c_omp_declare_simd_clauses_to_numbers (parms, c); |
24546 | if (c != NULL_TREE) |
24547 | c = tree_cons (NULL_TREE, c, NULL_TREE); |
24548 | c = build_tree_list (get_identifier ("omp declare simd" ), c); |
24549 | TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); |
24550 | DECL_ATTRIBUTES (fndecl) = c; |
24551 | } |
24552 | else |
24553 | { |
24554 | gcc_assert (strcmp (kind, "variant" ) == 0); |
24555 | c_finish_omp_declare_variant (parser, fndecl, parms); |
24556 | } |
24557 | } |
24558 | |
24559 | parser->tokens = &parser->tokens_buf[0]; |
24560 | parser->tokens_avail = tokens_avail; |
24561 | if (clauses.exists ()) |
24562 | clauses[0].type = CPP_PRAGMA; |
24563 | } |
24564 | |
24565 | /* D should be C_TOKEN_VEC from omp::decl attribute. If it contains |
24566 | a threadprivate, groupprivate, allocate or declare target directive, |
24567 | return true and parse it for DECL. */ |
24568 | |
24569 | bool |
24570 | c_maybe_parse_omp_decl (tree decl, tree d) |
24571 | { |
24572 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
24573 | vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d); |
24574 | c_token *first = toks->address (); |
24575 | c_token *last = first + toks->length (); |
24576 | const char *directive[3] = {}; |
24577 | for (int j = 0; j < 3; j++) |
24578 | { |
24579 | tree id = NULL_TREE; |
24580 | if (first + j == last) |
24581 | break; |
24582 | if (first[j].type == CPP_NAME) |
24583 | id = first[j].value; |
24584 | else if (first[j].type == CPP_KEYWORD) |
24585 | id = ridpointers[(int) first[j].keyword]; |
24586 | else |
24587 | break; |
24588 | directive[j] = IDENTIFIER_POINTER (id); |
24589 | } |
24590 | const c_omp_directive *dir = NULL; |
24591 | if (directive[0]) |
24592 | dir = c_omp_categorize_directive (directive[0], directive[1], |
24593 | directive[2]); |
24594 | if (dir == NULL) |
24595 | { |
24596 | error_at (first->location, |
24597 | "unknown OpenMP directive name in " |
24598 | "%qs attribute argument" , "omp::decl" ); |
24599 | return false; |
24600 | } |
24601 | if (dir->id != PRAGMA_OMP_THREADPRIVATE |
24602 | /* && dir->id != PRAGMA_OMP_GROUPPRIVATE */ |
24603 | && dir->id != PRAGMA_OMP_ALLOCATE |
24604 | && (dir->id != PRAGMA_OMP_DECLARE |
24605 | || strcmp (s1: directive[1], s2: "target" ) != 0)) |
24606 | return false; |
24607 | |
24608 | if (!flag_openmp && !dir->simd) |
24609 | return true; |
24610 | |
24611 | c_parser *parser = the_parser; |
24612 | unsigned int tokens_avail = parser->tokens_avail; |
24613 | gcc_assert (parser->tokens == &parser->tokens_buf[0]); |
24614 | toks = NULL; |
24615 | vec_safe_reserve (v&: toks, nelems: last - first + 2, exact: true); |
24616 | c_token tok = {}; |
24617 | tok.type = CPP_PRAGMA; |
24618 | tok.keyword = RID_MAX; |
24619 | tok.pragma_kind = pragma_kind (dir->id); |
24620 | tok.location = first->location; |
24621 | toks->quick_push (obj: tok); |
24622 | while (++first < last) |
24623 | toks->quick_push (obj: *first); |
24624 | tok = {}; |
24625 | tok.type = CPP_PRAGMA_EOL; |
24626 | tok.keyword = RID_MAX; |
24627 | tok.location = last[-1].location; |
24628 | toks->quick_push (obj: tok); |
24629 | tok = {}; |
24630 | tok.type = CPP_EOF; |
24631 | tok.keyword = RID_MAX; |
24632 | tok.location = last[-1].location; |
24633 | tok.flags = tokens_avail; |
24634 | toks->quick_push (obj: tok); |
24635 | parser->in_omp_decl_attribute = decl; |
24636 | parser->tokens = toks->address (); |
24637 | parser->tokens_avail = toks->length (); |
24638 | parser->in_omp_attribute_pragma = toks; |
24639 | c_parser_pragma (parser, context: pragma_external, NULL); |
24640 | parser->in_omp_decl_attribute = NULL_TREE; |
24641 | return true; |
24642 | } |
24643 | |
24644 | /* OpenMP 4.0: |
24645 | # pragma omp declare target new-line |
24646 | declarations and definitions |
24647 | # pragma omp end declare target new-line |
24648 | |
24649 | OpenMP 4.5: |
24650 | # pragma omp declare target ( extended-list ) new-line |
24651 | |
24652 | # pragma omp declare target declare-target-clauses[seq] new-line */ |
24653 | |
24654 | #define OMP_DECLARE_TARGET_CLAUSE_MASK \ |
24655 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ |
24656 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ENTER) \ |
24657 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \ |
24658 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE) \ |
24659 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INDIRECT)) |
24660 | |
24661 | static void |
24662 | c_parser_omp_declare_target (c_parser *parser) |
24663 | { |
24664 | tree clauses = NULL_TREE; |
24665 | int device_type = 0; |
24666 | bool indirect = false; |
24667 | bool only_device_type_or_indirect = true; |
24668 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
24669 | || (c_parser_next_token_is (parser, type: CPP_COMMA) |
24670 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME)) |
24671 | clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, |
24672 | where: "#pragma omp declare target" ); |
24673 | else if (parser->in_omp_decl_attribute |
24674 | || c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
24675 | { |
24676 | clauses = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ENTER, |
24677 | list: clauses); |
24678 | clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); |
24679 | c_parser_skip_to_pragma_eol (parser); |
24680 | } |
24681 | else |
24682 | { |
24683 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
24684 | c_parser_skip_to_pragma_eol (parser); |
24685 | c_omp_declare_target_attr attr = { .attr_syntax: attr_syntax, .device_type: -1, .indirect: 0 }; |
24686 | vec_safe_push (v&: current_omp_declare_target_attribute, obj: attr); |
24687 | return; |
24688 | } |
24689 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
24690 | { |
24691 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) |
24692 | device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c); |
24693 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_INDIRECT) |
24694 | indirect |= !integer_zerop (OMP_CLAUSE_INDIRECT_EXPR (c)); |
24695 | } |
24696 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
24697 | { |
24698 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE |
24699 | || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_INDIRECT) |
24700 | continue; |
24701 | tree t = OMP_CLAUSE_DECL (c), id; |
24702 | tree at1 = lookup_attribute (attr_name: "omp declare target" , DECL_ATTRIBUTES (t)); |
24703 | tree at2 = lookup_attribute (attr_name: "omp declare target link" , |
24704 | DECL_ATTRIBUTES (t)); |
24705 | only_device_type_or_indirect = false; |
24706 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) |
24707 | { |
24708 | id = get_identifier ("omp declare target link" ); |
24709 | std::swap (a&: at1, b&: at2); |
24710 | } |
24711 | else |
24712 | id = get_identifier ("omp declare target" ); |
24713 | if (at2) |
24714 | { |
24715 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) |
24716 | error_at (OMP_CLAUSE_LOCATION (c), |
24717 | "%qD specified both in declare target %<link%> and %qs" |
24718 | " clauses" , t, OMP_CLAUSE_ENTER_TO (c) ? "to" : "enter" ); |
24719 | else |
24720 | error_at (OMP_CLAUSE_LOCATION (c), |
24721 | "%qD specified both in declare target %<link%> and " |
24722 | "%<to%> or %<enter%> clauses" , t); |
24723 | continue; |
24724 | } |
24725 | if (!at1) |
24726 | { |
24727 | DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
24728 | if (TREE_CODE (t) != FUNCTION_DECL && !is_global_var (t)) |
24729 | continue; |
24730 | |
24731 | symtab_node *node = symtab_node::get (decl: t); |
24732 | if (node != NULL) |
24733 | { |
24734 | node->offloadable = 1; |
24735 | if (ENABLE_OFFLOADING) |
24736 | { |
24737 | g->have_offload = true; |
24738 | if (is_a <varpool_node *> (p: node)) |
24739 | vec_safe_push (v&: offload_vars, obj: t); |
24740 | } |
24741 | } |
24742 | } |
24743 | if (TREE_CODE (t) != FUNCTION_DECL) |
24744 | continue; |
24745 | if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0) |
24746 | { |
24747 | tree at3 = lookup_attribute (attr_name: "omp declare target host" , |
24748 | DECL_ATTRIBUTES (t)); |
24749 | if (at3 == NULL_TREE) |
24750 | { |
24751 | id = get_identifier ("omp declare target host" ); |
24752 | DECL_ATTRIBUTES (t) |
24753 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
24754 | } |
24755 | } |
24756 | if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0) |
24757 | { |
24758 | tree at3 = lookup_attribute (attr_name: "omp declare target nohost" , |
24759 | DECL_ATTRIBUTES (t)); |
24760 | if (at3 == NULL_TREE) |
24761 | { |
24762 | id = get_identifier ("omp declare target nohost" ); |
24763 | DECL_ATTRIBUTES (t) |
24764 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
24765 | } |
24766 | } |
24767 | if (indirect) |
24768 | { |
24769 | tree at4 = lookup_attribute (attr_name: "omp declare target indirect" , |
24770 | DECL_ATTRIBUTES (t)); |
24771 | if (at4 == NULL_TREE) |
24772 | { |
24773 | id = get_identifier ("omp declare target indirect" ); |
24774 | DECL_ATTRIBUTES (t) |
24775 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
24776 | } |
24777 | } |
24778 | } |
24779 | if ((device_type || indirect) && only_device_type_or_indirect) |
24780 | error_at (OMP_CLAUSE_LOCATION (clauses), |
24781 | "directive with only %<device_type%> or %<indirect%> clauses" ); |
24782 | if (indirect && device_type && device_type != OMP_CLAUSE_DEVICE_TYPE_ANY) |
24783 | error_at (OMP_CLAUSE_LOCATION (clauses), |
24784 | "%<device_type%> clause must specify 'any' when used with " |
24785 | "an %<indirect%> clause" ); |
24786 | } |
24787 | |
24788 | /* OpenMP 5.1 |
24789 | #pragma omp begin assumes clauses[optseq] new-line |
24790 | |
24791 | #pragma omp begin declare target clauses[optseq] new-line */ |
24792 | |
24793 | #define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK \ |
24794 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE) \ |
24795 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INDIRECT)) |
24796 | |
24797 | static void |
24798 | c_parser_omp_begin (c_parser *parser) |
24799 | { |
24800 | const char *p = "" ; |
24801 | c_parser_consume_pragma (parser); |
24802 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24803 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24804 | if (strcmp (s1: p, s2: "declare" ) == 0) |
24805 | { |
24806 | c_parser_consume_token (parser); |
24807 | p = "" ; |
24808 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24809 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24810 | if (strcmp (s1: p, s2: "target" ) == 0) |
24811 | { |
24812 | c_parser_consume_token (parser); |
24813 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
24814 | tree clauses |
24815 | = c_parser_omp_all_clauses (parser, |
24816 | OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK, |
24817 | where: "#pragma omp begin declare target" ); |
24818 | int device_type = 0; |
24819 | int indirect = 0; |
24820 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
24821 | { |
24822 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) |
24823 | device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c); |
24824 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_INDIRECT) |
24825 | indirect |= !integer_zerop (OMP_CLAUSE_INDIRECT_EXPR (c)); |
24826 | } |
24827 | c_omp_declare_target_attr attr = { .attr_syntax: attr_syntax, .device_type: device_type, |
24828 | .indirect: indirect }; |
24829 | vec_safe_push (v&: current_omp_declare_target_attribute, obj: attr); |
24830 | } |
24831 | else |
24832 | { |
24833 | c_parser_error (parser, gmsgid: "expected %<target%>" ); |
24834 | c_parser_skip_to_pragma_eol (parser); |
24835 | } |
24836 | } |
24837 | else if (strcmp (s1: p, s2: "assumes" ) == 0) |
24838 | { |
24839 | c_parser_consume_token (parser); |
24840 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
24841 | c_parser_omp_assumption_clauses (parser, false); |
24842 | struct c_omp_begin_assumes_data a = { .attr_syntax: attr_syntax }; |
24843 | vec_safe_push (v&: current_omp_begin_assumes, obj: a); |
24844 | } |
24845 | else |
24846 | { |
24847 | c_parser_error (parser, gmsgid: "expected %<declare target%> or %<assumes%>" ); |
24848 | c_parser_skip_to_pragma_eol (parser); |
24849 | } |
24850 | } |
24851 | |
24852 | /* OpenMP 4.0 |
24853 | #pragma omp end declare target |
24854 | |
24855 | OpenMP 5.1 |
24856 | #pragma omp end assumes */ |
24857 | |
24858 | static void |
24859 | c_parser_omp_end (c_parser *parser) |
24860 | { |
24861 | location_t loc = c_parser_peek_token (parser)->location; |
24862 | const char *p = "" ; |
24863 | c_parser_consume_pragma (parser); |
24864 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24865 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24866 | if (strcmp (s1: p, s2: "declare" ) == 0) |
24867 | { |
24868 | c_parser_consume_token (parser); |
24869 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
24870 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
24871 | s2: "target" ) == 0) |
24872 | c_parser_consume_token (parser); |
24873 | else |
24874 | { |
24875 | c_parser_error (parser, gmsgid: "expected %<target%>" ); |
24876 | c_parser_skip_to_pragma_eol (parser); |
24877 | return; |
24878 | } |
24879 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
24880 | c_parser_skip_to_pragma_eol (parser); |
24881 | if (!vec_safe_length (v: current_omp_declare_target_attribute)) |
24882 | error_at (loc, "%<#pragma omp end declare target%> without " |
24883 | "corresponding %<#pragma omp declare target%> or " |
24884 | "%<#pragma omp begin declare target%>" ); |
24885 | else |
24886 | { |
24887 | c_omp_declare_target_attr |
24888 | a = current_omp_declare_target_attribute->pop (); |
24889 | if (a.attr_syntax != attr_syntax) |
24890 | { |
24891 | if (a.attr_syntax) |
24892 | error_at (loc, |
24893 | "%qs in attribute syntax terminated " |
24894 | "with %qs in pragma syntax" , |
24895 | a.device_type >= 0 ? "begin declare target" |
24896 | : "declare target" , |
24897 | "end declare target" ); |
24898 | else |
24899 | error_at (loc, |
24900 | "%qs in pragma syntax terminated " |
24901 | "with %qs in attribute syntax" , |
24902 | a.device_type >= 0 ? "begin declare target" |
24903 | : "declare target" , |
24904 | "end declare target" ); |
24905 | } |
24906 | } |
24907 | } |
24908 | else if (strcmp (s1: p, s2: "assumes" ) == 0) |
24909 | { |
24910 | c_parser_consume_token (parser); |
24911 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
24912 | c_parser_skip_to_pragma_eol (parser); |
24913 | if (!vec_safe_length (v: current_omp_begin_assumes)) |
24914 | error_at (loc, "%qs without corresponding %qs" , |
24915 | "#pragma omp end assumes" , "#pragma omp begin assumes" ); |
24916 | else |
24917 | { |
24918 | c_omp_begin_assumes_data |
24919 | a = current_omp_begin_assumes->pop (); |
24920 | if (a.attr_syntax != attr_syntax) |
24921 | { |
24922 | if (a.attr_syntax) |
24923 | error_at (loc, |
24924 | "%qs in attribute syntax terminated " |
24925 | "with %qs in pragma syntax" , |
24926 | "begin assumes" , "end assumes" ); |
24927 | else |
24928 | error_at (loc, |
24929 | "%qs in pragma syntax terminated " |
24930 | "with %qs in attribute syntax" , |
24931 | "begin assumes" , "end assumes" ); |
24932 | } |
24933 | } |
24934 | } |
24935 | else |
24936 | { |
24937 | c_parser_error (parser, gmsgid: "expected %<declare%> or %<assumes%>" ); |
24938 | c_parser_skip_to_pragma_eol (parser); |
24939 | } |
24940 | } |
24941 | |
24942 | /* OpenMP 4.0 |
24943 | #pragma omp declare reduction (reduction-id : typename-list : expression) \ |
24944 | initializer-clause[opt] new-line |
24945 | |
24946 | initializer-clause: |
24947 | initializer (omp_priv = initializer) |
24948 | initializer (function-name (argument-list)) */ |
24949 | |
24950 | static void |
24951 | c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) |
24952 | { |
24953 | unsigned int tokens_avail = 0, i; |
24954 | c_token *saved_tokens = NULL; |
24955 | vec<tree> types = vNULL; |
24956 | vec<c_token> clauses = vNULL; |
24957 | enum tree_code reduc_code = ERROR_MARK; |
24958 | tree reduc_id = NULL_TREE; |
24959 | tree type; |
24960 | location_t rloc = c_parser_peek_token (parser)->location; |
24961 | |
24962 | if (context == pragma_struct || context == pragma_param) |
24963 | { |
24964 | error ("%<#pragma omp declare reduction%> not at file or block scope" ); |
24965 | goto fail; |
24966 | } |
24967 | |
24968 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
24969 | goto fail; |
24970 | |
24971 | switch (c_parser_peek_token (parser)->type) |
24972 | { |
24973 | case CPP_PLUS: |
24974 | reduc_code = PLUS_EXPR; |
24975 | break; |
24976 | case CPP_MULT: |
24977 | reduc_code = MULT_EXPR; |
24978 | break; |
24979 | case CPP_MINUS: |
24980 | reduc_code = MINUS_EXPR; |
24981 | break; |
24982 | case CPP_AND: |
24983 | reduc_code = BIT_AND_EXPR; |
24984 | break; |
24985 | case CPP_XOR: |
24986 | reduc_code = BIT_XOR_EXPR; |
24987 | break; |
24988 | case CPP_OR: |
24989 | reduc_code = BIT_IOR_EXPR; |
24990 | break; |
24991 | case CPP_AND_AND: |
24992 | reduc_code = TRUTH_ANDIF_EXPR; |
24993 | break; |
24994 | case CPP_OR_OR: |
24995 | reduc_code = TRUTH_ORIF_EXPR; |
24996 | break; |
24997 | case CPP_NAME: |
24998 | const char *p; |
24999 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25000 | if (strcmp (s1: p, s2: "min" ) == 0) |
25001 | { |
25002 | reduc_code = MIN_EXPR; |
25003 | break; |
25004 | } |
25005 | if (strcmp (s1: p, s2: "max" ) == 0) |
25006 | { |
25007 | reduc_code = MAX_EXPR; |
25008 | break; |
25009 | } |
25010 | reduc_id = c_parser_peek_token (parser)->value; |
25011 | break; |
25012 | default: |
25013 | c_parser_error (parser, |
25014 | gmsgid: "expected %<+%>, %<*%>, %<-%>, %<&%>, " |
25015 | "%<^%>, %<|%>, %<&&%>, %<||%> or identifier" ); |
25016 | goto fail; |
25017 | } |
25018 | |
25019 | tree orig_reduc_id, reduc_decl; |
25020 | orig_reduc_id = reduc_id; |
25021 | reduc_id = c_omp_reduction_id (reduc_code, reduc_id); |
25022 | reduc_decl = c_omp_reduction_decl (reduc_id); |
25023 | c_parser_consume_token (parser); |
25024 | |
25025 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
25026 | goto fail; |
25027 | |
25028 | while (true) |
25029 | { |
25030 | location_t loc = c_parser_peek_token (parser)->location; |
25031 | struct c_type_name *ctype = c_parser_type_name (parser); |
25032 | if (ctype != NULL) |
25033 | { |
25034 | type = groktypename (ctype, NULL, NULL); |
25035 | if (type == error_mark_node) |
25036 | ; |
25037 | else if ((INTEGRAL_TYPE_P (type) |
25038 | || SCALAR_FLOAT_TYPE_P (type) |
25039 | || TREE_CODE (type) == COMPLEX_TYPE) |
25040 | && orig_reduc_id == NULL_TREE) |
25041 | error_at (loc, "predeclared arithmetic type in " |
25042 | "%<#pragma omp declare reduction%>" ); |
25043 | else if (TREE_CODE (type) == FUNCTION_TYPE |
25044 | || TREE_CODE (type) == ARRAY_TYPE) |
25045 | error_at (loc, "function or array type in " |
25046 | "%<#pragma omp declare reduction%>" ); |
25047 | else if (TYPE_ATOMIC (type)) |
25048 | error_at (loc, "%<_Atomic%> qualified type in " |
25049 | "%<#pragma omp declare reduction%>" ); |
25050 | else if (TYPE_QUALS_NO_ADDR_SPACE (type)) |
25051 | error_at (loc, "const, volatile or restrict qualified type in " |
25052 | "%<#pragma omp declare reduction%>" ); |
25053 | else |
25054 | { |
25055 | tree t; |
25056 | for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t)) |
25057 | if (comptypes (TREE_PURPOSE (t), type)) |
25058 | { |
25059 | error_at (loc, "redeclaration of %qs " |
25060 | "%<#pragma omp declare reduction%> for " |
25061 | "type %qT" , |
25062 | IDENTIFIER_POINTER (reduc_id) |
25063 | + sizeof ("omp declare reduction " ) - 1, |
25064 | type); |
25065 | location_t ploc |
25066 | = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), |
25067 | 0)); |
25068 | error_at (ploc, "previous %<#pragma omp declare " |
25069 | "reduction%>" ); |
25070 | break; |
25071 | } |
25072 | if (t == NULL_TREE) |
25073 | types.safe_push (obj: type); |
25074 | } |
25075 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
25076 | c_parser_consume_token (parser); |
25077 | else |
25078 | break; |
25079 | } |
25080 | else |
25081 | break; |
25082 | } |
25083 | |
25084 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" ) |
25085 | || types.is_empty ()) |
25086 | { |
25087 | fail: |
25088 | clauses.release (); |
25089 | types.release (); |
25090 | while (true) |
25091 | { |
25092 | c_token *token = c_parser_peek_token (parser); |
25093 | if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL) |
25094 | break; |
25095 | c_parser_consume_token (parser); |
25096 | } |
25097 | c_parser_skip_to_pragma_eol (parser); |
25098 | return; |
25099 | } |
25100 | |
25101 | if (types.length () > 1) |
25102 | { |
25103 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
25104 | { |
25105 | c_token *token = c_parser_peek_token (parser); |
25106 | if (token->type == CPP_EOF) |
25107 | goto fail; |
25108 | clauses.safe_push (obj: *token); |
25109 | c_parser_consume_token (parser); |
25110 | } |
25111 | clauses.safe_push (obj: *c_parser_peek_token (parser)); |
25112 | c_parser_skip_to_pragma_eol (parser); |
25113 | |
25114 | /* Make sure nothing tries to read past the end of the tokens. */ |
25115 | c_token eof_token; |
25116 | memset (s: &eof_token, c: 0, n: sizeof (eof_token)); |
25117 | eof_token.type = CPP_EOF; |
25118 | clauses.safe_push (obj: eof_token); |
25119 | clauses.safe_push (obj: eof_token); |
25120 | } |
25121 | |
25122 | int errs = errorcount; |
25123 | FOR_EACH_VEC_ELT (types, i, type) |
25124 | { |
25125 | saved_tokens = parser->tokens; |
25126 | tokens_avail = parser->tokens_avail; |
25127 | if (!clauses.is_empty ()) |
25128 | { |
25129 | parser->tokens = clauses.address (); |
25130 | parser->tokens_avail = clauses.length (); |
25131 | parser->in_pragma = true; |
25132 | } |
25133 | |
25134 | bool nested = current_function_decl != NULL_TREE; |
25135 | if (nested) |
25136 | c_push_function_context (); |
25137 | tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, |
25138 | reduc_id, default_function_type); |
25139 | current_function_decl = fndecl; |
25140 | allocate_struct_function (fndecl, true); |
25141 | push_scope (); |
25142 | tree stmt = push_stmt_list (); |
25143 | /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't |
25144 | warn about these. */ |
25145 | tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25146 | get_identifier ("omp_out" ), type); |
25147 | DECL_ARTIFICIAL (omp_out) = 1; |
25148 | DECL_CONTEXT (omp_out) = fndecl; |
25149 | pushdecl (omp_out); |
25150 | tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25151 | get_identifier ("omp_in" ), type); |
25152 | DECL_ARTIFICIAL (omp_in) = 1; |
25153 | DECL_CONTEXT (omp_in) = fndecl; |
25154 | pushdecl (omp_in); |
25155 | struct c_expr combiner = c_parser_expression (parser); |
25156 | struct c_expr initializer; |
25157 | tree omp_priv = NULL_TREE, omp_orig = NULL_TREE; |
25158 | bool bad = false; |
25159 | initializer.set_error (); |
25160 | if (!c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
25161 | bad = true; |
25162 | else if (c_parser_next_token_is (parser, type: CPP_COMMA) |
25163 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
25164 | c_parser_consume_token (parser); |
25165 | if (!bad |
25166 | && (c_parser_next_token_is (parser, type: CPP_NAME) |
25167 | && strcmp (IDENTIFIER_POINTER |
25168 | (c_parser_peek_token (parser)->value), |
25169 | s2: "initializer" ) == 0)) |
25170 | { |
25171 | c_parser_consume_token (parser); |
25172 | pop_scope (); |
25173 | push_scope (); |
25174 | omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25175 | get_identifier ("omp_priv" ), type); |
25176 | DECL_ARTIFICIAL (omp_priv) = 1; |
25177 | DECL_INITIAL (omp_priv) = error_mark_node; |
25178 | DECL_CONTEXT (omp_priv) = fndecl; |
25179 | pushdecl (omp_priv); |
25180 | omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25181 | get_identifier ("omp_orig" ), type); |
25182 | DECL_ARTIFICIAL (omp_orig) = 1; |
25183 | DECL_CONTEXT (omp_orig) = fndecl; |
25184 | pushdecl (omp_orig); |
25185 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
25186 | bad = true; |
25187 | else if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
25188 | { |
25189 | c_parser_error (parser, gmsgid: "expected %<omp_priv%> or " |
25190 | "function-name" ); |
25191 | bad = true; |
25192 | } |
25193 | else if (strcmp (IDENTIFIER_POINTER |
25194 | (c_parser_peek_token (parser)->value), |
25195 | s2: "omp_priv" ) != 0) |
25196 | { |
25197 | if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN |
25198 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
25199 | { |
25200 | c_parser_error (parser, gmsgid: "expected function-name %<(%>" ); |
25201 | bad = true; |
25202 | } |
25203 | else |
25204 | initializer = c_parser_postfix_expression (parser); |
25205 | if (initializer.value |
25206 | && TREE_CODE (initializer.value) == CALL_EXPR) |
25207 | { |
25208 | int j; |
25209 | tree c = initializer.value; |
25210 | for (j = 0; j < call_expr_nargs (c); j++) |
25211 | { |
25212 | tree a = CALL_EXPR_ARG (c, j); |
25213 | STRIP_NOPS (a); |
25214 | if (TREE_CODE (a) == ADDR_EXPR |
25215 | && TREE_OPERAND (a, 0) == omp_priv) |
25216 | break; |
25217 | } |
25218 | if (j == call_expr_nargs (c)) |
25219 | error ("one of the initializer call arguments should be " |
25220 | "%<&omp_priv%>" ); |
25221 | } |
25222 | } |
25223 | else |
25224 | { |
25225 | c_parser_consume_token (parser); |
25226 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
25227 | bad = true; |
25228 | else |
25229 | { |
25230 | tree st = push_stmt_list (); |
25231 | location_t loc = c_parser_peek_token (parser)->location; |
25232 | rich_location richloc (line_table, loc); |
25233 | start_init (omp_priv, NULL_TREE, false, false, &richloc); |
25234 | struct c_expr init = c_parser_initializer (parser, decl: omp_priv); |
25235 | finish_init (); |
25236 | finish_decl (omp_priv, loc, init.value, |
25237 | init.original_type, NULL_TREE); |
25238 | pop_stmt_list (st); |
25239 | } |
25240 | } |
25241 | if (!bad |
25242 | && !c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
25243 | bad = true; |
25244 | } |
25245 | |
25246 | if (!bad) |
25247 | { |
25248 | c_parser_skip_to_pragma_eol (parser); |
25249 | |
25250 | tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3), |
25251 | DECL_INITIAL (reduc_decl)); |
25252 | DECL_INITIAL (reduc_decl) = t; |
25253 | DECL_SOURCE_LOCATION (omp_out) = rloc; |
25254 | TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out; |
25255 | TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in; |
25256 | TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value; |
25257 | walk_tree (&combiner.value, c_check_omp_declare_reduction_r, |
25258 | &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL); |
25259 | if (omp_priv) |
25260 | { |
25261 | DECL_SOURCE_LOCATION (omp_priv) = rloc; |
25262 | TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv; |
25263 | TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig; |
25264 | TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value; |
25265 | walk_tree (&initializer.value, c_check_omp_declare_reduction_r, |
25266 | &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); |
25267 | walk_tree (&DECL_INITIAL (omp_priv), |
25268 | c_check_omp_declare_reduction_r, |
25269 | &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); |
25270 | } |
25271 | } |
25272 | |
25273 | pop_stmt_list (stmt); |
25274 | pop_scope (); |
25275 | if (cfun->language != NULL) |
25276 | { |
25277 | ggc_free (cfun->language); |
25278 | cfun->language = NULL; |
25279 | } |
25280 | set_cfun (NULL); |
25281 | current_function_decl = NULL_TREE; |
25282 | if (nested) |
25283 | c_pop_function_context (); |
25284 | |
25285 | if (!clauses.is_empty ()) |
25286 | { |
25287 | parser->tokens = saved_tokens; |
25288 | parser->tokens_avail = tokens_avail; |
25289 | } |
25290 | if (bad) |
25291 | goto fail; |
25292 | if (errs != errorcount) |
25293 | break; |
25294 | } |
25295 | |
25296 | clauses.release (); |
25297 | types.release (); |
25298 | } |
25299 | |
25300 | |
25301 | /* OpenMP 4.0 |
25302 | #pragma omp declare simd declare-simd-clauses[optseq] new-line |
25303 | #pragma omp declare reduction (reduction-id : typename-list : expression) \ |
25304 | initializer-clause[opt] new-line |
25305 | #pragma omp declare target new-line |
25306 | |
25307 | OpenMP 5.0 |
25308 | #pragma omp declare variant (identifier) match (context-selector) */ |
25309 | |
25310 | static bool |
25311 | c_parser_omp_declare (c_parser *parser, enum pragma_context context) |
25312 | { |
25313 | c_parser_consume_pragma (parser); |
25314 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25315 | { |
25316 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25317 | if (strcmp (s1: p, s2: "simd" ) == 0) |
25318 | { |
25319 | /* c_parser_consume_token (parser); done in |
25320 | c_parser_omp_declare_simd. */ |
25321 | c_parser_omp_declare_simd (parser, context); |
25322 | return true; |
25323 | } |
25324 | if (strcmp (s1: p, s2: "reduction" ) == 0) |
25325 | { |
25326 | c_parser_consume_token (parser); |
25327 | c_parser_omp_declare_reduction (parser, context); |
25328 | return false; |
25329 | } |
25330 | if (!flag_openmp) /* flag_openmp_simd */ |
25331 | { |
25332 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25333 | return false; |
25334 | } |
25335 | if (strcmp (s1: p, s2: "target" ) == 0) |
25336 | { |
25337 | c_parser_consume_token (parser); |
25338 | c_parser_omp_declare_target (parser); |
25339 | return false; |
25340 | } |
25341 | if (strcmp (s1: p, s2: "variant" ) == 0) |
25342 | { |
25343 | /* c_parser_consume_token (parser); done in |
25344 | c_parser_omp_declare_simd. */ |
25345 | c_parser_omp_declare_simd (parser, context); |
25346 | return true; |
25347 | } |
25348 | } |
25349 | |
25350 | c_parser_error (parser, gmsgid: "expected %<simd%>, %<reduction%>, " |
25351 | "%<target%> or %<variant%>" ); |
25352 | c_parser_skip_to_pragma_eol (parser); |
25353 | return false; |
25354 | } |
25355 | |
25356 | /* OpenMP 5.0 |
25357 | #pragma omp requires clauses[optseq] new-line */ |
25358 | |
25359 | static void |
25360 | c_parser_omp_requires (c_parser *parser) |
25361 | { |
25362 | enum omp_requires new_req = (enum omp_requires) 0; |
25363 | |
25364 | c_parser_consume_pragma (parser); |
25365 | |
25366 | location_t loc = c_parser_peek_token (parser)->location; |
25367 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
25368 | { |
25369 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
25370 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
25371 | c_parser_consume_token (parser); |
25372 | |
25373 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25374 | { |
25375 | const char *p |
25376 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25377 | location_t cloc = c_parser_peek_token (parser)->location; |
25378 | enum omp_requires this_req = (enum omp_requires) 0; |
25379 | |
25380 | if (!strcmp (s1: p, s2: "unified_address" )) |
25381 | this_req = OMP_REQUIRES_UNIFIED_ADDRESS; |
25382 | else if (!strcmp (s1: p, s2: "unified_shared_memory" )) |
25383 | this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY; |
25384 | else if (!strcmp (s1: p, s2: "dynamic_allocators" )) |
25385 | this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS; |
25386 | else if (!strcmp (s1: p, s2: "reverse_offload" )) |
25387 | this_req = OMP_REQUIRES_REVERSE_OFFLOAD; |
25388 | else if (!strcmp (s1: p, s2: "atomic_default_mem_order" )) |
25389 | { |
25390 | c_parser_consume_token (parser); |
25391 | |
25392 | matching_parens parens; |
25393 | if (parens.require_open (parser)) |
25394 | { |
25395 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25396 | { |
25397 | tree v = c_parser_peek_token (parser)->value; |
25398 | p = IDENTIFIER_POINTER (v); |
25399 | |
25400 | if (!strcmp (s1: p, s2: "seq_cst" )) |
25401 | this_req |
25402 | = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST; |
25403 | else if (!strcmp (s1: p, s2: "relaxed" )) |
25404 | this_req |
25405 | = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED; |
25406 | else if (!strcmp (s1: p, s2: "acq_rel" )) |
25407 | this_req |
25408 | = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL; |
25409 | } |
25410 | if (this_req == 0) |
25411 | { |
25412 | error_at (c_parser_peek_token (parser)->location, |
25413 | "expected %<seq_cst%>, %<relaxed%> or " |
25414 | "%<acq_rel%>" ); |
25415 | switch (c_parser_peek_token (parser)->type) |
25416 | { |
25417 | case CPP_EOF: |
25418 | case CPP_PRAGMA_EOL: |
25419 | case CPP_CLOSE_PAREN: |
25420 | break; |
25421 | default: |
25422 | if (c_parser_peek_2nd_token (parser)->type |
25423 | == CPP_CLOSE_PAREN) |
25424 | c_parser_consume_token (parser); |
25425 | break; |
25426 | } |
25427 | } |
25428 | else |
25429 | c_parser_consume_token (parser); |
25430 | |
25431 | parens.skip_until_found_close (parser); |
25432 | if (this_req == 0) |
25433 | { |
25434 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25435 | return; |
25436 | } |
25437 | } |
25438 | p = NULL; |
25439 | } |
25440 | else |
25441 | { |
25442 | error_at (cloc, "expected %<unified_address%>, " |
25443 | "%<unified_shared_memory%>, " |
25444 | "%<dynamic_allocators%>, " |
25445 | "%<reverse_offload%> " |
25446 | "or %<atomic_default_mem_order%> clause" ); |
25447 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25448 | return; |
25449 | } |
25450 | if (p) |
25451 | c_parser_consume_token (parser); |
25452 | if (this_req) |
25453 | { |
25454 | if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) |
25455 | { |
25456 | if ((this_req & new_req) != 0) |
25457 | error_at (cloc, "too many %qs clauses" , p); |
25458 | if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS |
25459 | && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0) |
25460 | error_at (cloc, "%qs clause used lexically after first " |
25461 | "target construct or offloading API" , p); |
25462 | } |
25463 | else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) |
25464 | { |
25465 | error_at (cloc, "too many %qs clauses" , |
25466 | "atomic_default_mem_order" ); |
25467 | this_req = (enum omp_requires) 0; |
25468 | } |
25469 | else if ((omp_requires_mask |
25470 | & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) |
25471 | { |
25472 | error_at (cloc, "more than one %<atomic_default_mem_order%>" |
25473 | " clause in a single compilation unit" ); |
25474 | this_req |
25475 | = (enum omp_requires) |
25476 | (omp_requires_mask |
25477 | & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER); |
25478 | } |
25479 | else if ((omp_requires_mask |
25480 | & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0) |
25481 | error_at (cloc, "%<atomic_default_mem_order%> clause used " |
25482 | "lexically after first %<atomic%> construct " |
25483 | "without memory order clause" ); |
25484 | new_req = (enum omp_requires) (new_req | this_req); |
25485 | omp_requires_mask |
25486 | = (enum omp_requires) (omp_requires_mask | this_req); |
25487 | continue; |
25488 | } |
25489 | } |
25490 | break; |
25491 | } |
25492 | c_parser_skip_to_pragma_eol (parser); |
25493 | |
25494 | if (new_req == 0) |
25495 | error_at (loc, "%<pragma omp requires%> requires at least one clause" ); |
25496 | } |
25497 | |
25498 | /* Helper function for c_parser_omp_taskloop. |
25499 | Disallow zero sized or potentially zero sized task reductions. */ |
25500 | |
25501 | static tree |
25502 | c_finish_taskloop_clauses (tree clauses) |
25503 | { |
25504 | tree *pc = &clauses; |
25505 | for (tree c = clauses; c; c = *pc) |
25506 | { |
25507 | bool remove = false; |
25508 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) |
25509 | { |
25510 | tree type = strip_array_types (TREE_TYPE (OMP_CLAUSE_DECL (c))); |
25511 | if (integer_zerop (TYPE_SIZE_UNIT (type))) |
25512 | { |
25513 | error_at (OMP_CLAUSE_LOCATION (c), |
25514 | "zero sized type %qT in %<reduction%> clause" , type); |
25515 | remove = true; |
25516 | } |
25517 | else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) |
25518 | { |
25519 | error_at (OMP_CLAUSE_LOCATION (c), |
25520 | "variable sized type %qT in %<reduction%> clause" , |
25521 | type); |
25522 | remove = true; |
25523 | } |
25524 | } |
25525 | if (remove) |
25526 | *pc = OMP_CLAUSE_CHAIN (c); |
25527 | else |
25528 | pc = &OMP_CLAUSE_CHAIN (c); |
25529 | } |
25530 | return clauses; |
25531 | } |
25532 | |
25533 | /* OpenMP 4.5: |
25534 | #pragma omp taskloop taskloop-clause[optseq] new-line |
25535 | for-loop |
25536 | |
25537 | #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line |
25538 | for-loop */ |
25539 | |
25540 | #define OMP_TASKLOOP_CLAUSE_MASK \ |
25541 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
25542 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
25543 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
25544 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
25545 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
25546 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \ |
25547 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \ |
25548 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
25549 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ |
25550 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
25551 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ |
25552 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ |
25553 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ |
25554 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ |
25555 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
25556 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
25557 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) |
25558 | |
25559 | static tree |
25560 | c_parser_omp_taskloop (location_t loc, c_parser *parser, |
25561 | char *p_name, omp_clause_mask mask, tree *cclauses, |
25562 | bool *if_p) |
25563 | { |
25564 | tree clauses, block, ret; |
25565 | |
25566 | strcat (dest: p_name, src: " taskloop" ); |
25567 | mask |= OMP_TASKLOOP_CLAUSE_MASK; |
25568 | /* #pragma omp parallel master taskloop{, simd} disallow in_reduction |
25569 | clause. */ |
25570 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) |
25571 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION); |
25572 | |
25573 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25574 | { |
25575 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25576 | |
25577 | if (strcmp (s1: p, s2: "simd" ) == 0) |
25578 | { |
25579 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
25580 | if (cclauses == NULL) |
25581 | cclauses = cclauses_buf; |
25582 | c_parser_consume_token (parser); |
25583 | if (!flag_openmp) /* flag_openmp_simd */ |
25584 | return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
25585 | if_p); |
25586 | block = c_begin_compound_stmt (true); |
25587 | ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); |
25588 | block = c_end_compound_stmt (loc, block, true); |
25589 | if (ret == NULL) |
25590 | return ret; |
25591 | ret = make_node (OMP_TASKLOOP); |
25592 | TREE_TYPE (ret) = void_type_node; |
25593 | OMP_FOR_BODY (ret) = block; |
25594 | OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; |
25595 | OMP_FOR_CLAUSES (ret) |
25596 | = c_finish_taskloop_clauses (OMP_FOR_CLAUSES (ret)); |
25597 | SET_EXPR_LOCATION (ret, loc); |
25598 | add_stmt (ret); |
25599 | return ret; |
25600 | } |
25601 | } |
25602 | if (!flag_openmp) /* flag_openmp_simd */ |
25603 | { |
25604 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25605 | return NULL_TREE; |
25606 | } |
25607 | |
25608 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
25609 | if (cclauses) |
25610 | { |
25611 | omp_split_clauses (loc, code: OMP_TASKLOOP, mask, clauses, cclauses); |
25612 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; |
25613 | } |
25614 | |
25615 | clauses = c_finish_taskloop_clauses (clauses); |
25616 | block = c_begin_compound_stmt (true); |
25617 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_TASKLOOP, clauses, NULL, if_p); |
25618 | block = c_end_compound_stmt (loc, block, true); |
25619 | add_stmt (block); |
25620 | |
25621 | return ret; |
25622 | } |
25623 | |
25624 | /* OpenMP 5.1 |
25625 | #pragma omp nothing new-line */ |
25626 | |
25627 | static void |
25628 | c_parser_omp_nothing (c_parser *parser) |
25629 | { |
25630 | c_parser_consume_pragma (parser); |
25631 | c_parser_skip_to_pragma_eol (parser); |
25632 | } |
25633 | |
25634 | /* OpenMP 5.1 |
25635 | #pragma omp error clauses[optseq] new-line */ |
25636 | |
25637 | static bool |
25638 | c_parser_omp_error (c_parser *parser, enum pragma_context context) |
25639 | { |
25640 | int at_compilation = -1; |
25641 | int severity_fatal = -1; |
25642 | tree message = NULL_TREE; |
25643 | bool bad = false; |
25644 | location_t loc = c_parser_peek_token (parser)->location; |
25645 | |
25646 | c_parser_consume_pragma (parser); |
25647 | |
25648 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
25649 | { |
25650 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
25651 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
25652 | c_parser_consume_token (parser); |
25653 | |
25654 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
25655 | break; |
25656 | |
25657 | const char *p |
25658 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25659 | location_t cloc = c_parser_peek_token (parser)->location; |
25660 | static const char *args[] = { |
25661 | "execution" , "compilation" , "warning" , "fatal" |
25662 | }; |
25663 | int *v = NULL; |
25664 | int idx = 0, n = -1; |
25665 | tree m = NULL_TREE; |
25666 | |
25667 | if (!strcmp (s1: p, s2: "at" )) |
25668 | v = &at_compilation; |
25669 | else if (!strcmp (s1: p, s2: "severity" )) |
25670 | { |
25671 | v = &severity_fatal; |
25672 | idx += 2; |
25673 | } |
25674 | else if (strcmp (s1: p, s2: "message" )) |
25675 | { |
25676 | error_at (cloc, |
25677 | "expected %<at%>, %<severity%> or %<message%> clause" ); |
25678 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25679 | return false; |
25680 | } |
25681 | |
25682 | c_parser_consume_token (parser); |
25683 | |
25684 | matching_parens parens; |
25685 | if (parens.require_open (parser)) |
25686 | { |
25687 | if (v == NULL) |
25688 | { |
25689 | location_t expr_loc = c_parser_peek_token (parser)->location; |
25690 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
25691 | expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); |
25692 | m = convert (const_string_type_node, expr.value); |
25693 | m = c_fully_fold (m, false, NULL); |
25694 | } |
25695 | else |
25696 | { |
25697 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25698 | { |
25699 | tree val = c_parser_peek_token (parser)->value; |
25700 | const char *q = IDENTIFIER_POINTER (val); |
25701 | |
25702 | if (!strcmp (s1: q, s2: args[idx])) |
25703 | n = 0; |
25704 | else if (!strcmp (s1: q, s2: args[idx + 1])) |
25705 | n = 1; |
25706 | } |
25707 | if (n == -1) |
25708 | { |
25709 | error_at (c_parser_peek_token (parser)->location, |
25710 | "expected %qs or %qs" , args[idx], args[idx + 1]); |
25711 | bad = true; |
25712 | switch (c_parser_peek_token (parser)->type) |
25713 | { |
25714 | case CPP_EOF: |
25715 | case CPP_PRAGMA_EOL: |
25716 | case CPP_CLOSE_PAREN: |
25717 | break; |
25718 | default: |
25719 | if (c_parser_peek_2nd_token (parser)->type |
25720 | == CPP_CLOSE_PAREN) |
25721 | c_parser_consume_token (parser); |
25722 | break; |
25723 | } |
25724 | } |
25725 | else |
25726 | c_parser_consume_token (parser); |
25727 | } |
25728 | |
25729 | parens.skip_until_found_close (parser); |
25730 | |
25731 | if (v == NULL) |
25732 | { |
25733 | if (message) |
25734 | { |
25735 | error_at (cloc, "too many %qs clauses" , p); |
25736 | bad = true; |
25737 | } |
25738 | else |
25739 | message = m; |
25740 | } |
25741 | else if (n != -1) |
25742 | { |
25743 | if (*v != -1) |
25744 | { |
25745 | error_at (cloc, "too many %qs clauses" , p); |
25746 | bad = true; |
25747 | } |
25748 | else |
25749 | *v = n; |
25750 | } |
25751 | } |
25752 | else |
25753 | bad = true; |
25754 | } |
25755 | c_parser_skip_to_pragma_eol (parser); |
25756 | if (bad) |
25757 | return true; |
25758 | |
25759 | if (at_compilation == -1) |
25760 | at_compilation = 1; |
25761 | if (severity_fatal == -1) |
25762 | severity_fatal = 1; |
25763 | if (!at_compilation) |
25764 | { |
25765 | if (context != pragma_compound) |
25766 | { |
25767 | error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause " |
25768 | "may only be used in compound statements" ); |
25769 | return true; |
25770 | } |
25771 | tree fndecl |
25772 | = builtin_decl_explicit (fncode: severity_fatal ? BUILT_IN_GOMP_ERROR |
25773 | : BUILT_IN_GOMP_WARNING); |
25774 | if (!message) |
25775 | message = build_zero_cst (const_string_type_node); |
25776 | tree stmt = build_call_expr_loc (loc, fndecl, 2, message, |
25777 | build_all_ones_cst (size_type_node)); |
25778 | add_stmt (stmt); |
25779 | return true; |
25780 | } |
25781 | const char *msg = NULL; |
25782 | if (message) |
25783 | { |
25784 | msg = c_getstr (message); |
25785 | if (msg == NULL) |
25786 | msg = _("<message unknown at compile time>" ); |
25787 | } |
25788 | if (msg) |
25789 | emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, |
25790 | "%<pragma omp error%> encountered: %s" , msg); |
25791 | else |
25792 | emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, |
25793 | "%<pragma omp error%> encountered" ); |
25794 | return false; |
25795 | } |
25796 | |
25797 | /* Assumption clauses: |
25798 | OpenMP 5.1 |
25799 | absent (directive-name-list) |
25800 | contains (directive-name-list) |
25801 | holds (expression) |
25802 | no_openmp |
25803 | no_openmp_routines |
25804 | no_parallelism */ |
25805 | |
25806 | static void |
25807 | c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume) |
25808 | { |
25809 | bool no_openmp = false; |
25810 | bool no_openmp_routines = false; |
25811 | bool no_parallelism = false; |
25812 | bitmap_head absent_head, contains_head; |
25813 | |
25814 | bitmap_obstack_initialize (NULL); |
25815 | bitmap_initialize (head: &absent_head, obstack: &bitmap_default_obstack); |
25816 | bitmap_initialize (head: &contains_head, obstack: &bitmap_default_obstack); |
25817 | |
25818 | if (c_parser_next_token_is (parser, type: CPP_PRAGMA_EOL)) |
25819 | error_at (c_parser_peek_token (parser)->location, |
25820 | "expected at least one assumption clause" ); |
25821 | |
25822 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
25823 | { |
25824 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
25825 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
25826 | c_parser_consume_token (parser); |
25827 | |
25828 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
25829 | break; |
25830 | |
25831 | const char *p |
25832 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25833 | location_t cloc = c_parser_peek_token (parser)->location; |
25834 | |
25835 | if (!strcmp (s1: p, s2: "no_openmp" )) |
25836 | { |
25837 | c_parser_consume_token (parser); |
25838 | if (no_openmp) |
25839 | error_at (cloc, "too many %qs clauses" , "no_openmp" ); |
25840 | no_openmp = true; |
25841 | } |
25842 | else if (!strcmp (s1: p, s2: "no_openmp_routines" )) |
25843 | { |
25844 | c_parser_consume_token (parser); |
25845 | if (no_openmp_routines) |
25846 | error_at (cloc, "too many %qs clauses" , "no_openmp_routines" ); |
25847 | no_openmp_routines = true; |
25848 | } |
25849 | else if (!strcmp (s1: p, s2: "no_parallelism" )) |
25850 | { |
25851 | c_parser_consume_token (parser); |
25852 | if (no_parallelism) |
25853 | error_at (cloc, "too many %qs clauses" , "no_parallelism" ); |
25854 | no_parallelism = true; |
25855 | } |
25856 | else if (!strcmp (s1: p, s2: "holds" )) |
25857 | { |
25858 | c_parser_consume_token (parser); |
25859 | matching_parens parens; |
25860 | if (parens.require_open (parser)) |
25861 | { |
25862 | location_t eloc = c_parser_peek_token (parser)->location; |
25863 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
25864 | tree t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; |
25865 | t = c_objc_common_truthvalue_conversion (eloc, t); |
25866 | t = c_fully_fold (t, false, NULL); |
25867 | if (is_assume && t != error_mark_node) |
25868 | { |
25869 | tree fn = build_call_expr_internal_loc (eloc, IFN_ASSUME, |
25870 | void_type_node, 1, |
25871 | t); |
25872 | add_stmt (fn); |
25873 | } |
25874 | parens.skip_until_found_close (parser); |
25875 | } |
25876 | } |
25877 | else if (!strcmp (s1: p, s2: "absent" ) || !strcmp (s1: p, s2: "contains" )) |
25878 | { |
25879 | c_parser_consume_token (parser); |
25880 | matching_parens parens; |
25881 | if (parens.require_open (parser)) |
25882 | { |
25883 | do |
25884 | { |
25885 | const char *directive[3] = {}; |
25886 | int i; |
25887 | location_t dloc = c_parser_peek_token (parser)->location; |
25888 | for (i = 0; i < 3; i++) |
25889 | { |
25890 | tree id; |
25891 | if (c_parser_peek_nth_token (parser, n: i + 1)->type |
25892 | == CPP_NAME) |
25893 | id = c_parser_peek_nth_token (parser, n: i + 1)->value; |
25894 | else if (c_parser_peek_nth_token (parser, n: i + 1)->keyword |
25895 | != RID_MAX) |
25896 | { |
25897 | enum rid rid |
25898 | = c_parser_peek_nth_token (parser, n: i + 1)->keyword; |
25899 | id = ridpointers[rid]; |
25900 | } |
25901 | else |
25902 | break; |
25903 | directive[i] = IDENTIFIER_POINTER (id); |
25904 | } |
25905 | if (i == 0) |
25906 | error_at (dloc, "expected directive name" ); |
25907 | else |
25908 | { |
25909 | const struct c_omp_directive *dir |
25910 | = c_omp_categorize_directive (directive[0], |
25911 | directive[1], |
25912 | directive[2]); |
25913 | if (dir == NULL |
25914 | || dir->kind == C_OMP_DIR_DECLARATIVE |
25915 | || dir->kind == C_OMP_DIR_INFORMATIONAL |
25916 | || dir->id == PRAGMA_OMP_END |
25917 | || (!dir->second && directive[1]) |
25918 | || (!dir->third && directive[2])) |
25919 | error_at (dloc, "unknown OpenMP directive name in " |
25920 | "%qs clause argument" , p); |
25921 | else |
25922 | { |
25923 | int id = dir - c_omp_directives; |
25924 | if (bitmap_bit_p (p[0] == 'a' ? &contains_head |
25925 | : &absent_head, id)) |
25926 | error_at (dloc, "%<%s%s%s%s%s%> directive " |
25927 | "mentioned in both %<absent%> and " |
25928 | "%<contains%> clauses" , |
25929 | directive[0], |
25930 | directive[1] ? " " : "" , |
25931 | directive[1] ? directive[1] : "" , |
25932 | directive[2] ? " " : "" , |
25933 | directive[2] ? directive[2] : "" ); |
25934 | else if (!bitmap_set_bit (p[0] == 'a' |
25935 | ? &absent_head |
25936 | : &contains_head, id)) |
25937 | error_at (dloc, "%<%s%s%s%s%s%> directive " |
25938 | "mentioned multiple times in %qs " |
25939 | "clauses" , |
25940 | directive[0], |
25941 | directive[1] ? " " : "" , |
25942 | directive[1] ? directive[1] : "" , |
25943 | directive[2] ? " " : "" , |
25944 | directive[2] ? directive[2] : "" , p); |
25945 | } |
25946 | for (; i; --i) |
25947 | c_parser_consume_token (parser); |
25948 | } |
25949 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
25950 | c_parser_consume_token (parser); |
25951 | else |
25952 | break; |
25953 | } |
25954 | while (1); |
25955 | parens.skip_until_found_close (parser); |
25956 | } |
25957 | } |
25958 | else if (startswith (str: p, prefix: "ext_" )) |
25959 | { |
25960 | warning_at (cloc, 0, "unknown assumption clause %qs" , p); |
25961 | c_parser_consume_token (parser); |
25962 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
25963 | { |
25964 | matching_parens parens; |
25965 | parens.consume_open (parser); |
25966 | c_parser_balanced_token_sequence (parser); |
25967 | parens.require_close (parser); |
25968 | } |
25969 | } |
25970 | else |
25971 | { |
25972 | c_parser_consume_token (parser); |
25973 | error_at (cloc, "expected assumption clause" ); |
25974 | break; |
25975 | } |
25976 | } |
25977 | c_parser_skip_to_pragma_eol (parser); |
25978 | } |
25979 | |
25980 | /* OpenMP 5.1 |
25981 | #pragma omp assume clauses[optseq] new-line */ |
25982 | |
25983 | static void |
25984 | c_parser_omp_assume (c_parser *parser, bool *if_p) |
25985 | { |
25986 | c_parser_omp_assumption_clauses (parser, is_assume: true); |
25987 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
25988 | } |
25989 | |
25990 | /* OpenMP 5.1 |
25991 | #pragma omp assumes clauses[optseq] new-line */ |
25992 | |
25993 | static void |
25994 | c_parser_omp_assumes (c_parser *parser) |
25995 | { |
25996 | c_parser_consume_pragma (parser); |
25997 | c_parser_omp_assumption_clauses (parser, is_assume: false); |
25998 | } |
25999 | |
26000 | /* Main entry point to parsing most OpenMP pragmas. */ |
26001 | |
26002 | static void |
26003 | c_parser_omp_construct (c_parser *parser, bool *if_p) |
26004 | { |
26005 | enum pragma_kind p_kind; |
26006 | location_t loc; |
26007 | tree stmt; |
26008 | char p_name[sizeof "#pragma omp teams distribute parallel for simd" ]; |
26009 | omp_clause_mask mask (0); |
26010 | |
26011 | loc = c_parser_peek_token (parser)->location; |
26012 | p_kind = c_parser_peek_token (parser)->pragma_kind; |
26013 | c_parser_consume_pragma (parser); |
26014 | |
26015 | switch (p_kind) |
26016 | { |
26017 | case PRAGMA_OACC_ATOMIC: |
26018 | c_parser_omp_atomic (loc, parser, openacc: true); |
26019 | return; |
26020 | case PRAGMA_OACC_CACHE: |
26021 | strcpy (dest: p_name, src: "#pragma acc" ); |
26022 | stmt = c_parser_oacc_cache (loc, parser); |
26023 | break; |
26024 | case PRAGMA_OACC_DATA: |
26025 | stmt = c_parser_oacc_data (loc, parser, if_p); |
26026 | break; |
26027 | case PRAGMA_OACC_HOST_DATA: |
26028 | stmt = c_parser_oacc_host_data (loc, parser, if_p); |
26029 | break; |
26030 | case PRAGMA_OACC_KERNELS: |
26031 | case PRAGMA_OACC_PARALLEL: |
26032 | case PRAGMA_OACC_SERIAL: |
26033 | strcpy (dest: p_name, src: "#pragma acc" ); |
26034 | stmt = c_parser_oacc_compute (loc, parser, p_kind, p_name, if_p); |
26035 | break; |
26036 | case PRAGMA_OACC_LOOP: |
26037 | strcpy (dest: p_name, src: "#pragma acc" ); |
26038 | stmt = c_parser_oacc_loop (loc, parser, p_name, mask, NULL, if_p); |
26039 | break; |
26040 | case PRAGMA_OACC_WAIT: |
26041 | strcpy (dest: p_name, src: "#pragma wait" ); |
26042 | stmt = c_parser_oacc_wait (loc, parser, p_name); |
26043 | break; |
26044 | case PRAGMA_OMP_ATOMIC: |
26045 | c_parser_omp_atomic (loc, parser, openacc: false); |
26046 | return; |
26047 | case PRAGMA_OMP_CRITICAL: |
26048 | stmt = c_parser_omp_critical (loc, parser, if_p); |
26049 | break; |
26050 | case PRAGMA_OMP_DISTRIBUTE: |
26051 | strcpy (dest: p_name, src: "#pragma omp" ); |
26052 | stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL, if_p); |
26053 | break; |
26054 | case PRAGMA_OMP_FOR: |
26055 | strcpy (dest: p_name, src: "#pragma omp" ); |
26056 | stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL, if_p); |
26057 | break; |
26058 | case PRAGMA_OMP_LOOP: |
26059 | strcpy (dest: p_name, src: "#pragma omp" ); |
26060 | stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); |
26061 | break; |
26062 | case PRAGMA_OMP_MASKED: |
26063 | strcpy (dest: p_name, src: "#pragma omp" ); |
26064 | stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); |
26065 | break; |
26066 | case PRAGMA_OMP_MASTER: |
26067 | strcpy (dest: p_name, src: "#pragma omp" ); |
26068 | stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); |
26069 | break; |
26070 | case PRAGMA_OMP_PARALLEL: |
26071 | strcpy (dest: p_name, src: "#pragma omp" ); |
26072 | stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); |
26073 | break; |
26074 | case PRAGMA_OMP_SCOPE: |
26075 | stmt = c_parser_omp_scope (loc, parser, if_p); |
26076 | break; |
26077 | case PRAGMA_OMP_SECTIONS: |
26078 | strcpy (dest: p_name, src: "#pragma omp" ); |
26079 | stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); |
26080 | break; |
26081 | case PRAGMA_OMP_SIMD: |
26082 | strcpy (dest: p_name, src: "#pragma omp" ); |
26083 | stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL, if_p); |
26084 | break; |
26085 | case PRAGMA_OMP_SINGLE: |
26086 | stmt = c_parser_omp_single (loc, parser, if_p); |
26087 | break; |
26088 | case PRAGMA_OMP_TASK: |
26089 | stmt = c_parser_omp_task (loc, parser, if_p); |
26090 | break; |
26091 | case PRAGMA_OMP_TASKGROUP: |
26092 | stmt = c_parser_omp_taskgroup (loc, parser, if_p); |
26093 | break; |
26094 | case PRAGMA_OMP_TASKLOOP: |
26095 | strcpy (dest: p_name, src: "#pragma omp" ); |
26096 | stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL, if_p); |
26097 | break; |
26098 | case PRAGMA_OMP_TEAMS: |
26099 | strcpy (dest: p_name, src: "#pragma omp" ); |
26100 | stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p); |
26101 | break; |
26102 | case PRAGMA_OMP_ASSUME: |
26103 | c_parser_omp_assume (parser, if_p); |
26104 | return; |
26105 | default: |
26106 | gcc_unreachable (); |
26107 | } |
26108 | |
26109 | if (stmt && stmt != error_mark_node) |
26110 | gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); |
26111 | } |
26112 | |
26113 | |
26114 | /* OpenMP 2.5: |
26115 | # pragma omp threadprivate (variable-list) */ |
26116 | |
26117 | static void |
26118 | c_parser_omp_threadprivate (c_parser *parser) |
26119 | { |
26120 | tree vars, t; |
26121 | location_t loc; |
26122 | |
26123 | c_parser_consume_pragma (parser); |
26124 | loc = c_parser_peek_token (parser)->location; |
26125 | vars = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ERROR, NULL); |
26126 | |
26127 | /* Mark every variable in VARS to be assigned thread local storage. */ |
26128 | for (t = vars; t; t = TREE_CHAIN (t)) |
26129 | { |
26130 | tree v = TREE_PURPOSE (t); |
26131 | |
26132 | /* FIXME diagnostics: Ideally we should keep individual |
26133 | locations for all the variables in the var list to make the |
26134 | following errors more precise. Perhaps |
26135 | c_parser_omp_var_list_parens() should construct a list of |
26136 | locations to go along with the var list. */ |
26137 | |
26138 | /* If V had already been marked threadprivate, it doesn't matter |
26139 | whether it had been used prior to this point. */ |
26140 | if (!VAR_P (v)) |
26141 | error_at (loc, "%qD is not a variable" , v); |
26142 | else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) |
26143 | error_at (loc, "%qE declared %<threadprivate%> after first use" , v); |
26144 | else if (! is_global_var (t: v)) |
26145 | error_at (loc, "automatic variable %qE cannot be %<threadprivate%>" , v); |
26146 | else if (TREE_TYPE (v) == error_mark_node) |
26147 | ; |
26148 | else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) |
26149 | error_at (loc, "%<threadprivate%> %qE has incomplete type" , v); |
26150 | else |
26151 | { |
26152 | if (! DECL_THREAD_LOCAL_P (v)) |
26153 | { |
26154 | set_decl_tls_model (v, decl_default_tls_model (v)); |
26155 | /* If rtl has been already set for this var, call |
26156 | make_decl_rtl once again, so that encode_section_info |
26157 | has a chance to look at the new decl flags. */ |
26158 | if (DECL_RTL_SET_P (v)) |
26159 | make_decl_rtl (v); |
26160 | } |
26161 | C_DECL_THREADPRIVATE_P (v) = 1; |
26162 | } |
26163 | } |
26164 | |
26165 | c_parser_skip_to_pragma_eol (parser); |
26166 | } |
26167 | |
26168 | /* Parse a transaction attribute (GCC Extension). |
26169 | |
26170 | transaction-attribute: |
26171 | gnu-attributes |
26172 | attribute-specifier |
26173 | */ |
26174 | |
26175 | static tree |
26176 | c_parser_transaction_attributes (c_parser *parser) |
26177 | { |
26178 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
26179 | return c_parser_gnu_attributes (parser); |
26180 | |
26181 | if (!c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE)) |
26182 | return NULL_TREE; |
26183 | return c_parser_std_attribute_specifier (parser, for_tm: true); |
26184 | } |
26185 | |
26186 | /* Parse a __transaction_atomic or __transaction_relaxed statement |
26187 | (GCC Extension). |
26188 | |
26189 | transaction-statement: |
26190 | __transaction_atomic transaction-attribute[opt] compound-statement |
26191 | __transaction_relaxed compound-statement |
26192 | |
26193 | Note that the only valid attribute is: "outer". |
26194 | */ |
26195 | |
26196 | static tree |
26197 | c_parser_transaction (c_parser *parser, enum rid keyword) |
26198 | { |
26199 | unsigned int old_in = parser->in_transaction; |
26200 | unsigned int this_in = 1, new_in; |
26201 | location_t loc = c_parser_peek_token (parser)->location; |
26202 | tree stmt, attrs; |
26203 | |
26204 | gcc_assert ((keyword == RID_TRANSACTION_ATOMIC |
26205 | || keyword == RID_TRANSACTION_RELAXED) |
26206 | && c_parser_next_token_is_keyword (parser, keyword)); |
26207 | c_parser_consume_token (parser); |
26208 | |
26209 | if (keyword == RID_TRANSACTION_RELAXED) |
26210 | this_in |= TM_STMT_ATTR_RELAXED; |
26211 | else |
26212 | { |
26213 | attrs = c_parser_transaction_attributes (parser); |
26214 | if (attrs) |
26215 | this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); |
26216 | } |
26217 | |
26218 | /* Keep track if we're in the lexical scope of an outer transaction. */ |
26219 | new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); |
26220 | |
26221 | parser->in_transaction = new_in; |
26222 | stmt = c_parser_compound_statement (parser); |
26223 | parser->in_transaction = old_in; |
26224 | |
26225 | if (flag_tm) |
26226 | stmt = c_finish_transaction (loc, stmt, this_in); |
26227 | else |
26228 | error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? |
26229 | "%<__transaction_atomic%> without transactional memory support enabled" |
26230 | : "%<__transaction_relaxed %> " |
26231 | "without transactional memory support enabled" )); |
26232 | |
26233 | return stmt; |
26234 | } |
26235 | |
26236 | /* Parse a __transaction_atomic or __transaction_relaxed expression |
26237 | (GCC Extension). |
26238 | |
26239 | transaction-expression: |
26240 | __transaction_atomic ( expression ) |
26241 | __transaction_relaxed ( expression ) |
26242 | */ |
26243 | |
26244 | static struct c_expr |
26245 | c_parser_transaction_expression (c_parser *parser, enum rid keyword) |
26246 | { |
26247 | struct c_expr ret; |
26248 | unsigned int old_in = parser->in_transaction; |
26249 | unsigned int this_in = 1; |
26250 | location_t loc = c_parser_peek_token (parser)->location; |
26251 | tree attrs; |
26252 | |
26253 | gcc_assert ((keyword == RID_TRANSACTION_ATOMIC |
26254 | || keyword == RID_TRANSACTION_RELAXED) |
26255 | && c_parser_next_token_is_keyword (parser, keyword)); |
26256 | c_parser_consume_token (parser); |
26257 | |
26258 | if (keyword == RID_TRANSACTION_RELAXED) |
26259 | this_in |= TM_STMT_ATTR_RELAXED; |
26260 | else |
26261 | { |
26262 | attrs = c_parser_transaction_attributes (parser); |
26263 | if (attrs) |
26264 | this_in |= parse_tm_stmt_attr (attrs, 0); |
26265 | } |
26266 | |
26267 | parser->in_transaction = this_in; |
26268 | matching_parens parens; |
26269 | if (parens.require_open (parser)) |
26270 | { |
26271 | tree expr = c_parser_expression (parser).value; |
26272 | ret.original_type = TREE_TYPE (expr); |
26273 | ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); |
26274 | if (this_in & TM_STMT_ATTR_RELAXED) |
26275 | TRANSACTION_EXPR_RELAXED (ret.value) = 1; |
26276 | SET_EXPR_LOCATION (ret.value, loc); |
26277 | ret.original_code = TRANSACTION_EXPR; |
26278 | ret.m_decimal = 0; |
26279 | if (!parens.require_close (parser)) |
26280 | { |
26281 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
26282 | goto error; |
26283 | } |
26284 | } |
26285 | else |
26286 | { |
26287 | error: |
26288 | ret.set_error (); |
26289 | ret.original_code = ERROR_MARK; |
26290 | ret.original_type = NULL; |
26291 | } |
26292 | parser->in_transaction = old_in; |
26293 | |
26294 | if (!flag_tm) |
26295 | error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? |
26296 | "%<__transaction_atomic%> without transactional memory support enabled" |
26297 | : "%<__transaction_relaxed %> " |
26298 | "without transactional memory support enabled" )); |
26299 | |
26300 | set_c_expr_source_range (expr: &ret, start: loc, finish: loc); |
26301 | |
26302 | return ret; |
26303 | } |
26304 | |
26305 | /* Parse a __transaction_cancel statement (GCC Extension). |
26306 | |
26307 | transaction-cancel-statement: |
26308 | __transaction_cancel transaction-attribute[opt] ; |
26309 | |
26310 | Note that the only valid attribute is "outer". |
26311 | */ |
26312 | |
26313 | static tree |
26314 | c_parser_transaction_cancel (c_parser *parser) |
26315 | { |
26316 | location_t loc = c_parser_peek_token (parser)->location; |
26317 | tree attrs; |
26318 | bool is_outer = false; |
26319 | |
26320 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL)); |
26321 | c_parser_consume_token (parser); |
26322 | |
26323 | attrs = c_parser_transaction_attributes (parser); |
26324 | if (attrs) |
26325 | is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); |
26326 | |
26327 | if (!flag_tm) |
26328 | { |
26329 | error_at (loc, "%<__transaction_cancel%> without " |
26330 | "transactional memory support enabled" ); |
26331 | goto ret_error; |
26332 | } |
26333 | else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) |
26334 | { |
26335 | error_at (loc, "%<__transaction_cancel%> within a " |
26336 | "%<__transaction_relaxed%>" ); |
26337 | goto ret_error; |
26338 | } |
26339 | else if (is_outer) |
26340 | { |
26341 | if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 |
26342 | && !is_tm_may_cancel_outer (current_function_decl)) |
26343 | { |
26344 | error_at (loc, "outer %<__transaction_cancel%> not " |
26345 | "within outer %<__transaction_atomic%> or " |
26346 | "a %<transaction_may_cancel_outer%> function" ); |
26347 | goto ret_error; |
26348 | } |
26349 | } |
26350 | else if (parser->in_transaction == 0) |
26351 | { |
26352 | error_at (loc, "%<__transaction_cancel%> not within " |
26353 | "%<__transaction_atomic%>" ); |
26354 | goto ret_error; |
26355 | } |
26356 | |
26357 | return add_stmt (build_tm_abort_call (loc, is_outer)); |
26358 | |
26359 | ret_error: |
26360 | return build1 (NOP_EXPR, void_type_node, error_mark_node); |
26361 | } |
26362 | |
26363 | /* Parse a single source file. */ |
26364 | |
26365 | void |
26366 | c_parse_file (void) |
26367 | { |
26368 | /* Use local storage to begin. If the first token is a pragma, parse it. |
26369 | If it is #pragma GCC pch_preprocess, then this will load a PCH file |
26370 | which will cause garbage collection. */ |
26371 | c_parser tparser; |
26372 | |
26373 | memset (s: &tparser, c: 0, n: sizeof tparser); |
26374 | tparser.translate_strings_p = true; |
26375 | tparser.tokens = &tparser.tokens_buf[0]; |
26376 | the_parser = &tparser; |
26377 | |
26378 | if (c_parser_peek_token (parser: &tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) |
26379 | c_parser_pragma_pch_preprocess (parser: &tparser); |
26380 | else |
26381 | c_common_no_more_pch (); |
26382 | |
26383 | the_parser = ggc_alloc<c_parser> (); |
26384 | *the_parser = tparser; |
26385 | if (tparser.tokens == &tparser.tokens_buf[0]) |
26386 | the_parser->tokens = &the_parser->tokens_buf[0]; |
26387 | |
26388 | /* Initialize EH, if we've been told to do so. */ |
26389 | if (flag_exceptions) |
26390 | using_eh_for_cleanups (); |
26391 | |
26392 | c_parser_translation_unit (parser: the_parser); |
26393 | the_parser = NULL; |
26394 | } |
26395 | |
26396 | void |
26397 | c_init_preprocess (void) |
26398 | { |
26399 | /* Create a parser for use by pragma_lex during preprocessing. */ |
26400 | the_parser = ggc_alloc<c_parser> (); |
26401 | memset (s: the_parser, c: 0, n: sizeof (c_parser)); |
26402 | the_parser->tokens = &the_parser->tokens_buf[0]; |
26403 | } |
26404 | |
26405 | /* Parse the body of a function declaration marked with "__RTL". |
26406 | |
26407 | The RTL parser works on the level of characters read from a |
26408 | FILE *, whereas c_parser works at the level of tokens. |
26409 | Square this circle by consuming all of the tokens up to and |
26410 | including the closing brace, recording the start/end of the RTL |
26411 | fragment, and reopening the file and re-reading the relevant |
26412 | lines within the RTL parser. |
26413 | |
26414 | This requires the opening and closing braces of the C function |
26415 | to be on separate lines from the RTL they wrap. |
26416 | |
26417 | Take ownership of START_WITH_PASS, if non-NULL. */ |
26418 | |
26419 | location_t |
26420 | c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) |
26421 | { |
26422 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
26423 | { |
26424 | free (ptr: start_with_pass); |
26425 | return c_parser_peek_token (parser)->location; |
26426 | } |
26427 | |
26428 | location_t start_loc = c_parser_peek_token (parser)->location; |
26429 | |
26430 | /* Consume all tokens, up to the closing brace, handling |
26431 | matching pairs of braces in the rtl dump. */ |
26432 | int num_open_braces = 1; |
26433 | while (1) |
26434 | { |
26435 | switch (c_parser_peek_token (parser)->type) |
26436 | { |
26437 | case CPP_OPEN_BRACE: |
26438 | num_open_braces++; |
26439 | break; |
26440 | case CPP_CLOSE_BRACE: |
26441 | if (--num_open_braces == 0) |
26442 | goto found_closing_brace; |
26443 | break; |
26444 | case CPP_EOF: |
26445 | error_at (start_loc, "no closing brace" ); |
26446 | free (ptr: start_with_pass); |
26447 | return c_parser_peek_token (parser)->location; |
26448 | default: |
26449 | break; |
26450 | } |
26451 | c_parser_consume_token (parser); |
26452 | } |
26453 | |
26454 | found_closing_brace: |
26455 | /* At the closing brace; record its location. */ |
26456 | location_t end_loc = c_parser_peek_token (parser)->location; |
26457 | |
26458 | /* Consume the closing brace. */ |
26459 | c_parser_consume_token (parser); |
26460 | |
26461 | /* Invoke the RTL parser. */ |
26462 | if (!read_rtl_function_body_from_file_range (start_loc, end_loc)) |
26463 | { |
26464 | free (ptr: start_with_pass); |
26465 | return end_loc; |
26466 | } |
26467 | |
26468 | /* Run the backend on the cfun created above, transferring ownership of |
26469 | START_WITH_PASS. */ |
26470 | run_rtl_passes (initial_pass_name: start_with_pass); |
26471 | return end_loc; |
26472 | } |
26473 | |
26474 | #include "gt-c-c-parser.h" |
26475 | |