1 | /* Parser for C and Objective-C. |
2 | Copyright (C) 1987-2024 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 | bool potential_nesting_p = false; |
3671 | tree std_attrs = NULL_TREE; |
3672 | tree attrs; |
3673 | tree ident = NULL_TREE; |
3674 | tree fixed_underlying_type = NULL_TREE; |
3675 | location_t enum_loc; |
3676 | location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
3677 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); |
3678 | c_parser_consume_token (parser); |
3679 | have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); |
3680 | if (have_std_attrs) |
3681 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3682 | attrs = c_parser_gnu_attributes (parser); |
3683 | enum_loc = c_parser_peek_token (parser)->location; |
3684 | /* Set the location in case we create a decl now. */ |
3685 | c_parser_set_source_position_from_token (token: c_parser_peek_token (parser)); |
3686 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
3687 | { |
3688 | ident = c_parser_peek_token (parser)->value; |
3689 | ident_loc = c_parser_peek_token (parser)->location; |
3690 | enum_loc = ident_loc; |
3691 | c_parser_consume_token (parser); |
3692 | } |
3693 | if (c_parser_next_token_is (parser, type: CPP_COLON) |
3694 | /* Distinguish an enum-type-specifier from a bit-field |
3695 | declaration of the form "enum e : constant-expression;". */ |
3696 | && c_token_starts_typename (token: c_parser_peek_2nd_token (parser))) |
3697 | { |
3698 | pedwarn_c11 (enum_loc, opt: OPT_Wpedantic, |
3699 | "ISO C does not support specifying %<enum%> underlying " |
3700 | "types before C23" ); |
3701 | if (ident) |
3702 | { |
3703 | /* The tag is in scope during the enum-type-specifier (which |
3704 | may refer to the tag inside typeof). */ |
3705 | ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, |
3706 | have_std_attrs, std_attrs, true); |
3707 | if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)) |
3708 | error_at (enum_loc, "%<enum%> declared both with and without " |
3709 | "fixed underlying type" ); |
3710 | potential_nesting_p = NULL_TREE == TYPE_VALUES (ret.spec); |
3711 | } |
3712 | else |
3713 | { |
3714 | /* There must be an enum definition, so this initialization |
3715 | (to avoid possible warnings about uninitialized data) |
3716 | will be replaced later (either with the results of that |
3717 | definition, or with the results of error handling for the |
3718 | case of no tag and no definition). */ |
3719 | ret.spec = NULL_TREE; |
3720 | ret.kind = ctsk_tagdef; |
3721 | ret.expr = NULL_TREE; |
3722 | ret.expr_const_operands = true; |
3723 | ret.has_enum_type_specifier = true; |
3724 | } |
3725 | c_parser_consume_token (parser); |
3726 | struct c_declspecs *specs = build_null_declspecs (); |
3727 | c_parser_declspecs (parser, specs, scspec_ok: false, typespec_ok: true, start_attr_ok: false, alignspec_ok: false, auto_type_ok: false, |
3728 | start_std_attr_ok: false, end_std_attr_ok: true, la: cla_prefer_id); |
3729 | finish_declspecs (specs); |
3730 | if (specs->default_int_p) |
3731 | error_at (enum_loc, "no %<enum%> underlying type specified" ); |
3732 | else if (TREE_CODE (specs->type) != INTEGER_TYPE |
3733 | && TREE_CODE (specs->type) != BOOLEAN_TYPE) |
3734 | { |
3735 | error_at (enum_loc, "invalid %<enum%> underlying type" ); |
3736 | specs->type = integer_type_node; |
3737 | } |
3738 | else if (specs->restrict_p) |
3739 | error_at (enum_loc, "invalid use of %<restrict%>" ); |
3740 | fixed_underlying_type = TYPE_MAIN_VARIANT (specs->type); |
3741 | if (ident) |
3742 | { |
3743 | /* The type specified must be consistent with any previously |
3744 | specified underlying type. If this is a newly declared |
3745 | type, it is now a complete type. */ |
3746 | if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) |
3747 | && ENUM_UNDERLYING_TYPE (ret.spec) == NULL_TREE) |
3748 | { |
3749 | TYPE_MIN_VALUE (ret.spec) = |
3750 | TYPE_MIN_VALUE (fixed_underlying_type); |
3751 | TYPE_MAX_VALUE (ret.spec) = |
3752 | TYPE_MAX_VALUE (fixed_underlying_type); |
3753 | TYPE_UNSIGNED (ret.spec) = TYPE_UNSIGNED (fixed_underlying_type); |
3754 | SET_TYPE_ALIGN (ret.spec, TYPE_ALIGN (fixed_underlying_type)); |
3755 | TYPE_SIZE (ret.spec) = NULL_TREE; |
3756 | TYPE_PRECISION (ret.spec) = |
3757 | TYPE_PRECISION (fixed_underlying_type); |
3758 | ENUM_UNDERLYING_TYPE (ret.spec) = fixed_underlying_type; |
3759 | layout_type (ret.spec); |
3760 | } |
3761 | else if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) |
3762 | && !comptypes (fixed_underlying_type, |
3763 | ENUM_UNDERLYING_TYPE (ret.spec))) |
3764 | { |
3765 | error_at (enum_loc, "%<enum%> underlying type incompatible with " |
3766 | "previous declaration" ); |
3767 | fixed_underlying_type = ENUM_UNDERLYING_TYPE (ret.spec); |
3768 | } |
3769 | } |
3770 | } |
3771 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
3772 | { |
3773 | /* Parse an enum definition. */ |
3774 | struct c_enum_contents the_enum; |
3775 | tree type; |
3776 | tree postfix_attrs; |
3777 | /* We chain the enumerators in reverse order, then put them in |
3778 | forward order at the end. */ |
3779 | tree values; |
3780 | timevar_push (tv: TV_PARSE_ENUM); |
3781 | type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type, |
3782 | potential_nesting_p); |
3783 | values = NULL_TREE; |
3784 | c_parser_consume_token (parser); |
3785 | while (true) |
3786 | { |
3787 | tree enum_id; |
3788 | tree enum_value; |
3789 | tree enum_decl; |
3790 | bool seen_comma; |
3791 | c_token *token; |
3792 | location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
3793 | location_t decl_loc, value_loc; |
3794 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
3795 | { |
3796 | /* Give a nicer error for "enum {}". */ |
3797 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE) |
3798 | && !parser->error) |
3799 | { |
3800 | error_at (c_parser_peek_token (parser)->location, |
3801 | "empty enum is invalid" ); |
3802 | parser->error = true; |
3803 | } |
3804 | else |
3805 | c_parser_error (parser, gmsgid: "expected identifier" ); |
3806 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
3807 | values = error_mark_node; |
3808 | break; |
3809 | } |
3810 | token = c_parser_peek_token (parser); |
3811 | enum_id = token->value; |
3812 | /* Set the location in case we create a decl now. */ |
3813 | c_parser_set_source_position_from_token (token); |
3814 | decl_loc = value_loc = token->location; |
3815 | c_parser_consume_token (parser); |
3816 | /* Parse any specified attributes. */ |
3817 | tree std_attrs = NULL_TREE; |
3818 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
3819 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3820 | tree enum_attrs = chainon (std_attrs, |
3821 | c_parser_gnu_attributes (parser)); |
3822 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
3823 | { |
3824 | c_parser_consume_token (parser); |
3825 | value_loc = c_parser_peek_token (parser)->location; |
3826 | enum_value = convert_lvalue_to_rvalue (value_loc, |
3827 | (c_parser_expr_no_commas |
3828 | (parser, NULL)), |
3829 | true, true).value; |
3830 | } |
3831 | else |
3832 | enum_value = NULL_TREE; |
3833 | enum_decl = build_enumerator (decl_loc, value_loc, |
3834 | &the_enum, enum_id, enum_value); |
3835 | if (enum_attrs) |
3836 | decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0); |
3837 | TREE_CHAIN (enum_decl) = values; |
3838 | values = enum_decl; |
3839 | seen_comma = false; |
3840 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
3841 | { |
3842 | comma_loc = c_parser_peek_token (parser)->location; |
3843 | seen_comma = true; |
3844 | c_parser_consume_token (parser); |
3845 | } |
3846 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
3847 | { |
3848 | if (seen_comma) |
3849 | pedwarn_c90 (comma_loc, opt: OPT_Wpedantic, |
3850 | "comma at end of enumerator list" ); |
3851 | c_parser_consume_token (parser); |
3852 | break; |
3853 | } |
3854 | if (!seen_comma) |
3855 | { |
3856 | c_parser_error (parser, gmsgid: "expected %<,%> or %<}%>" ); |
3857 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
3858 | values = error_mark_node; |
3859 | break; |
3860 | } |
3861 | } |
3862 | postfix_attrs = c_parser_gnu_attributes (parser); |
3863 | ret.spec = finish_enum (type, nreverse (values), |
3864 | chainon (std_attrs, |
3865 | chainon (attrs, postfix_attrs))); |
3866 | ret.kind = ctsk_tagdef; |
3867 | ret.expr = NULL_TREE; |
3868 | ret.expr_const_operands = true; |
3869 | ret.has_enum_type_specifier = fixed_underlying_type != NULL_TREE; |
3870 | timevar_pop (tv: TV_PARSE_ENUM); |
3871 | return ret; |
3872 | } |
3873 | else if (!ident) |
3874 | { |
3875 | c_parser_error (parser, gmsgid: "expected %<{%>" ); |
3876 | ret.spec = error_mark_node; |
3877 | ret.kind = ctsk_tagref; |
3878 | ret.expr = NULL_TREE; |
3879 | ret.expr_const_operands = true; |
3880 | ret.has_enum_type_specifier = false; |
3881 | return ret; |
3882 | } |
3883 | /* Attributes may only appear when the members are defined or in |
3884 | certain forward declarations (treat enum forward declarations in |
3885 | GNU C analogously to struct and union forward declarations in |
3886 | standard C). */ |
3887 | if (have_std_attrs && c_parser_next_token_is_not (parser, type: CPP_SEMICOLON)) |
3888 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
3889 | if (fixed_underlying_type == NULL_TREE) |
3890 | { |
3891 | ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, |
3892 | std_attrs, false); |
3893 | /* In ISO C, enumerated types without a fixed underlying type |
3894 | can be referred to only if already defined. */ |
3895 | if (pedantic && !COMPLETE_TYPE_P (ret.spec)) |
3896 | { |
3897 | gcc_assert (ident); |
3898 | pedwarn (enum_loc, OPT_Wpedantic, |
3899 | "ISO C forbids forward references to %<enum%> types" ); |
3900 | } |
3901 | } |
3902 | return ret; |
3903 | } |
3904 | |
3905 | /* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1). |
3906 | |
3907 | struct-or-union-specifier: |
3908 | struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] |
3909 | identifier[opt] { struct-contents } gnu-attributes[opt] |
3910 | struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt] |
3911 | identifier |
3912 | |
3913 | struct-contents: |
3914 | struct-declaration-list |
3915 | |
3916 | struct-declaration-list: |
3917 | struct-declaration ; |
3918 | struct-declaration-list struct-declaration ; |
3919 | |
3920 | GNU extensions: |
3921 | |
3922 | struct-contents: |
3923 | empty |
3924 | struct-declaration |
3925 | struct-declaration-list struct-declaration |
3926 | |
3927 | struct-declaration-list: |
3928 | struct-declaration-list ; |
3929 | ; |
3930 | |
3931 | (Note that in the syntax here, unlike that in ISO C, the semicolons |
3932 | are included here rather than in struct-declaration, in order to |
3933 | describe the syntax with extra semicolons and missing semicolon at |
3934 | end.) |
3935 | |
3936 | Objective-C: |
3937 | |
3938 | struct-declaration-list: |
3939 | @defs ( class-name ) |
3940 | |
3941 | (Note this does not include a trailing semicolon, but can be |
3942 | followed by further declarations, and gets a pedwarn-if-pedantic |
3943 | when followed by a semicolon.) */ |
3944 | |
3945 | static struct c_typespec |
3946 | c_parser_struct_or_union_specifier (c_parser *parser) |
3947 | { |
3948 | struct c_typespec ret; |
3949 | bool have_std_attrs; |
3950 | tree std_attrs = NULL_TREE; |
3951 | tree attrs; |
3952 | tree ident = NULL_TREE; |
3953 | location_t struct_loc; |
3954 | location_t ident_loc = UNKNOWN_LOCATION; |
3955 | enum tree_code code; |
3956 | switch (c_parser_peek_token (parser)->keyword) |
3957 | { |
3958 | case RID_STRUCT: |
3959 | code = RECORD_TYPE; |
3960 | break; |
3961 | case RID_UNION: |
3962 | code = UNION_TYPE; |
3963 | break; |
3964 | default: |
3965 | gcc_unreachable (); |
3966 | } |
3967 | struct_loc = c_parser_peek_token (parser)->location; |
3968 | c_parser_consume_token (parser); |
3969 | have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); |
3970 | if (have_std_attrs) |
3971 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
3972 | attrs = c_parser_gnu_attributes (parser); |
3973 | |
3974 | /* Set the location in case we create a decl now. */ |
3975 | c_parser_set_source_position_from_token (token: c_parser_peek_token (parser)); |
3976 | |
3977 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
3978 | { |
3979 | ident = c_parser_peek_token (parser)->value; |
3980 | ident_loc = c_parser_peek_token (parser)->location; |
3981 | struct_loc = ident_loc; |
3982 | c_parser_consume_token (parser); |
3983 | } |
3984 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
3985 | { |
3986 | /* Parse a struct or union definition. Start the scope of the |
3987 | tag before parsing components. */ |
3988 | class c_struct_parse_info *struct_info; |
3989 | tree type = start_struct (struct_loc, code, ident, &struct_info); |
3990 | tree postfix_attrs; |
3991 | /* We chain the components in reverse order, then put them in |
3992 | forward order at the end. Each struct-declaration may |
3993 | declare multiple components (comma-separated), so we must use |
3994 | chainon to join them, although when parsing each |
3995 | struct-declaration we can use TREE_CHAIN directly. |
3996 | |
3997 | The theory behind all this is that there will be more |
3998 | semicolon separated fields than comma separated fields, and |
3999 | so we'll be minimizing the number of node traversals required |
4000 | by chainon. */ |
4001 | tree contents; |
4002 | tree expr = NULL; |
4003 | timevar_push (tv: TV_PARSE_STRUCT); |
4004 | contents = NULL_TREE; |
4005 | c_parser_consume_token (parser); |
4006 | /* Handle the Objective-C @defs construct, |
4007 | e.g. foo(sizeof(struct{ @defs(ClassName) }));. */ |
4008 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_DEFS)) |
4009 | { |
4010 | tree name; |
4011 | gcc_assert (c_dialect_objc ()); |
4012 | c_parser_consume_token (parser); |
4013 | matching_parens parens; |
4014 | if (!parens.require_open (parser)) |
4015 | goto end_at_defs; |
4016 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
4017 | && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME) |
4018 | { |
4019 | name = c_parser_peek_token (parser)->value; |
4020 | c_parser_consume_token (parser); |
4021 | } |
4022 | else |
4023 | { |
4024 | c_parser_error (parser, gmsgid: "expected class name" ); |
4025 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
4026 | goto end_at_defs; |
4027 | } |
4028 | parens.skip_until_found_close (parser); |
4029 | contents = nreverse (objc_get_class_ivars (name)); |
4030 | } |
4031 | end_at_defs: |
4032 | /* Parse the struct-declarations and semicolons. Problems with |
4033 | semicolons are diagnosed here; empty structures are diagnosed |
4034 | elsewhere. */ |
4035 | while (true) |
4036 | { |
4037 | tree decls; |
4038 | /* Parse any stray semicolon. */ |
4039 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
4040 | { |
4041 | location_t semicolon_loc |
4042 | = c_parser_peek_token (parser)->location; |
4043 | gcc_rich_location richloc (semicolon_loc); |
4044 | richloc.add_fixit_remove (); |
4045 | pedwarn (&richloc, OPT_Wpedantic, |
4046 | "extra semicolon in struct or union specified" ); |
4047 | c_parser_consume_token (parser); |
4048 | continue; |
4049 | } |
4050 | /* Stop if at the end of the struct or union contents. */ |
4051 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4052 | { |
4053 | c_parser_consume_token (parser); |
4054 | break; |
4055 | } |
4056 | /* Accept #pragmas at struct scope. */ |
4057 | if (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
4058 | { |
4059 | c_parser_pragma (parser, pragma_struct, NULL); |
4060 | continue; |
4061 | } |
4062 | /* Parse some comma-separated declarations, but not the |
4063 | trailing semicolon if any. */ |
4064 | decls = c_parser_struct_declaration (parser, &expr); |
4065 | contents = chainon (decls, contents); |
4066 | /* If no semicolon follows, either we have a parse error or |
4067 | are at the end of the struct or union and should |
4068 | pedwarn. */ |
4069 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
4070 | c_parser_consume_token (parser); |
4071 | else |
4072 | { |
4073 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4074 | pedwarn (c_parser_peek_token (parser)->location, 0, |
4075 | "no semicolon at end of struct or union" ); |
4076 | else if (parser->error |
4077 | || !c_parser_next_token_starts_declspecs (parser)) |
4078 | { |
4079 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
4080 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
4081 | break; |
4082 | } |
4083 | |
4084 | /* If we come here, we have already emitted an error |
4085 | for an expected `;', identifier or `(', and we also |
4086 | recovered already. Go on with the next field. */ |
4087 | } |
4088 | } |
4089 | postfix_attrs = c_parser_gnu_attributes (parser); |
4090 | ret.spec = finish_struct (struct_loc, type, nreverse (contents), |
4091 | chainon (std_attrs, |
4092 | chainon (attrs, postfix_attrs)), |
4093 | struct_info, expr: &expr); |
4094 | ret.kind = ctsk_tagdef; |
4095 | ret.expr = expr; |
4096 | ret.expr_const_operands = true; |
4097 | ret.has_enum_type_specifier = false; |
4098 | timevar_pop (tv: TV_PARSE_STRUCT); |
4099 | return ret; |
4100 | } |
4101 | else if (!ident) |
4102 | { |
4103 | c_parser_error (parser, gmsgid: "expected %<{%>" ); |
4104 | ret.spec = error_mark_node; |
4105 | ret.kind = ctsk_tagref; |
4106 | ret.expr = NULL_TREE; |
4107 | ret.expr_const_operands = true; |
4108 | ret.has_enum_type_specifier = false; |
4109 | return ret; |
4110 | } |
4111 | /* Attributes may only appear when the members are defined or in |
4112 | certain forward declarations. */ |
4113 | if (have_std_attrs && c_parser_next_token_is_not (parser, type: CPP_SEMICOLON)) |
4114 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
4115 | /* ??? Existing practice is that GNU attributes are ignored after |
4116 | the struct or union keyword when not defining the members. */ |
4117 | ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs, |
4118 | false); |
4119 | return ret; |
4120 | } |
4121 | |
4122 | /* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1), |
4123 | *without* the trailing semicolon. |
4124 | |
4125 | struct-declaration: |
4126 | attribute-specifier-sequence[opt] specifier-qualifier-list |
4127 | attribute-specifier-sequence[opt] struct-declarator-list |
4128 | static_assert-declaration-no-semi |
4129 | |
4130 | specifier-qualifier-list: |
4131 | type-specifier specifier-qualifier-list[opt] |
4132 | type-qualifier specifier-qualifier-list[opt] |
4133 | alignment-specifier specifier-qualifier-list[opt] |
4134 | gnu-attributes specifier-qualifier-list[opt] |
4135 | |
4136 | struct-declarator-list: |
4137 | struct-declarator |
4138 | struct-declarator-list , gnu-attributes[opt] struct-declarator |
4139 | |
4140 | struct-declarator: |
4141 | declarator gnu-attributes[opt] |
4142 | declarator[opt] : constant-expression gnu-attributes[opt] |
4143 | |
4144 | GNU extensions: |
4145 | |
4146 | struct-declaration: |
4147 | __extension__ struct-declaration |
4148 | specifier-qualifier-list |
4149 | |
4150 | Unlike the ISO C syntax, semicolons are handled elsewhere. The use |
4151 | of gnu-attributes where shown is a GNU extension. In GNU C, we accept |
4152 | any expression without commas in the syntax (assignment |
4153 | expressions, not just conditional expressions); assignment |
4154 | expressions will be diagnosed as non-constant. */ |
4155 | |
4156 | static tree |
4157 | c_parser_struct_declaration (c_parser *parser, tree *expr) |
4158 | { |
4159 | struct c_declspecs *specs; |
4160 | tree prefix_attrs; |
4161 | tree all_prefix_attrs; |
4162 | tree decls; |
4163 | location_t decl_loc; |
4164 | if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
4165 | { |
4166 | int ext; |
4167 | tree decl; |
4168 | ext = disable_extension_diagnostics (); |
4169 | c_parser_consume_token (parser); |
4170 | decl = c_parser_struct_declaration (parser, expr); |
4171 | restore_extension_diagnostics (flags: ext); |
4172 | return decl; |
4173 | } |
4174 | if (c_parser_next_token_is_keyword (parser, keyword: RID_STATIC_ASSERT)) |
4175 | { |
4176 | c_parser_static_assert_declaration_no_semi (parser); |
4177 | return NULL_TREE; |
4178 | } |
4179 | specs = build_null_declspecs (); |
4180 | decl_loc = c_parser_peek_token (parser)->location; |
4181 | /* Strictly by the standard, we shouldn't allow _Alignas here, |
4182 | but it appears to have been intended to allow it there, so |
4183 | we're keeping it as it is until WG14 reaches a conclusion |
4184 | of N1731. |
4185 | <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf> */ |
4186 | c_parser_declspecs (parser, specs, scspec_ok: false, typespec_ok: true, start_attr_ok: true, |
4187 | alignspec_ok: true, auto_type_ok: false, start_std_attr_ok: true, end_std_attr_ok: true, la: cla_nonabstract_decl); |
4188 | if (parser->error) |
4189 | return NULL_TREE; |
4190 | if (!specs->declspecs_seen_p) |
4191 | { |
4192 | c_parser_error (parser, gmsgid: "expected specifier-qualifier-list" ); |
4193 | return NULL_TREE; |
4194 | } |
4195 | finish_declspecs (specs); |
4196 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
4197 | || c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4198 | { |
4199 | tree ret; |
4200 | if (specs->typespec_kind == ctsk_none) |
4201 | { |
4202 | pedwarn (decl_loc, OPT_Wpedantic, |
4203 | "ISO C forbids member declarations with no members" ); |
4204 | shadow_tag_warned (specs, pedantic); |
4205 | ret = NULL_TREE; |
4206 | } |
4207 | else |
4208 | { |
4209 | /* Support for unnamed structs or unions as members of |
4210 | structs or unions (which is [a] useful and [b] supports |
4211 | MS P-SDK). */ |
4212 | tree attrs = NULL; |
4213 | |
4214 | ret = grokfield (c_parser_peek_token (parser)->location, |
4215 | build_id_declarator (NULL_TREE), specs, |
4216 | NULL_TREE, &attrs, expr); |
4217 | if (ret) |
4218 | decl_attributes (&ret, attrs, 0); |
4219 | } |
4220 | return ret; |
4221 | } |
4222 | |
4223 | /* Provide better error recovery. Note that a type name here is valid, |
4224 | and will be treated as a field name. */ |
4225 | if (specs->typespec_kind == ctsk_tagdef |
4226 | && TREE_CODE (specs->type) != ENUMERAL_TYPE |
4227 | && c_parser_next_token_starts_declspecs (parser) |
4228 | && !c_parser_next_token_is (parser, type: CPP_NAME)) |
4229 | { |
4230 | c_parser_error (parser, gmsgid: "expected %<;%>, identifier or %<(%>" ); |
4231 | parser->error = false; |
4232 | return NULL_TREE; |
4233 | } |
4234 | |
4235 | pending_xref_error (); |
4236 | prefix_attrs = specs->attrs; |
4237 | all_prefix_attrs = prefix_attrs; |
4238 | specs->attrs = NULL_TREE; |
4239 | decls = NULL_TREE; |
4240 | while (true) |
4241 | { |
4242 | /* Declaring one or more declarators or un-named bit-fields. */ |
4243 | struct c_declarator *declarator; |
4244 | bool dummy = false; |
4245 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
4246 | declarator = build_id_declarator (NULL_TREE); |
4247 | else |
4248 | declarator = c_parser_declarator (parser, |
4249 | type_seen_p: specs->typespec_kind != ctsk_none, |
4250 | kind: C_DTR_NORMAL, seen_id: &dummy); |
4251 | if (declarator == NULL) |
4252 | { |
4253 | c_parser_skip_to_end_of_block_or_statement (parser); |
4254 | break; |
4255 | } |
4256 | if (c_parser_next_token_is (parser, type: CPP_COLON) |
4257 | || c_parser_next_token_is (parser, type: CPP_COMMA) |
4258 | || c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
4259 | || c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE) |
4260 | || c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
4261 | { |
4262 | tree postfix_attrs = NULL_TREE; |
4263 | tree width = NULL_TREE; |
4264 | tree d; |
4265 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
4266 | { |
4267 | c_parser_consume_token (parser); |
4268 | location_t loc = c_parser_peek_token (parser)->location; |
4269 | width = convert_lvalue_to_rvalue (loc, |
4270 | (c_parser_expr_no_commas |
4271 | (parser, NULL)), |
4272 | true, true).value; |
4273 | } |
4274 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
4275 | postfix_attrs = c_parser_gnu_attributes (parser); |
4276 | d = grokfield (c_parser_peek_token (parser)->location, |
4277 | declarator, specs, width, &all_prefix_attrs, expr); |
4278 | decl_attributes (&d, chainon (postfix_attrs, |
4279 | all_prefix_attrs), 0); |
4280 | DECL_CHAIN (d) = decls; |
4281 | decls = d; |
4282 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
4283 | all_prefix_attrs = chainon (c_parser_gnu_attributes (parser), |
4284 | prefix_attrs); |
4285 | else |
4286 | all_prefix_attrs = prefix_attrs; |
4287 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
4288 | c_parser_consume_token (parser); |
4289 | else if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
4290 | || c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
4291 | { |
4292 | /* Semicolon consumed in caller. */ |
4293 | break; |
4294 | } |
4295 | else |
4296 | { |
4297 | c_parser_error (parser, gmsgid: "expected %<,%>, %<;%> or %<}%>" ); |
4298 | break; |
4299 | } |
4300 | } |
4301 | else |
4302 | { |
4303 | c_parser_error (parser, |
4304 | gmsgid: "expected %<:%>, %<,%>, %<;%>, %<}%> or " |
4305 | "%<__attribute__%>" ); |
4306 | break; |
4307 | } |
4308 | } |
4309 | return decls; |
4310 | } |
4311 | |
4312 | /* Parse a typeof specifier (a GNU extension adopted in C23). |
4313 | |
4314 | typeof-specifier: |
4315 | typeof ( expression ) |
4316 | typeof ( type-name ) |
4317 | typeof_unqual ( expression ) |
4318 | typeof_unqual ( type-name ) |
4319 | */ |
4320 | |
4321 | static struct c_typespec |
4322 | c_parser_typeof_specifier (c_parser *parser) |
4323 | { |
4324 | bool is_unqual; |
4325 | bool is_std; |
4326 | struct c_typespec ret; |
4327 | ret.kind = ctsk_typeof; |
4328 | ret.spec = error_mark_node; |
4329 | ret.expr = NULL_TREE; |
4330 | ret.expr_const_operands = true; |
4331 | ret.has_enum_type_specifier = false; |
4332 | if (c_parser_next_token_is_keyword (parser, keyword: RID_TYPEOF)) |
4333 | { |
4334 | is_unqual = false; |
4335 | tree spelling = c_parser_peek_token (parser)->value; |
4336 | is_std = (flag_isoc23 |
4337 | && strcmp (IDENTIFIER_POINTER (spelling), s2: "typeof" ) == 0); |
4338 | } |
4339 | else |
4340 | { |
4341 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL)); |
4342 | is_unqual = true; |
4343 | tree spelling = c_parser_peek_token (parser)->value; |
4344 | is_std = strcmp (IDENTIFIER_POINTER (spelling), s2: "typeof_unqual" ) == 0; |
4345 | } |
4346 | c_parser_consume_token (parser); |
4347 | c_inhibit_evaluation_warnings++; |
4348 | in_typeof++; |
4349 | matching_parens parens; |
4350 | if (!parens.require_open (parser)) |
4351 | { |
4352 | c_inhibit_evaluation_warnings--; |
4353 | in_typeof--; |
4354 | return ret; |
4355 | } |
4356 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
4357 | { |
4358 | struct c_type_name *type = c_parser_type_name (parser); |
4359 | c_inhibit_evaluation_warnings--; |
4360 | in_typeof--; |
4361 | if (type != NULL) |
4362 | { |
4363 | ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); |
4364 | pop_maybe_used (c_type_variably_modified_p (t: ret.spec)); |
4365 | } |
4366 | } |
4367 | else |
4368 | { |
4369 | bool was_vm; |
4370 | location_t here = c_parser_peek_token (parser)->location; |
4371 | struct c_expr expr = c_parser_expression (parser); |
4372 | c_inhibit_evaluation_warnings--; |
4373 | in_typeof--; |
4374 | if (TREE_CODE (expr.value) == COMPONENT_REF |
4375 | && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) |
4376 | error_at (here, "%<typeof%> applied to a bit-field" ); |
4377 | mark_exp_read (expr.value); |
4378 | ret.spec = TREE_TYPE (expr.value); |
4379 | was_vm = c_type_variably_modified_p (t: ret.spec); |
4380 | /* This is returned with the type so that when the type is |
4381 | evaluated, this can be evaluated. */ |
4382 | if (was_vm) |
4383 | ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands); |
4384 | pop_maybe_used (was_vm); |
4385 | } |
4386 | parens.skip_until_found_close (parser); |
4387 | if (ret.spec != error_mark_node) |
4388 | { |
4389 | if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED) |
4390 | ret.spec = TYPE_MAIN_VARIANT (ret.spec); |
4391 | if (is_std) |
4392 | { |
4393 | /* In ISO C terms, _Noreturn is not part of the type of |
4394 | expressions such as &abort, but in GCC it is represented |
4395 | internally as a type qualifier. */ |
4396 | if (TREE_CODE (ret.spec) == FUNCTION_TYPE |
4397 | && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED) |
4398 | ret.spec = TYPE_MAIN_VARIANT (ret.spec); |
4399 | else if (FUNCTION_POINTER_TYPE_P (ret.spec) |
4400 | && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED) |
4401 | ret.spec |
4402 | = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec))); |
4403 | } |
4404 | } |
4405 | return ret; |
4406 | } |
4407 | |
4408 | /* Parse an alignment-specifier. |
4409 | |
4410 | C11 6.7.5: |
4411 | |
4412 | alignment-specifier: |
4413 | _Alignas ( type-name ) |
4414 | _Alignas ( constant-expression ) |
4415 | */ |
4416 | |
4417 | static tree |
4418 | c_parser_alignas_specifier (c_parser * parser) |
4419 | { |
4420 | tree ret = error_mark_node; |
4421 | location_t loc = c_parser_peek_token (parser)->location; |
4422 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS)); |
4423 | tree spelling = c_parser_peek_token (parser)->value; |
4424 | c_parser_consume_token (parser); |
4425 | if (flag_isoc99) |
4426 | pedwarn_c99 (loc, opt: OPT_Wpedantic, |
4427 | "ISO C99 does not support %qE" , spelling); |
4428 | else |
4429 | pedwarn_c99 (loc, opt: OPT_Wpedantic, |
4430 | "ISO C90 does not support %qE" , spelling); |
4431 | matching_parens parens; |
4432 | if (!parens.require_open (parser)) |
4433 | return ret; |
4434 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
4435 | { |
4436 | struct c_type_name *type = c_parser_type_name (parser); |
4437 | if (type != NULL) |
4438 | ret = c_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL), |
4439 | false, true, 1); |
4440 | } |
4441 | else |
4442 | ret = convert_lvalue_to_rvalue (loc, |
4443 | c_parser_expr_no_commas (parser, NULL), |
4444 | true, true).value; |
4445 | parens.skip_until_found_close (parser); |
4446 | return ret; |
4447 | } |
4448 | |
4449 | /* Parse a declarator, possibly an abstract declarator (C90 6.5.4, |
4450 | 6.5.5, C99 6.7.5, 6.7.6, C11 6.7.6, 6.7.7). If TYPE_SEEN_P then |
4451 | a typedef name may be redeclared; otherwise it may not. KIND |
4452 | indicates which kind of declarator is wanted. Returns a valid |
4453 | declarator except in the case of a syntax error in which case NULL is |
4454 | returned. *SEEN_ID is set to true if an identifier being declared is |
4455 | seen; this is used to diagnose bad forms of abstract array declarators |
4456 | and to determine whether an identifier list is syntactically permitted. |
4457 | |
4458 | declarator: |
4459 | pointer[opt] direct-declarator |
4460 | |
4461 | direct-declarator: |
4462 | identifier |
4463 | ( gnu-attributes[opt] declarator ) |
4464 | direct-declarator array-declarator |
4465 | direct-declarator ( parameter-type-list ) |
4466 | direct-declarator ( identifier-list[opt] ) |
4467 | |
4468 | pointer: |
4469 | * type-qualifier-list[opt] |
4470 | * type-qualifier-list[opt] pointer |
4471 | |
4472 | type-qualifier-list: |
4473 | type-qualifier |
4474 | gnu-attributes |
4475 | type-qualifier-list type-qualifier |
4476 | type-qualifier-list gnu-attributes |
4477 | |
4478 | array-declarator: |
4479 | [ type-qualifier-list[opt] assignment-expression[opt] ] |
4480 | [ static type-qualifier-list[opt] assignment-expression ] |
4481 | [ type-qualifier-list static assignment-expression ] |
4482 | [ type-qualifier-list[opt] * ] |
4483 | |
4484 | parameter-type-list: |
4485 | parameter-list |
4486 | parameter-list , ... |
4487 | |
4488 | parameter-list: |
4489 | parameter-declaration |
4490 | parameter-list , parameter-declaration |
4491 | |
4492 | parameter-declaration: |
4493 | declaration-specifiers declarator gnu-attributes[opt] |
4494 | declaration-specifiers abstract-declarator[opt] gnu-attributes[opt] |
4495 | |
4496 | identifier-list: |
4497 | identifier |
4498 | identifier-list , identifier |
4499 | |
4500 | abstract-declarator: |
4501 | pointer |
4502 | pointer[opt] direct-abstract-declarator |
4503 | |
4504 | direct-abstract-declarator: |
4505 | ( gnu-attributes[opt] abstract-declarator ) |
4506 | direct-abstract-declarator[opt] array-declarator |
4507 | direct-abstract-declarator[opt] ( parameter-type-list[opt] ) |
4508 | |
4509 | GNU extensions: |
4510 | |
4511 | direct-declarator: |
4512 | direct-declarator ( parameter-forward-declarations |
4513 | parameter-type-list[opt] ) |
4514 | |
4515 | direct-abstract-declarator: |
4516 | direct-abstract-declarator[opt] ( parameter-forward-declarations |
4517 | parameter-type-list[opt] ) |
4518 | |
4519 | parameter-forward-declarations: |
4520 | parameter-list ; |
4521 | parameter-forward-declarations parameter-list ; |
4522 | |
4523 | The uses of gnu-attributes shown above are GNU extensions. |
4524 | |
4525 | Some forms of array declarator are not included in C99 in the |
4526 | syntax for abstract declarators; these are disallowed elsewhere. |
4527 | This may be a defect (DR#289). |
4528 | |
4529 | This function also accepts an omitted abstract declarator as being |
4530 | an abstract declarator, although not part of the formal syntax. */ |
4531 | |
4532 | struct c_declarator * |
4533 | c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, |
4534 | bool *seen_id) |
4535 | { |
4536 | /* Parse any initial pointer part. */ |
4537 | if (c_parser_next_token_is (parser, type: CPP_MULT)) |
4538 | { |
4539 | struct c_declspecs *quals_attrs = build_null_declspecs (); |
4540 | struct c_declarator *inner; |
4541 | c_parser_consume_token (parser); |
4542 | c_parser_declspecs (parser, specs: quals_attrs, scspec_ok: false, typespec_ok: false, start_attr_ok: true, |
4543 | alignspec_ok: false, auto_type_ok: false, start_std_attr_ok: true, end_std_attr_ok: false, la: cla_prefer_id); |
4544 | inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); |
4545 | if (inner == NULL) |
4546 | return NULL; |
4547 | else |
4548 | return make_pointer_declarator (quals_attrs, inner); |
4549 | } |
4550 | /* Now we have a direct declarator, direct abstract declarator or |
4551 | nothing (which counts as a direct abstract declarator here). */ |
4552 | return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id); |
4553 | } |
4554 | |
4555 | /* Parse a direct declarator or direct abstract declarator; arguments |
4556 | as c_parser_declarator. */ |
4557 | |
4558 | static struct c_declarator * |
4559 | c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, |
4560 | bool *seen_id) |
4561 | { |
4562 | /* The direct declarator must start with an identifier (possibly |
4563 | omitted) or a parenthesized declarator (possibly abstract). In |
4564 | an ordinary declarator, initial parentheses must start a |
4565 | parenthesized declarator. In an abstract declarator or parameter |
4566 | declarator, they could start a parenthesized declarator or a |
4567 | parameter list. To tell which, the open parenthesis and any |
4568 | following gnu-attributes must be read. If a declaration |
4569 | specifier or standard attributes follow, then it is a parameter |
4570 | list; if the specifier is a typedef name, there might be an |
4571 | ambiguity about redeclaring it, which is resolved in the |
4572 | direction of treating it as a typedef name. If a close |
4573 | parenthesis follows, it is also an empty parameter list, as the |
4574 | syntax does not permit empty abstract declarators. Otherwise, it |
4575 | is a parenthesized declarator (in which case the analysis may be |
4576 | repeated inside it, recursively). |
4577 | |
4578 | ??? There is an ambiguity in a parameter declaration "int |
4579 | (__attribute__((foo)) x)", where x is not a typedef name: it |
4580 | could be an abstract declarator for a function, or declare x with |
4581 | parentheses. The proper resolution of this ambiguity needs |
4582 | documenting. At present we follow an accident of the old |
4583 | parser's implementation, whereby the first parameter must have |
4584 | some declaration specifiers other than just gnu-attributes. Thus as |
4585 | a parameter declaration it is treated as a parenthesized |
4586 | parameter named x, and as an abstract declarator it is |
4587 | rejected. |
4588 | |
4589 | ??? Also following the old parser, gnu-attributes inside an empty |
4590 | parameter list are ignored, making it a list not yielding a |
4591 | prototype, rather than giving an error or making it have one |
4592 | parameter with implicit type int. |
4593 | |
4594 | ??? Also following the old parser, typedef names may be |
4595 | redeclared in declarators, but not Objective-C class names. */ |
4596 | |
4597 | if (kind != C_DTR_ABSTRACT |
4598 | && c_parser_next_token_is (parser, type: CPP_NAME) |
4599 | && ((type_seen_p |
4600 | && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME |
4601 | || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) |
4602 | || c_parser_peek_token (parser)->id_kind == C_ID_ID)) |
4603 | { |
4604 | struct c_declarator *inner |
4605 | = build_id_declarator (c_parser_peek_token (parser)->value); |
4606 | *seen_id = true; |
4607 | inner->id_loc = c_parser_peek_token (parser)->location; |
4608 | c_parser_consume_token (parser); |
4609 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
4610 | inner->u.id.attrs = c_parser_std_attribute_specifier_sequence (parser); |
4611 | return c_parser_direct_declarator_inner (parser, *seen_id, inner); |
4612 | } |
4613 | |
4614 | if (kind != C_DTR_NORMAL |
4615 | && c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE) |
4616 | && !c_parser_nth_token_starts_std_attributes (parser, 1)) |
4617 | { |
4618 | struct c_declarator *inner = build_id_declarator (NULL_TREE); |
4619 | inner->id_loc = c_parser_peek_token (parser)->location; |
4620 | return c_parser_direct_declarator_inner (parser, *seen_id, inner); |
4621 | } |
4622 | |
4623 | /* Either we are at the end of an abstract declarator, or we have |
4624 | parentheses. */ |
4625 | |
4626 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
4627 | { |
4628 | tree attrs; |
4629 | struct c_declarator *inner; |
4630 | c_parser_consume_token (parser); |
4631 | bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, |
4632 | keyword: RID_ATTRIBUTE); |
4633 | attrs = c_parser_gnu_attributes (parser); |
4634 | if (kind != C_DTR_NORMAL |
4635 | && (c_parser_next_token_starts_declspecs (parser) |
4636 | || (!have_gnu_attrs |
4637 | && (c_parser_nth_token_starts_std_attributes (parser, 1) |
4638 | || c_parser_next_token_is (parser, type: CPP_ELLIPSIS))) |
4639 | || c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN))) |
4640 | { |
4641 | struct c_arg_info *args |
4642 | = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL, |
4643 | attrs, have_gnu_attrs); |
4644 | if (args == NULL) |
4645 | return NULL; |
4646 | else |
4647 | { |
4648 | inner = build_id_declarator (NULL_TREE); |
4649 | if (!(args->types |
4650 | && args->types != error_mark_node |
4651 | && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) |
4652 | && c_parser_nth_token_starts_std_attributes (parser, 1)) |
4653 | { |
4654 | tree std_attrs |
4655 | = c_parser_std_attribute_specifier_sequence (parser); |
4656 | if (std_attrs) |
4657 | inner = build_attrs_declarator (std_attrs, inner); |
4658 | } |
4659 | inner = build_function_declarator (args, inner); |
4660 | return c_parser_direct_declarator_inner (parser, *seen_id, |
4661 | inner); |
4662 | } |
4663 | } |
4664 | /* A parenthesized declarator. */ |
4665 | inner = c_parser_declarator (parser, type_seen_p, kind, seen_id); |
4666 | if (inner != NULL && attrs != NULL) |
4667 | inner = build_attrs_declarator (attrs, inner); |
4668 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4669 | { |
4670 | c_parser_consume_token (parser); |
4671 | if (inner == NULL) |
4672 | return NULL; |
4673 | else |
4674 | return c_parser_direct_declarator_inner (parser, *seen_id, inner); |
4675 | } |
4676 | else |
4677 | { |
4678 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4679 | msgid: "expected %<)%>" ); |
4680 | return NULL; |
4681 | } |
4682 | } |
4683 | else |
4684 | { |
4685 | if (kind == C_DTR_NORMAL) |
4686 | { |
4687 | c_parser_error (parser, gmsgid: "expected identifier or %<(%>" ); |
4688 | return NULL; |
4689 | } |
4690 | else |
4691 | return build_id_declarator (NULL_TREE); |
4692 | } |
4693 | } |
4694 | |
4695 | /* Parse part of a direct declarator or direct abstract declarator, |
4696 | given that some (in INNER) has already been parsed; ID_PRESENT is |
4697 | true if an identifier is present, false for an abstract |
4698 | declarator. */ |
4699 | |
4700 | static struct c_declarator * |
4701 | c_parser_direct_declarator_inner (c_parser *parser, bool id_present, |
4702 | struct c_declarator *inner) |
4703 | { |
4704 | /* Parse a sequence of array declarators and parameter lists. */ |
4705 | if (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE) |
4706 | && !c_parser_nth_token_starts_std_attributes (parser, 1)) |
4707 | { |
4708 | location_t brace_loc = c_parser_peek_token (parser)->location; |
4709 | struct c_declarator *declarator; |
4710 | struct c_declspecs *quals_attrs = build_null_declspecs (); |
4711 | bool static_seen; |
4712 | bool star_seen; |
4713 | struct c_expr dimen; |
4714 | dimen.value = NULL_TREE; |
4715 | dimen.original_code = ERROR_MARK; |
4716 | dimen.original_type = NULL_TREE; |
4717 | c_parser_consume_token (parser); |
4718 | c_parser_declspecs (parser, specs: quals_attrs, scspec_ok: false, typespec_ok: false, start_attr_ok: true, |
4719 | alignspec_ok: false, auto_type_ok: false, start_std_attr_ok: false, end_std_attr_ok: false, la: cla_prefer_id); |
4720 | static_seen = c_parser_next_token_is_keyword (parser, keyword: RID_STATIC); |
4721 | if (static_seen) |
4722 | c_parser_consume_token (parser); |
4723 | if (static_seen && !quals_attrs->declspecs_seen_p) |
4724 | c_parser_declspecs (parser, specs: quals_attrs, scspec_ok: false, typespec_ok: false, start_attr_ok: true, |
4725 | alignspec_ok: false, auto_type_ok: false, start_std_attr_ok: false, end_std_attr_ok: false, la: cla_prefer_id); |
4726 | if (!quals_attrs->declspecs_seen_p) |
4727 | quals_attrs = NULL; |
4728 | /* If "static" is present, there must be an array dimension. |
4729 | Otherwise, there may be a dimension, "*", or no |
4730 | dimension. */ |
4731 | if (static_seen) |
4732 | { |
4733 | star_seen = false; |
4734 | dimen = c_parser_expr_no_commas (parser, NULL); |
4735 | } |
4736 | else |
4737 | { |
4738 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
4739 | { |
4740 | dimen.value = NULL_TREE; |
4741 | star_seen = false; |
4742 | } |
4743 | else if (c_parser_next_token_is (parser, type: CPP_MULT)) |
4744 | { |
4745 | if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE) |
4746 | { |
4747 | dimen.value = NULL_TREE; |
4748 | star_seen = true; |
4749 | c_parser_consume_token (parser); |
4750 | } |
4751 | else |
4752 | { |
4753 | star_seen = false; |
4754 | dimen = c_parser_expr_no_commas (parser, NULL); |
4755 | } |
4756 | } |
4757 | else |
4758 | { |
4759 | star_seen = false; |
4760 | dimen = c_parser_expr_no_commas (parser, NULL); |
4761 | } |
4762 | } |
4763 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
4764 | c_parser_consume_token (parser); |
4765 | else |
4766 | { |
4767 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
4768 | msgid: "expected %<]%>" ); |
4769 | return NULL; |
4770 | } |
4771 | if (dimen.value) |
4772 | dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true); |
4773 | declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs, |
4774 | static_seen, star_seen); |
4775 | if (declarator == NULL) |
4776 | return NULL; |
4777 | if (c_parser_nth_token_starts_std_attributes (parser, 1)) |
4778 | { |
4779 | tree std_attrs |
4780 | = c_parser_std_attribute_specifier_sequence (parser); |
4781 | if (std_attrs) |
4782 | inner = build_attrs_declarator (std_attrs, inner); |
4783 | } |
4784 | inner = set_array_declarator_inner (declarator, inner); |
4785 | return c_parser_direct_declarator_inner (parser, id_present, inner); |
4786 | } |
4787 | else if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
4788 | { |
4789 | tree attrs; |
4790 | struct c_arg_info *args; |
4791 | c_parser_consume_token (parser); |
4792 | bool have_gnu_attrs = c_parser_next_token_is_keyword (parser, |
4793 | keyword: RID_ATTRIBUTE); |
4794 | attrs = c_parser_gnu_attributes (parser); |
4795 | args = c_parser_parms_declarator (parser, id_present, attrs, |
4796 | have_gnu_attrs); |
4797 | if (args == NULL) |
4798 | return NULL; |
4799 | else |
4800 | { |
4801 | if (!(args->types |
4802 | && args->types != error_mark_node |
4803 | && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE) |
4804 | && c_parser_nth_token_starts_std_attributes (parser, 1)) |
4805 | { |
4806 | tree std_attrs |
4807 | = c_parser_std_attribute_specifier_sequence (parser); |
4808 | if (std_attrs) |
4809 | inner = build_attrs_declarator (std_attrs, inner); |
4810 | } |
4811 | inner = build_function_declarator (args, inner); |
4812 | return c_parser_direct_declarator_inner (parser, id_present, inner); |
4813 | } |
4814 | } |
4815 | return inner; |
4816 | } |
4817 | |
4818 | /* Parse a parameter list or identifier list, including the closing |
4819 | parenthesis but not the opening one. ATTRS are the gnu-attributes |
4820 | at the start of the list. ID_LIST_OK is true if an identifier list |
4821 | is acceptable; such a list must not have attributes at the start. |
4822 | HAVE_GNU_ATTRS says whether any gnu-attributes (including empty |
4823 | attributes) were present (in which case standard attributes cannot |
4824 | occur). */ |
4825 | |
4826 | static struct c_arg_info * |
4827 | c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs, |
4828 | bool have_gnu_attrs) |
4829 | { |
4830 | push_scope (); |
4831 | declare_parm_level (); |
4832 | /* If the list starts with an identifier, it is an identifier list. |
4833 | Otherwise, it is either a prototype list or an empty list. */ |
4834 | if (id_list_ok |
4835 | && !attrs |
4836 | && c_parser_next_token_is (parser, type: CPP_NAME) |
4837 | && c_parser_peek_token (parser)->id_kind == C_ID_ID |
4838 | |
4839 | /* Look ahead to detect typos in type names. */ |
4840 | && c_parser_peek_2nd_token (parser)->type != CPP_NAME |
4841 | && c_parser_peek_2nd_token (parser)->type != CPP_MULT |
4842 | && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN |
4843 | && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE |
4844 | && c_parser_peek_2nd_token (parser)->type != CPP_KEYWORD) |
4845 | { |
4846 | tree list = NULL_TREE, *nextp = &list; |
4847 | while (c_parser_next_token_is (parser, type: CPP_NAME) |
4848 | && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
4849 | { |
4850 | *nextp = build_tree_list (NULL_TREE, |
4851 | c_parser_peek_token (parser)->value); |
4852 | nextp = & TREE_CHAIN (*nextp); |
4853 | c_parser_consume_token (parser); |
4854 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
4855 | break; |
4856 | c_parser_consume_token (parser); |
4857 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4858 | { |
4859 | c_parser_error (parser, gmsgid: "expected identifier" ); |
4860 | break; |
4861 | } |
4862 | } |
4863 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4864 | { |
4865 | struct c_arg_info *ret = build_arg_info (); |
4866 | ret->types = list; |
4867 | c_parser_consume_token (parser); |
4868 | pop_scope (); |
4869 | return ret; |
4870 | } |
4871 | else |
4872 | { |
4873 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4874 | msgid: "expected %<)%>" ); |
4875 | pop_scope (); |
4876 | return NULL; |
4877 | } |
4878 | } |
4879 | else |
4880 | { |
4881 | struct c_arg_info *ret |
4882 | = c_parser_parms_list_declarator (parser, attrs, NULL, have_gnu_attrs); |
4883 | pop_scope (); |
4884 | return ret; |
4885 | } |
4886 | } |
4887 | |
4888 | /* Parse a parameter list (possibly empty), including the closing |
4889 | parenthesis but not the opening one. ATTRS are the gnu-attributes |
4890 | at the start of the list; if HAVE_GNU_ATTRS, there were some such |
4891 | attributes (possibly empty, in which case ATTRS is NULL_TREE), |
4892 | which means standard attributes cannot start the list. EXPR is |
4893 | NULL or an expression that needs to be evaluated for the side |
4894 | effects of array size expressions in the parameters. */ |
4895 | |
4896 | static struct c_arg_info * |
4897 | c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr, |
4898 | bool have_gnu_attrs) |
4899 | { |
4900 | bool bad_parm = false; |
4901 | |
4902 | /* ??? Following the old parser, forward parameter declarations may |
4903 | use abstract declarators, and if no real parameter declarations |
4904 | follow the forward declarations then this is not diagnosed. Also |
4905 | note as above that gnu-attributes are ignored as the only contents of |
4906 | the parentheses, or as the only contents after forward |
4907 | declarations. */ |
4908 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4909 | { |
4910 | struct c_arg_info *ret = build_arg_info (); |
4911 | c_parser_consume_token (parser); |
4912 | return ret; |
4913 | } |
4914 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS) && !have_gnu_attrs) |
4915 | { |
4916 | struct c_arg_info *ret = build_arg_info (); |
4917 | |
4918 | ret->types = NULL_TREE; |
4919 | pedwarn_c11 (c_parser_peek_token (parser)->location, opt: OPT_Wpedantic, |
4920 | "ISO C requires a named argument before %<...%> " |
4921 | "before C23" ); |
4922 | c_parser_consume_token (parser); |
4923 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4924 | { |
4925 | ret->no_named_args_stdarg_p = true; |
4926 | c_parser_consume_token (parser); |
4927 | return ret; |
4928 | } |
4929 | else |
4930 | { |
4931 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4932 | msgid: "expected %<)%>" ); |
4933 | return NULL; |
4934 | } |
4935 | } |
4936 | /* Nonempty list of parameters, either terminated with semicolon |
4937 | (forward declarations; recurse) or with close parenthesis (normal |
4938 | function) or with ", ... )" (variadic function). */ |
4939 | while (true) |
4940 | { |
4941 | /* Parse a parameter. */ |
4942 | struct c_parm *parm = c_parser_parameter_declaration (parser, attrs, |
4943 | have_gnu_attrs); |
4944 | attrs = NULL_TREE; |
4945 | have_gnu_attrs = false; |
4946 | if (parm == NULL) |
4947 | bad_parm = true; |
4948 | else |
4949 | push_parm_decl (parm, &expr); |
4950 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
4951 | { |
4952 | tree new_attrs; |
4953 | c_parser_consume_token (parser); |
4954 | mark_forward_parm_decls (); |
4955 | bool new_have_gnu_attrs |
4956 | = c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE); |
4957 | new_attrs = c_parser_gnu_attributes (parser); |
4958 | return c_parser_parms_list_declarator (parser, attrs: new_attrs, expr, |
4959 | have_gnu_attrs: new_have_gnu_attrs); |
4960 | } |
4961 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4962 | { |
4963 | c_parser_consume_token (parser); |
4964 | if (bad_parm) |
4965 | return NULL; |
4966 | else |
4967 | return get_parm_info (false, expr); |
4968 | } |
4969 | if (!c_parser_require (parser, type: CPP_COMMA, |
4970 | msgid: "expected %<;%>, %<,%> or %<)%>" , |
4971 | UNKNOWN_LOCATION, type_is_unique: false)) |
4972 | { |
4973 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
4974 | return NULL; |
4975 | } |
4976 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
4977 | { |
4978 | c_parser_consume_token (parser); |
4979 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
4980 | { |
4981 | c_parser_consume_token (parser); |
4982 | if (bad_parm) |
4983 | return NULL; |
4984 | else |
4985 | return get_parm_info (true, expr); |
4986 | } |
4987 | else |
4988 | { |
4989 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
4990 | msgid: "expected %<)%>" ); |
4991 | return NULL; |
4992 | } |
4993 | } |
4994 | } |
4995 | } |
4996 | |
4997 | /* Parse a parameter declaration. ATTRS are the gnu-attributes at the |
4998 | start of the declaration if it is the first parameter; |
4999 | HAVE_GNU_ATTRS is true if there were any gnu-attributes there (even |
5000 | empty) there. */ |
5001 | |
5002 | static struct c_parm * |
5003 | c_parser_parameter_declaration (c_parser *parser, tree attrs, |
5004 | bool have_gnu_attrs) |
5005 | { |
5006 | struct c_declspecs *specs; |
5007 | struct c_declarator *declarator; |
5008 | tree prefix_attrs; |
5009 | tree postfix_attrs = NULL_TREE; |
5010 | bool dummy = false; |
5011 | |
5012 | /* Accept #pragmas between parameter declarations. */ |
5013 | while (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
5014 | c_parser_pragma (parser, pragma_param, NULL); |
5015 | |
5016 | if (!c_parser_next_token_starts_declspecs (parser) |
5017 | && !c_parser_nth_token_starts_std_attributes (parser, 1)) |
5018 | { |
5019 | c_token *token = c_parser_peek_token (parser); |
5020 | if (parser->error) |
5021 | return NULL; |
5022 | c_parser_set_source_position_from_token (token); |
5023 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_type)) |
5024 | { |
5025 | auto_diagnostic_group d; |
5026 | name_hint hint = lookup_name_fuzzy (token->value, |
5027 | FUZZY_LOOKUP_TYPENAME, |
5028 | token->location); |
5029 | if (const char *suggestion = hint.suggestion ()) |
5030 | { |
5031 | gcc_rich_location richloc (token->location); |
5032 | richloc.add_fixit_replace (new_content: suggestion); |
5033 | error_at (&richloc, |
5034 | "unknown type name %qE; did you mean %qs?" , |
5035 | token->value, suggestion); |
5036 | } |
5037 | else |
5038 | error_at (token->location, "unknown type name %qE" , token->value); |
5039 | parser->error = true; |
5040 | } |
5041 | /* ??? In some Objective-C cases '...' isn't applicable so there |
5042 | should be a different message. */ |
5043 | else |
5044 | c_parser_error (parser, |
5045 | gmsgid: "expected declaration specifiers or %<...%>" ); |
5046 | c_parser_skip_to_end_of_parameter (parser); |
5047 | return NULL; |
5048 | } |
5049 | |
5050 | location_t start_loc = c_parser_peek_token (parser)->location; |
5051 | |
5052 | specs = build_null_declspecs (); |
5053 | if (attrs) |
5054 | { |
5055 | declspecs_add_attrs (input_location, specs, attrs); |
5056 | attrs = NULL_TREE; |
5057 | } |
5058 | c_parser_declspecs (parser, specs, scspec_ok: true, typespec_ok: true, start_attr_ok: true, alignspec_ok: true, auto_type_ok: false, |
5059 | start_std_attr_ok: !have_gnu_attrs, end_std_attr_ok: true, la: cla_nonabstract_decl); |
5060 | finish_declspecs (specs); |
5061 | pending_xref_error (); |
5062 | prefix_attrs = specs->attrs; |
5063 | specs->attrs = NULL_TREE; |
5064 | declarator = c_parser_declarator (parser, |
5065 | type_seen_p: specs->typespec_kind != ctsk_none, |
5066 | kind: C_DTR_PARM, seen_id: &dummy); |
5067 | if (declarator == NULL) |
5068 | { |
5069 | c_parser_skip_until_found (parser, type: CPP_COMMA, NULL); |
5070 | return NULL; |
5071 | } |
5072 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
5073 | postfix_attrs = c_parser_gnu_attributes (parser); |
5074 | |
5075 | /* Generate a location for the parameter, ranging from the start of the |
5076 | initial token to the end of the final token. |
5077 | |
5078 | If we have a identifier, then use it for the caret location, e.g. |
5079 | |
5080 | extern int callee (int one, int (*two)(int, int), float three); |
5081 | ~~~~~~^~~~~~~~~~~~~~ |
5082 | |
5083 | otherwise, reuse the start location for the caret location e.g.: |
5084 | |
5085 | extern int callee (int one, int (*)(int, int), float three); |
5086 | ^~~~~~~~~~~~~~~~~ |
5087 | */ |
5088 | location_t end_loc = parser->last_token_location; |
5089 | |
5090 | /* Find any cdk_id declarator; determine if we have an identifier. */ |
5091 | c_declarator *id_declarator = declarator; |
5092 | while (id_declarator && id_declarator->kind != cdk_id) |
5093 | id_declarator = id_declarator->declarator; |
5094 | location_t caret_loc = (id_declarator->u.id.id |
5095 | ? id_declarator->id_loc |
5096 | : start_loc); |
5097 | location_t param_loc = make_location (caret: caret_loc, start: start_loc, finish: end_loc); |
5098 | |
5099 | return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs), |
5100 | declarator, param_loc); |
5101 | } |
5102 | |
5103 | /* Parse a string literal in an asm expression. It should not be |
5104 | translated, and wide string literals are an error although |
5105 | permitted by the syntax. This is a GNU extension. |
5106 | |
5107 | asm-string-literal: |
5108 | string-literal |
5109 | */ |
5110 | |
5111 | static tree |
5112 | c_parser_asm_string_literal (c_parser *parser) |
5113 | { |
5114 | tree str; |
5115 | int save_flag = warn_overlength_strings; |
5116 | warn_overlength_strings = 0; |
5117 | str = c_parser_string_literal (parser, false, false).value; |
5118 | warn_overlength_strings = save_flag; |
5119 | return str; |
5120 | } |
5121 | |
5122 | /* Parse a simple asm expression. This is used in restricted |
5123 | contexts, where a full expression with inputs and outputs does not |
5124 | make sense. This is a GNU extension. |
5125 | |
5126 | simple-asm-expr: |
5127 | asm ( asm-string-literal ) |
5128 | */ |
5129 | |
5130 | static tree |
5131 | c_parser_simple_asm_expr (c_parser *parser) |
5132 | { |
5133 | tree str; |
5134 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); |
5135 | c_parser_consume_token (parser); |
5136 | matching_parens parens; |
5137 | if (!parens.require_open (parser)) |
5138 | return NULL_TREE; |
5139 | str = c_parser_asm_string_literal (parser); |
5140 | if (!parens.require_close (parser)) |
5141 | { |
5142 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
5143 | return NULL_TREE; |
5144 | } |
5145 | return str; |
5146 | } |
5147 | |
5148 | static tree |
5149 | c_parser_gnu_attribute_any_word (c_parser *parser) |
5150 | { |
5151 | tree attr_name = NULL_TREE; |
5152 | |
5153 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD)) |
5154 | { |
5155 | /* ??? See comment above about what keywords are accepted here. */ |
5156 | bool ok; |
5157 | switch (c_parser_peek_token (parser)->keyword) |
5158 | { |
5159 | case RID_STATIC: |
5160 | case RID_UNSIGNED: |
5161 | case RID_LONG: |
5162 | case RID_CONST: |
5163 | case RID_EXTERN: |
5164 | case RID_REGISTER: |
5165 | case RID_TYPEDEF: |
5166 | case RID_SHORT: |
5167 | case RID_INLINE: |
5168 | case RID_NORETURN: |
5169 | case RID_VOLATILE: |
5170 | case RID_SIGNED: |
5171 | case RID_AUTO: |
5172 | case RID_RESTRICT: |
5173 | case RID_COMPLEX: |
5174 | case RID_THREAD: |
5175 | case RID_INT: |
5176 | case RID_CHAR: |
5177 | case RID_FLOAT: |
5178 | case RID_DOUBLE: |
5179 | case RID_VOID: |
5180 | case RID_DFLOAT32: |
5181 | case RID_DFLOAT64: |
5182 | case RID_DFLOAT128: |
5183 | CASE_RID_FLOATN_NX: |
5184 | case RID_BOOL: |
5185 | case RID_BITINT: |
5186 | case RID_FRACT: |
5187 | case RID_ACCUM: |
5188 | case RID_SAT: |
5189 | case RID_TRANSACTION_ATOMIC: |
5190 | case RID_TRANSACTION_CANCEL: |
5191 | case RID_ATOMIC: |
5192 | case RID_AUTO_TYPE: |
5193 | case RID_CONSTEXPR: |
5194 | case RID_INT_N_0: |
5195 | case RID_INT_N_1: |
5196 | case RID_INT_N_2: |
5197 | case RID_INT_N_3: |
5198 | ok = true; |
5199 | break; |
5200 | default: |
5201 | ok = false; |
5202 | break; |
5203 | } |
5204 | if (!ok) |
5205 | return NULL_TREE; |
5206 | |
5207 | /* Accept __attribute__((__const)) as __attribute__((const)) etc. */ |
5208 | attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword]; |
5209 | } |
5210 | else if (c_parser_next_token_is (parser, type: CPP_NAME)) |
5211 | attr_name = c_parser_peek_token (parser)->value; |
5212 | |
5213 | return attr_name; |
5214 | } |
5215 | |
5216 | /* Parse attribute arguments. This is a common form of syntax |
5217 | covering all currently valid GNU and standard attributes. |
5218 | |
5219 | gnu-attribute-arguments: |
5220 | identifier |
5221 | identifier , nonempty-expr-list |
5222 | expr-list |
5223 | |
5224 | where the "identifier" must not be declared as a type. ??? Why not |
5225 | allow identifiers declared as types to start the arguments? */ |
5226 | |
5227 | static tree |
5228 | c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, |
5229 | bool require_string, bool assume_attr, |
5230 | bool allow_empty_args) |
5231 | { |
5232 | vec<tree, va_gc> *expr_list; |
5233 | tree attr_args; |
5234 | /* Parse the attribute contents. If they start with an |
5235 | identifier which is followed by a comma or close |
5236 | parenthesis, then the arguments start with that |
5237 | identifier; otherwise they are an expression list. |
5238 | In objective-c the identifier may be a classname. */ |
5239 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
5240 | && (c_parser_peek_token (parser)->id_kind == C_ID_ID |
5241 | || (c_dialect_objc () |
5242 | && c_parser_peek_token (parser)->id_kind |
5243 | == C_ID_CLASSNAME)) |
5244 | && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA) |
5245 | || (c_parser_peek_2nd_token (parser)->type |
5246 | == CPP_CLOSE_PAREN)) |
5247 | && (takes_identifier |
5248 | || (c_dialect_objc () |
5249 | && !assume_attr |
5250 | && c_parser_peek_token (parser)->id_kind |
5251 | == C_ID_CLASSNAME))) |
5252 | { |
5253 | tree arg1 = c_parser_peek_token (parser)->value; |
5254 | c_parser_consume_token (parser); |
5255 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5256 | attr_args = build_tree_list (NULL_TREE, arg1); |
5257 | else |
5258 | { |
5259 | tree tree_list; |
5260 | c_parser_consume_token (parser); |
5261 | expr_list = c_parser_expr_list (parser, false, true, |
5262 | NULL, NULL, NULL, NULL); |
5263 | tree_list = build_tree_list_vec (expr_list); |
5264 | attr_args = tree_cons (NULL_TREE, arg1, tree_list); |
5265 | release_tree_vector (expr_list); |
5266 | } |
5267 | } |
5268 | else |
5269 | { |
5270 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5271 | { |
5272 | if (!allow_empty_args) |
5273 | error_at (c_parser_peek_token (parser)->location, |
5274 | "parentheses must be omitted if " |
5275 | "attribute argument list is empty" ); |
5276 | attr_args = NULL_TREE; |
5277 | } |
5278 | else if (require_string) |
5279 | { |
5280 | /* The only valid argument for this attribute is a string |
5281 | literal. Handle this specially here to avoid accepting |
5282 | string literals with excess parentheses. */ |
5283 | tree string = c_parser_string_literal (parser, false, true).value; |
5284 | attr_args = build_tree_list (NULL_TREE, string); |
5285 | } |
5286 | else if (assume_attr) |
5287 | { |
5288 | tree cond |
5289 | = c_parser_conditional_expression (parser, NULL, NULL_TREE).value; |
5290 | if (!c_parser_next_token_is (parser, type: CPP_COMMA)) |
5291 | attr_args = build_tree_list (NULL_TREE, cond); |
5292 | else |
5293 | { |
5294 | tree tree_list; |
5295 | c_parser_consume_token (parser); |
5296 | expr_list = c_parser_expr_list (parser, false, true, |
5297 | NULL, NULL, NULL, NULL); |
5298 | tree_list = build_tree_list_vec (expr_list); |
5299 | attr_args = tree_cons (NULL_TREE, cond, tree_list); |
5300 | release_tree_vector (expr_list); |
5301 | } |
5302 | } |
5303 | else |
5304 | { |
5305 | expr_list = c_parser_expr_list (parser, false, true, |
5306 | NULL, NULL, NULL, NULL); |
5307 | attr_args = build_tree_list_vec (expr_list); |
5308 | release_tree_vector (expr_list); |
5309 | } |
5310 | } |
5311 | return attr_args; |
5312 | } |
5313 | |
5314 | /* Parse (possibly empty) gnu-attributes. This is a GNU extension. |
5315 | |
5316 | gnu-attributes: |
5317 | empty |
5318 | gnu-attributes gnu-attribute |
5319 | |
5320 | gnu-attribute: |
5321 | __attribute__ ( ( gnu-attribute-list ) ) |
5322 | |
5323 | gnu-attribute-list: |
5324 | gnu-attrib |
5325 | gnu-attribute_list , gnu-attrib |
5326 | |
5327 | gnu-attrib: |
5328 | empty |
5329 | any-word |
5330 | any-word ( gnu-attribute-arguments ) |
5331 | |
5332 | where "any-word" may be any identifier (including one declared as a |
5333 | type), a reserved word storage class specifier, type specifier or |
5334 | type qualifier. ??? This still leaves out most reserved keywords |
5335 | (following the old parser), shouldn't we include them? |
5336 | When EXPECT_COMMA is true, expect the attribute to be preceded |
5337 | by a comma and fail if it isn't. |
5338 | When EMPTY_OK is true, allow and consume any number of consecutive |
5339 | commas with no attributes in between. */ |
5340 | |
5341 | static tree |
5342 | c_parser_gnu_attribute (c_parser *parser, tree attrs, |
5343 | bool expect_comma = false, bool empty_ok = true) |
5344 | { |
5345 | bool comma_first = c_parser_next_token_is (parser, type: CPP_COMMA); |
5346 | if (!comma_first |
5347 | && !c_parser_next_token_is (parser, type: CPP_NAME) |
5348 | && !c_parser_next_token_is (parser, type: CPP_KEYWORD)) |
5349 | return NULL_TREE; |
5350 | |
5351 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
5352 | { |
5353 | c_parser_consume_token (parser); |
5354 | if (!empty_ok) |
5355 | return attrs; |
5356 | } |
5357 | |
5358 | tree attr_name = c_parser_gnu_attribute_any_word (parser); |
5359 | if (attr_name == NULL_TREE) |
5360 | return NULL_TREE; |
5361 | |
5362 | attr_name = canonicalize_attr_name (attr_name); |
5363 | c_parser_consume_token (parser); |
5364 | |
5365 | tree attr; |
5366 | if (c_parser_next_token_is_not (parser, type: CPP_OPEN_PAREN)) |
5367 | { |
5368 | if (expect_comma && !comma_first) |
5369 | { |
5370 | /* A comma is missing between the last attribute on the chain |
5371 | and this one. */ |
5372 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5373 | msgid: "expected %<)%>" ); |
5374 | return error_mark_node; |
5375 | } |
5376 | attr = build_tree_list (attr_name, NULL_TREE); |
5377 | /* Add this attribute to the list. */ |
5378 | attrs = chainon (attrs, attr); |
5379 | return attrs; |
5380 | } |
5381 | c_parser_consume_token (parser); |
5382 | |
5383 | tree attr_args |
5384 | = c_parser_attribute_arguments (parser, |
5385 | takes_identifier: attribute_takes_identifier_p (attr_name), |
5386 | require_string: false, |
5387 | assume_attr: is_attribute_p (attr_name: "assume" , ident: attr_name), |
5388 | allow_empty_args: true); |
5389 | |
5390 | attr = build_tree_list (attr_name, attr_args); |
5391 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5392 | c_parser_consume_token (parser); |
5393 | else |
5394 | { |
5395 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5396 | msgid: "expected %<)%>" ); |
5397 | return error_mark_node; |
5398 | } |
5399 | |
5400 | if (expect_comma && !comma_first) |
5401 | { |
5402 | /* A comma is missing between the last attribute on the chain |
5403 | and this one. */ |
5404 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5405 | msgid: "expected %<)%>" ); |
5406 | return error_mark_node; |
5407 | } |
5408 | |
5409 | /* Add this attribute to the list. */ |
5410 | attrs = chainon (attrs, attr); |
5411 | return attrs; |
5412 | } |
5413 | |
5414 | static tree |
5415 | c_parser_gnu_attributes (c_parser *parser) |
5416 | { |
5417 | tree attrs = NULL_TREE; |
5418 | while (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
5419 | { |
5420 | bool save_translate_strings_p = parser->translate_strings_p; |
5421 | parser->translate_strings_p = false; |
5422 | /* Consume the `__attribute__' keyword. */ |
5423 | c_parser_consume_token (parser); |
5424 | /* Look for the two `(' tokens. */ |
5425 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
5426 | { |
5427 | parser->translate_strings_p = save_translate_strings_p; |
5428 | return attrs; |
5429 | } |
5430 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
5431 | { |
5432 | parser->translate_strings_p = save_translate_strings_p; |
5433 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
5434 | return attrs; |
5435 | } |
5436 | /* Parse the attribute list. Require a comma between successive |
5437 | (possibly empty) attributes. */ |
5438 | for (bool expect_comma = false; ; expect_comma = true) |
5439 | { |
5440 | /* Parse a single attribute. */ |
5441 | tree attr = c_parser_gnu_attribute (parser, attrs, expect_comma); |
5442 | if (attr == error_mark_node) |
5443 | return attrs; |
5444 | if (!attr) |
5445 | break; |
5446 | attrs = attr; |
5447 | } |
5448 | |
5449 | /* Look for the two `)' tokens. */ |
5450 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5451 | c_parser_consume_token (parser); |
5452 | else |
5453 | { |
5454 | parser->translate_strings_p = save_translate_strings_p; |
5455 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5456 | msgid: "expected %<)%>" ); |
5457 | return attrs; |
5458 | } |
5459 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
5460 | c_parser_consume_token (parser); |
5461 | else |
5462 | { |
5463 | parser->translate_strings_p = save_translate_strings_p; |
5464 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
5465 | msgid: "expected %<)%>" ); |
5466 | return attrs; |
5467 | } |
5468 | parser->translate_strings_p = save_translate_strings_p; |
5469 | } |
5470 | |
5471 | return attrs; |
5472 | } |
5473 | |
5474 | /* Parse an optional balanced token sequence. |
5475 | |
5476 | balanced-token-sequence: |
5477 | balanced-token |
5478 | balanced-token-sequence balanced-token |
5479 | |
5480 | balanced-token: |
5481 | ( balanced-token-sequence[opt] ) |
5482 | [ balanced-token-sequence[opt] ] |
5483 | { balanced-token-sequence[opt] } |
5484 | any token other than ()[]{} |
5485 | */ |
5486 | |
5487 | static void |
5488 | c_parser_balanced_token_sequence (c_parser *parser) |
5489 | { |
5490 | while (true) |
5491 | { |
5492 | c_token *token = c_parser_peek_token (parser); |
5493 | switch (token->type) |
5494 | { |
5495 | case CPP_OPEN_BRACE: |
5496 | { |
5497 | matching_braces braces; |
5498 | braces.consume_open (parser); |
5499 | c_parser_balanced_token_sequence (parser); |
5500 | braces.require_close (parser); |
5501 | break; |
5502 | } |
5503 | |
5504 | case CPP_OPEN_PAREN: |
5505 | { |
5506 | matching_parens parens; |
5507 | parens.consume_open (parser); |
5508 | c_parser_balanced_token_sequence (parser); |
5509 | parens.require_close (parser); |
5510 | break; |
5511 | } |
5512 | |
5513 | case CPP_OPEN_SQUARE: |
5514 | c_parser_consume_token (parser); |
5515 | c_parser_balanced_token_sequence (parser); |
5516 | c_parser_require (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5517 | break; |
5518 | |
5519 | case CPP_CLOSE_BRACE: |
5520 | case CPP_CLOSE_PAREN: |
5521 | case CPP_CLOSE_SQUARE: |
5522 | case CPP_EOF: |
5523 | return; |
5524 | |
5525 | case CPP_PRAGMA: |
5526 | c_parser_consume_pragma (parser); |
5527 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
5528 | break; |
5529 | |
5530 | default: |
5531 | c_parser_consume_token (parser); |
5532 | break; |
5533 | } |
5534 | } |
5535 | } |
5536 | |
5537 | static bool c_parser_check_balanced_raw_token_sequence (c_parser *, |
5538 | unsigned int *); |
5539 | |
5540 | /* Parse arguments of omp::directive or omp::decl attribute. |
5541 | |
5542 | directive-name ,[opt] clause-list[opt] |
5543 | |
5544 | For directive just remember the tokens in a vector for subsequent |
5545 | parsing. */ |
5546 | |
5547 | static void |
5548 | c_parser_omp_directive_args (c_parser *parser, tree attribute, bool decl_p) |
5549 | { |
5550 | unsigned int n = 1; |
5551 | c_token *first = c_parser_peek_token (parser); |
5552 | if (!c_parser_check_balanced_raw_token_sequence (parser, &n) |
5553 | || (c_parser_peek_nth_token_raw (parser, n)->type |
5554 | != CPP_CLOSE_PAREN)) |
5555 | { |
5556 | c_parser_balanced_token_sequence (parser); |
5557 | TREE_VALUE (attribute) = NULL_TREE; |
5558 | return; |
5559 | } |
5560 | if (n == 1) |
5561 | { |
5562 | error_at (first->location, "expected OpenMP directive name" ); |
5563 | TREE_VALUE (attribute) = NULL_TREE; |
5564 | return; |
5565 | } |
5566 | vec<c_token, va_gc> *v; |
5567 | vec_alloc (v, nelems: n - 1); |
5568 | for (--n; n; --n) |
5569 | { |
5570 | c_token *tok = c_parser_peek_token (parser); |
5571 | v->quick_push (obj: *tok); |
5572 | c_parser_consume_token (parser); |
5573 | } |
5574 | tree arg = make_node (C_TOKEN_VEC); |
5575 | C_TOKEN_VEC_TOKENS (arg) = v; |
5576 | if (decl_p) |
5577 | TREE_PUBLIC (arg) = 1; |
5578 | TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute)); |
5579 | } |
5580 | |
5581 | /* Parse arguments of omp::sequence attribute. |
5582 | |
5583 | omp::[opt] directive-attr [ , omp::[opt] directive-attr ]... */ |
5584 | |
5585 | static void |
5586 | c_parser_omp_sequence_args (c_parser *parser, tree attribute) |
5587 | { |
5588 | do |
5589 | { |
5590 | c_token *token = c_parser_peek_token (parser); |
5591 | if (token->type == CPP_NAME |
5592 | && strcmp (IDENTIFIER_POINTER (token->value), s2: "omp" ) == 0 |
5593 | && c_parser_peek_2nd_token (parser)->type == CPP_SCOPE) |
5594 | { |
5595 | c_parser_consume_token (parser); |
5596 | c_parser_consume_token (parser); |
5597 | token = c_parser_peek_token (parser); |
5598 | } |
5599 | bool directive = false; |
5600 | const char *p; |
5601 | if (token->type != CPP_NAME) |
5602 | p = "" ; |
5603 | else |
5604 | p = IDENTIFIER_POINTER (token->value); |
5605 | if (strcmp (s1: p, s2: "directive" ) == 0) |
5606 | directive = true; |
5607 | else if (strcmp (s1: p, s2: "sequence" ) != 0) |
5608 | { |
5609 | error_at (token->location, "expected %<directive%> or %<sequence%>" ); |
5610 | unsigned nesting_depth = 0; |
5611 | |
5612 | while (true) |
5613 | { |
5614 | /* Peek at the next token. */ |
5615 | token = c_parser_peek_token (parser); |
5616 | /* If we've reached the token we want, consume it and stop. */ |
5617 | if ((token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) |
5618 | && !nesting_depth) |
5619 | break; |
5620 | /* If we've run out of tokens, stop. */ |
5621 | if (token->type == CPP_EOF) |
5622 | break; |
5623 | if (token->type == CPP_PRAGMA_EOL && parser->in_pragma) |
5624 | break; |
5625 | if (token->type == CPP_OPEN_BRACE |
5626 | || token->type == CPP_OPEN_PAREN |
5627 | || token->type == CPP_OPEN_SQUARE) |
5628 | ++nesting_depth; |
5629 | else if (token->type == CPP_CLOSE_BRACE |
5630 | || token->type == CPP_CLOSE_PAREN |
5631 | || token->type == CPP_CLOSE_SQUARE) |
5632 | { |
5633 | if (nesting_depth-- == 0) |
5634 | break; |
5635 | } |
5636 | /* Consume this token. */ |
5637 | c_parser_consume_token (parser); |
5638 | } |
5639 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5640 | break; |
5641 | c_parser_consume_token (parser); |
5642 | continue; |
5643 | } |
5644 | c_parser_consume_token (parser); |
5645 | matching_parens parens; |
5646 | if (parens.require_open (parser)) |
5647 | { |
5648 | if (directive) |
5649 | c_parser_omp_directive_args (parser, attribute, decl_p: false); |
5650 | else |
5651 | c_parser_omp_sequence_args (parser, attribute); |
5652 | parens.skip_until_found_close (parser); |
5653 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5654 | break; |
5655 | c_parser_consume_token (parser); |
5656 | } |
5657 | else if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5658 | break; |
5659 | else |
5660 | c_parser_consume_token (parser); |
5661 | } |
5662 | while (1); |
5663 | } |
5664 | |
5665 | /* Parse standard (C23) attributes (including GNU attributes in the |
5666 | gnu:: namespace). |
5667 | |
5668 | attribute-specifier-sequence: |
5669 | attribute-specifier-sequence[opt] attribute-specifier |
5670 | |
5671 | attribute-specifier: |
5672 | [ [ attribute-list ] ] |
5673 | |
5674 | attribute-list: |
5675 | attribute[opt] |
5676 | attribute-list, attribute[opt] |
5677 | |
5678 | attribute: |
5679 | attribute-token attribute-argument-clause[opt] |
5680 | |
5681 | attribute-token: |
5682 | standard-attribute |
5683 | attribute-prefixed-token |
5684 | |
5685 | standard-attribute: |
5686 | identifier |
5687 | |
5688 | attribute-prefixed-token: |
5689 | attribute-prefix :: identifier |
5690 | |
5691 | attribute-prefix: |
5692 | identifier |
5693 | |
5694 | attribute-argument-clause: |
5695 | ( balanced-token-sequence[opt] ) |
5696 | |
5697 | Keywords are accepted as identifiers for this purpose. |
5698 | |
5699 | As an extension, we permit an attribute-specifier to be: |
5700 | |
5701 | [ [ __extension__ attribute-list ] ] |
5702 | |
5703 | Two colons are then accepted as a synonym for ::. No attempt is made |
5704 | to check whether the colons are immediately adjacent. LOOSE_SCOPE_P |
5705 | indicates whether this relaxation is in effect. */ |
5706 | |
5707 | static tree |
5708 | c_parser_std_attribute (c_parser *parser, bool for_tm) |
5709 | { |
5710 | c_token *token = c_parser_peek_token (parser); |
5711 | tree ns, name, attribute; |
5712 | |
5713 | /* Parse the attribute-token. */ |
5714 | if (token->type != CPP_NAME && token->type != CPP_KEYWORD) |
5715 | { |
5716 | c_parser_error (parser, gmsgid: "expected identifier" ); |
5717 | return error_mark_node; |
5718 | } |
5719 | name = canonicalize_attr_name (attr_name: token->value); |
5720 | c_parser_consume_token (parser); |
5721 | if (c_parser_next_token_is (parser, type: CPP_SCOPE) |
5722 | || (c_parser_next_token_is (parser, type: CPP_COLON) |
5723 | && (c_parser_peek_token (parser)->flags & COLON_SCOPE) != 0 |
5724 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
5725 | { |
5726 | ns = name; |
5727 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
5728 | c_parser_consume_token (parser); |
5729 | c_parser_consume_token (parser); |
5730 | token = c_parser_peek_token (parser); |
5731 | if (token->type != CPP_NAME && token->type != CPP_KEYWORD) |
5732 | { |
5733 | c_parser_error (parser, gmsgid: "expected identifier" ); |
5734 | return error_mark_node; |
5735 | } |
5736 | name = canonicalize_attr_name (attr_name: token->value); |
5737 | c_parser_consume_token (parser); |
5738 | } |
5739 | else |
5740 | ns = NULL_TREE; |
5741 | attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE); |
5742 | |
5743 | /* Parse the arguments, if any. */ |
5744 | const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute)); |
5745 | if (c_parser_next_token_is_not (parser, type: CPP_OPEN_PAREN)) |
5746 | { |
5747 | if ((flag_openmp || flag_openmp_simd) |
5748 | && ns |
5749 | && is_attribute_p (attr_name: "omp" , ident: ns) |
5750 | && (is_attribute_p (attr_name: "directive" , ident: name) |
5751 | || is_attribute_p (attr_name: "sequence" , ident: name) |
5752 | || is_attribute_p (attr_name: "decl" , ident: name))) |
5753 | { |
5754 | error ("%<omp::%E%> attribute requires argument" , name); |
5755 | return error_mark_node; |
5756 | } |
5757 | goto out; |
5758 | } |
5759 | { |
5760 | location_t open_loc = c_parser_peek_token (parser)->location; |
5761 | matching_parens parens; |
5762 | parens.consume_open (parser); |
5763 | if ((as && as->max_length == 0) |
5764 | /* Special-case the transactional-memory attribute "outer", |
5765 | which is specially handled but not registered as an |
5766 | attribute, to avoid allowing arbitrary balanced token |
5767 | sequences as arguments. */ |
5768 | || is_attribute_p (attr_name: "outer" , ident: name)) |
5769 | { |
5770 | error_at (open_loc, "%qE attribute does not take any arguments" , name); |
5771 | parens.skip_until_found_close (parser); |
5772 | return error_mark_node; |
5773 | } |
5774 | /* If this is a fake attribute created to handle -Wno-attributes, |
5775 | we must skip parsing the arguments. */ |
5776 | if (as && !attribute_ignored_p (as)) |
5777 | { |
5778 | bool takes_identifier |
5779 | = (ns != NULL_TREE |
5780 | && strcmp (IDENTIFIER_POINTER (ns), s2: "gnu" ) == 0 |
5781 | && attribute_takes_identifier_p (name)); |
5782 | bool require_string |
5783 | = (ns == NULL_TREE |
5784 | && (strcmp (IDENTIFIER_POINTER (name), s2: "deprecated" ) == 0 |
5785 | || strcmp (IDENTIFIER_POINTER (name), s2: "nodiscard" ) == 0)); |
5786 | bool assume_attr |
5787 | = (ns != NULL_TREE |
5788 | && strcmp (IDENTIFIER_POINTER (ns), s2: "gnu" ) == 0 |
5789 | && strcmp (IDENTIFIER_POINTER (name), s2: "assume" ) == 0); |
5790 | TREE_VALUE (attribute) |
5791 | = c_parser_attribute_arguments (parser, takes_identifier, |
5792 | require_string, assume_attr, allow_empty_args: false); |
5793 | } |
5794 | else |
5795 | { |
5796 | if ((flag_openmp || flag_openmp_simd) |
5797 | && ns |
5798 | && is_attribute_p (attr_name: "omp" , ident: ns)) |
5799 | { |
5800 | if (is_attribute_p (attr_name: "directive" , ident: name)) |
5801 | { |
5802 | c_parser_omp_directive_args (parser, attribute, decl_p: false); |
5803 | parens.skip_until_found_close (parser); |
5804 | return attribute; |
5805 | } |
5806 | else if (is_attribute_p (attr_name: "decl" , ident: name)) |
5807 | { |
5808 | TREE_VALUE (TREE_PURPOSE (attribute)) |
5809 | = get_identifier ("directive" ); |
5810 | c_parser_omp_directive_args (parser, attribute, decl_p: true); |
5811 | parens.skip_until_found_close (parser); |
5812 | return attribute; |
5813 | } |
5814 | else if (is_attribute_p (attr_name: "sequence" , ident: name)) |
5815 | { |
5816 | TREE_VALUE (TREE_PURPOSE (attribute)) |
5817 | = get_identifier ("directive" ); |
5818 | c_parser_omp_sequence_args (parser, attribute); |
5819 | parens.skip_until_found_close (parser); |
5820 | TREE_VALUE (attribute) = nreverse (TREE_VALUE (attribute)); |
5821 | return attribute; |
5822 | } |
5823 | } |
5824 | c_parser_balanced_token_sequence (parser); |
5825 | } |
5826 | parens.require_close (parser); |
5827 | } |
5828 | out: |
5829 | if (ns == NULL_TREE && !for_tm && !as) |
5830 | { |
5831 | /* An attribute with standard syntax and no namespace specified |
5832 | is a constraint violation if it is not one of the known |
5833 | standard attributes. Diagnose it here with a pedwarn and |
5834 | then discard it to prevent a duplicate warning later. */ |
5835 | pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored" , |
5836 | name); |
5837 | return error_mark_node; |
5838 | } |
5839 | return attribute; |
5840 | } |
5841 | |
5842 | static tree |
5843 | c_parser_std_attribute_list (c_parser *parser, bool for_tm) |
5844 | { |
5845 | tree attributes = NULL_TREE; |
5846 | while (true) |
5847 | { |
5848 | c_token *token = c_parser_peek_token (parser); |
5849 | if (token->type == CPP_CLOSE_SQUARE) |
5850 | break; |
5851 | if (token->type == CPP_COMMA) |
5852 | { |
5853 | c_parser_consume_token (parser); |
5854 | continue; |
5855 | } |
5856 | tree attribute = c_parser_std_attribute (parser, for_tm); |
5857 | if (attribute != error_mark_node) |
5858 | { |
5859 | TREE_CHAIN (attribute) = attributes; |
5860 | attributes = attribute; |
5861 | } |
5862 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
5863 | break; |
5864 | } |
5865 | return attributes; |
5866 | } |
5867 | |
5868 | static tree |
5869 | c_parser_std_attribute_specifier (c_parser *parser, bool for_tm) |
5870 | { |
5871 | location_t loc = c_parser_peek_token (parser)->location; |
5872 | if (!c_parser_require (parser, type: CPP_OPEN_SQUARE, msgid: "expected %<[%>" )) |
5873 | return NULL_TREE; |
5874 | if (!c_parser_require (parser, type: CPP_OPEN_SQUARE, msgid: "expected %<[%>" )) |
5875 | { |
5876 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5877 | return NULL_TREE; |
5878 | } |
5879 | tree attributes; |
5880 | if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
5881 | { |
5882 | auto ext = disable_extension_diagnostics (); |
5883 | c_parser_consume_token (parser); |
5884 | attributes = c_parser_std_attribute_list (parser, for_tm); |
5885 | restore_extension_diagnostics (flags: ext); |
5886 | } |
5887 | else |
5888 | { |
5889 | if (!for_tm) |
5890 | pedwarn_c11 (loc, opt: OPT_Wpedantic, |
5891 | "ISO C does not support %<[[]]%> attributes before C23" ); |
5892 | attributes = c_parser_std_attribute_list (parser, for_tm); |
5893 | } |
5894 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5895 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, msgid: "expected %<]%>" ); |
5896 | return nreverse (attributes); |
5897 | } |
5898 | |
5899 | /* Look past an optional balanced token sequence of raw look-ahead |
5900 | tokens starting with the *Nth token. *N is updated to point to the |
5901 | following token. Return true if such a sequence was found, false |
5902 | if the tokens parsed were not balanced. */ |
5903 | |
5904 | static bool |
5905 | c_parser_check_balanced_raw_token_sequence (c_parser *parser, unsigned int *n) |
5906 | { |
5907 | while (true) |
5908 | { |
5909 | c_token *token = c_parser_peek_nth_token_raw (parser, n: *n); |
5910 | switch (token->type) |
5911 | { |
5912 | case CPP_OPEN_BRACE: |
5913 | { |
5914 | ++*n; |
5915 | if (c_parser_check_balanced_raw_token_sequence (parser, n)) |
5916 | { |
5917 | token = c_parser_peek_nth_token_raw (parser, n: *n); |
5918 | if (token->type == CPP_CLOSE_BRACE) |
5919 | ++*n; |
5920 | else |
5921 | return false; |
5922 | } |
5923 | else |
5924 | return false; |
5925 | break; |
5926 | } |
5927 | |
5928 | case CPP_OPEN_PAREN: |
5929 | { |
5930 | ++*n; |
5931 | if (c_parser_check_balanced_raw_token_sequence (parser, n)) |
5932 | { |
5933 | token = c_parser_peek_nth_token_raw (parser, n: *n); |
5934 | if (token->type == CPP_CLOSE_PAREN) |
5935 | ++*n; |
5936 | else |
5937 | return false; |
5938 | } |
5939 | else |
5940 | return false; |
5941 | break; |
5942 | } |
5943 | |
5944 | case CPP_OPEN_SQUARE: |
5945 | { |
5946 | ++*n; |
5947 | if (c_parser_check_balanced_raw_token_sequence (parser, n)) |
5948 | { |
5949 | token = c_parser_peek_nth_token_raw (parser, n: *n); |
5950 | if (token->type == CPP_CLOSE_SQUARE) |
5951 | ++*n; |
5952 | else |
5953 | return false; |
5954 | } |
5955 | else |
5956 | return false; |
5957 | break; |
5958 | } |
5959 | |
5960 | case CPP_CLOSE_BRACE: |
5961 | case CPP_CLOSE_PAREN: |
5962 | case CPP_CLOSE_SQUARE: |
5963 | case CPP_EOF: |
5964 | return true; |
5965 | |
5966 | default: |
5967 | ++*n; |
5968 | break; |
5969 | } |
5970 | } |
5971 | } |
5972 | |
5973 | /* Return whether standard attributes start with the Nth token. */ |
5974 | |
5975 | static bool |
5976 | c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n) |
5977 | { |
5978 | if (!(c_parser_peek_nth_token (parser, n)->type == CPP_OPEN_SQUARE |
5979 | && c_parser_peek_nth_token (parser, n: n + 1)->type == CPP_OPEN_SQUARE)) |
5980 | return false; |
5981 | /* In C, '[[' must start attributes. In Objective-C, we need to |
5982 | check whether '[[' is matched by ']]'. */ |
5983 | if (!c_dialect_objc ()) |
5984 | return true; |
5985 | n += 2; |
5986 | if (!c_parser_check_balanced_raw_token_sequence (parser, n: &n)) |
5987 | return false; |
5988 | c_token *token = c_parser_peek_nth_token_raw (parser, n); |
5989 | if (token->type != CPP_CLOSE_SQUARE) |
5990 | return false; |
5991 | token = c_parser_peek_nth_token_raw (parser, n: n + 1); |
5992 | return token->type == CPP_CLOSE_SQUARE; |
5993 | } |
5994 | |
5995 | static tree |
5996 | c_parser_std_attribute_specifier_sequence (c_parser *parser) |
5997 | { |
5998 | tree attributes = NULL_TREE; |
5999 | do |
6000 | { |
6001 | tree attrs = c_parser_std_attribute_specifier (parser, for_tm: false); |
6002 | attributes = chainon (attributes, attrs); |
6003 | } |
6004 | while (c_parser_nth_token_starts_std_attributes (parser, n: 1)); |
6005 | return attributes; |
6006 | } |
6007 | |
6008 | /* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). ALIGNAS_OK |
6009 | says whether alignment specifiers are OK (only in cases that might |
6010 | be the type name of a compound literal). |
6011 | |
6012 | type-name: |
6013 | specifier-qualifier-list abstract-declarator[opt] |
6014 | */ |
6015 | |
6016 | struct c_type_name * |
6017 | c_parser_type_name (c_parser *parser, bool alignas_ok) |
6018 | { |
6019 | struct c_declspecs *specs = build_null_declspecs (); |
6020 | struct c_declarator *declarator; |
6021 | struct c_type_name *ret; |
6022 | bool dummy = false; |
6023 | c_parser_declspecs (parser, specs, scspec_ok: false, typespec_ok: true, start_attr_ok: true, alignspec_ok: alignas_ok, auto_type_ok: false, |
6024 | start_std_attr_ok: false, end_std_attr_ok: true, la: cla_prefer_type); |
6025 | if (!specs->declspecs_seen_p) |
6026 | { |
6027 | c_parser_error (parser, gmsgid: "expected specifier-qualifier-list" ); |
6028 | return NULL; |
6029 | } |
6030 | if (specs->type != error_mark_node) |
6031 | { |
6032 | pending_xref_error (); |
6033 | finish_declspecs (specs); |
6034 | } |
6035 | declarator = c_parser_declarator (parser, |
6036 | type_seen_p: specs->typespec_kind != ctsk_none, |
6037 | kind: C_DTR_ABSTRACT, seen_id: &dummy); |
6038 | if (declarator == NULL) |
6039 | return NULL; |
6040 | ret = XOBNEW (&parser_obstack, struct c_type_name); |
6041 | ret->specs = specs; |
6042 | ret->declarator = declarator; |
6043 | return ret; |
6044 | } |
6045 | |
6046 | /* Parse an initializer (C90 6.5.7, C99 6.7.8, C11 6.7.9). |
6047 | |
6048 | initializer: |
6049 | assignment-expression |
6050 | { initializer-list } |
6051 | { initializer-list , } |
6052 | |
6053 | initializer-list: |
6054 | designation[opt] initializer |
6055 | initializer-list , designation[opt] initializer |
6056 | |
6057 | designation: |
6058 | designator-list = |
6059 | |
6060 | designator-list: |
6061 | designator |
6062 | designator-list designator |
6063 | |
6064 | designator: |
6065 | array-designator |
6066 | . identifier |
6067 | |
6068 | array-designator: |
6069 | [ constant-expression ] |
6070 | |
6071 | GNU extensions: |
6072 | |
6073 | initializer: |
6074 | { } |
6075 | |
6076 | designation: |
6077 | array-designator |
6078 | identifier : |
6079 | |
6080 | array-designator: |
6081 | [ constant-expression ... constant-expression ] |
6082 | |
6083 | Any expression without commas is accepted in the syntax for the |
6084 | constant-expressions, with non-constant expressions rejected later. |
6085 | |
6086 | DECL is the declaration we're parsing this initializer for. |
6087 | |
6088 | This function is only used for top-level initializers; for nested |
6089 | ones, see c_parser_initval. */ |
6090 | |
6091 | static struct c_expr |
6092 | c_parser_initializer (c_parser *parser, tree decl) |
6093 | { |
6094 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
6095 | return c_parser_braced_init (parser, NULL_TREE, false, NULL, decl); |
6096 | else |
6097 | { |
6098 | struct c_expr ret; |
6099 | location_t loc = c_parser_peek_token (parser)->location; |
6100 | ret = c_parser_expr_no_commas (parser, NULL); |
6101 | if (decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) |
6102 | { |
6103 | error_at (loc, |
6104 | "variable-sized object may not be initialized except " |
6105 | "with an empty initializer" ); |
6106 | ret.set_error (); |
6107 | } |
6108 | /* This is handled mostly by gimplify.cc, but we have to deal with |
6109 | not warning about int x = x; as it is a GCC extension to turn off |
6110 | this warning but only if warn_init_self is zero. */ |
6111 | if (VAR_P (decl) |
6112 | && !DECL_EXTERNAL (decl) |
6113 | && !TREE_STATIC (decl) |
6114 | && ret.value == decl |
6115 | && !warning_enabled_at (DECL_SOURCE_LOCATION (decl), opt: OPT_Winit_self)) |
6116 | suppress_warning (decl, OPT_Winit_self); |
6117 | if (TREE_CODE (ret.value) != STRING_CST |
6118 | && (TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR |
6119 | || C_DECL_DECLARED_CONSTEXPR (COMPOUND_LITERAL_EXPR_DECL |
6120 | (ret.value)))) |
6121 | ret = convert_lvalue_to_rvalue (loc, ret, true, true, true); |
6122 | return ret; |
6123 | } |
6124 | } |
6125 | |
6126 | /* The location of the last comma within the current initializer list, |
6127 | or UNKNOWN_LOCATION if not within one. */ |
6128 | |
6129 | location_t last_init_list_comma; |
6130 | |
6131 | /* Parse a braced initializer list. TYPE is the type specified for a |
6132 | compound literal, and NULL_TREE for other initializers and for |
6133 | nested braced lists. NESTED_P is true for nested braced lists, |
6134 | false for the list of a compound literal or the list that is the |
6135 | top-level initializer in a declaration. DECL is the declaration for |
6136 | the top-level initializer for a declaration, otherwise NULL_TREE. */ |
6137 | |
6138 | static struct c_expr |
6139 | c_parser_braced_init (c_parser *parser, tree type, bool nested_p, |
6140 | struct obstack *outer_obstack, tree decl) |
6141 | { |
6142 | struct c_expr ret; |
6143 | struct obstack braced_init_obstack; |
6144 | location_t brace_loc = c_parser_peek_token (parser)->location; |
6145 | gcc_obstack_init (&braced_init_obstack); |
6146 | gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); |
6147 | bool save_c_omp_array_section_p = c_omp_array_section_p; |
6148 | c_omp_array_section_p = false; |
6149 | matching_braces braces; |
6150 | braces.consume_open (parser); |
6151 | if (nested_p) |
6152 | { |
6153 | finish_implicit_inits (brace_loc, outer_obstack); |
6154 | push_init_level (brace_loc, 0, &braced_init_obstack); |
6155 | } |
6156 | else |
6157 | really_start_incremental_init (type); |
6158 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
6159 | { |
6160 | pedwarn_c11 (brace_loc, opt: OPT_Wpedantic, |
6161 | "ISO C forbids empty initializer braces before C23" ); |
6162 | } |
6163 | else |
6164 | { |
6165 | if (decl && decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) |
6166 | error_at (brace_loc, |
6167 | "variable-sized object may not be initialized except " |
6168 | "with an empty initializer" ); |
6169 | /* Parse a non-empty initializer list, possibly with a trailing |
6170 | comma. */ |
6171 | while (true) |
6172 | { |
6173 | c_parser_initelt (parser, &braced_init_obstack); |
6174 | if (parser->error) |
6175 | break; |
6176 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
6177 | { |
6178 | last_init_list_comma = c_parser_peek_token (parser)->location; |
6179 | c_parser_consume_token (parser); |
6180 | } |
6181 | else |
6182 | break; |
6183 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
6184 | break; |
6185 | } |
6186 | } |
6187 | c_omp_array_section_p = save_c_omp_array_section_p; |
6188 | c_token *next_tok = c_parser_peek_token (parser); |
6189 | if (next_tok->type != CPP_CLOSE_BRACE) |
6190 | { |
6191 | ret.set_error (); |
6192 | ret.original_code = ERROR_MARK; |
6193 | ret.original_type = NULL; |
6194 | braces.skip_until_found_close (parser); |
6195 | pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma); |
6196 | obstack_free (&braced_init_obstack, NULL); |
6197 | return ret; |
6198 | } |
6199 | location_t close_loc = next_tok->location; |
6200 | c_parser_consume_token (parser); |
6201 | ret = pop_init_level (brace_loc, 0, &braced_init_obstack, close_loc); |
6202 | obstack_free (&braced_init_obstack, NULL); |
6203 | set_c_expr_source_range (expr: &ret, start: brace_loc, finish: close_loc); |
6204 | return ret; |
6205 | } |
6206 | |
6207 | /* Parse a nested initializer, including designators. */ |
6208 | |
6209 | static void |
6210 | c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) |
6211 | { |
6212 | /* Parse any designator or designator list. A single array |
6213 | designator may have the subsequent "=" omitted in GNU C, but a |
6214 | longer list or a structure member designator may not. */ |
6215 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
6216 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
6217 | { |
6218 | /* Old-style structure member designator. */ |
6219 | set_init_label (c_parser_peek_token (parser)->location, |
6220 | c_parser_peek_token (parser)->value, |
6221 | c_parser_peek_token (parser)->location, |
6222 | braced_init_obstack); |
6223 | /* Use the colon as the error location. */ |
6224 | pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, |
6225 | "obsolete use of designated initializer with %<:%>" ); |
6226 | c_parser_consume_token (parser); |
6227 | c_parser_consume_token (parser); |
6228 | } |
6229 | else |
6230 | { |
6231 | /* des_seen is 0 if there have been no designators, 1 if there |
6232 | has been a single array designator and 2 otherwise. */ |
6233 | int des_seen = 0; |
6234 | /* Location of a designator. */ |
6235 | location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
6236 | while (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE) |
6237 | || c_parser_next_token_is (parser, type: CPP_DOT)) |
6238 | { |
6239 | int des_prev = des_seen; |
6240 | if (!des_seen) |
6241 | des_loc = c_parser_peek_token (parser)->location; |
6242 | if (des_seen < 2) |
6243 | des_seen++; |
6244 | if (c_parser_next_token_is (parser, type: CPP_DOT)) |
6245 | { |
6246 | des_seen = 2; |
6247 | c_parser_consume_token (parser); |
6248 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
6249 | { |
6250 | set_init_label (des_loc, c_parser_peek_token (parser)->value, |
6251 | c_parser_peek_token (parser)->location, |
6252 | braced_init_obstack); |
6253 | c_parser_consume_token (parser); |
6254 | } |
6255 | else |
6256 | { |
6257 | struct c_expr init; |
6258 | init.set_error (); |
6259 | init.original_code = ERROR_MARK; |
6260 | init.original_type = NULL; |
6261 | c_parser_error (parser, gmsgid: "expected identifier" ); |
6262 | c_parser_skip_until_found (parser, type: CPP_COMMA, NULL); |
6263 | process_init_element (input_location, init, false, |
6264 | braced_init_obstack); |
6265 | return; |
6266 | } |
6267 | } |
6268 | else |
6269 | { |
6270 | struct c_expr first_expr; |
6271 | tree first, second; |
6272 | location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
6273 | location_t array_index_loc = UNKNOWN_LOCATION; |
6274 | /* ??? Following the old parser, [ objc-receiver |
6275 | objc-message-args ] is accepted as an initializer, |
6276 | being distinguished from a designator by what follows |
6277 | the first assignment expression inside the square |
6278 | brackets, but after a first array designator a |
6279 | subsequent square bracket is for Objective-C taken to |
6280 | start an expression, using the obsolete form of |
6281 | designated initializer without '=', rather than |
6282 | possibly being a second level of designation: in LALR |
6283 | terms, the '[' is shifted rather than reducing |
6284 | designator to designator-list. */ |
6285 | if (des_prev == 1 && c_dialect_objc ()) |
6286 | { |
6287 | des_seen = des_prev; |
6288 | break; |
6289 | } |
6290 | if (des_prev == 0 && c_dialect_objc ()) |
6291 | { |
6292 | /* This might be an array designator or an |
6293 | Objective-C message expression. If the former, |
6294 | continue parsing here; if the latter, parse the |
6295 | remainder of the initializer given the starting |
6296 | primary-expression. ??? It might make sense to |
6297 | distinguish when des_prev == 1 as well; see |
6298 | previous comment. */ |
6299 | tree rec, args; |
6300 | struct c_expr mexpr; |
6301 | c_parser_consume_token (parser); |
6302 | if (c_parser_peek_token (parser)->type == CPP_NAME |
6303 | && ((c_parser_peek_token (parser)->id_kind |
6304 | == C_ID_TYPENAME) |
6305 | || (c_parser_peek_token (parser)->id_kind |
6306 | == C_ID_CLASSNAME))) |
6307 | { |
6308 | /* Type name receiver. */ |
6309 | tree id = c_parser_peek_token (parser)->value; |
6310 | c_parser_consume_token (parser); |
6311 | rec = objc_get_class_reference (id); |
6312 | goto parse_message_args; |
6313 | } |
6314 | array_index_loc = c_parser_peek_token (parser)->location; |
6315 | first_expr = c_parser_expr_no_commas (parser, NULL); |
6316 | mark_exp_read (first_expr.value); |
6317 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS) |
6318 | || c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
6319 | goto array_desig_after_first; |
6320 | first = first_expr.value; |
6321 | /* Expression receiver. So far only one part |
6322 | without commas has been parsed; there might be |
6323 | more of the expression. */ |
6324 | rec = first; |
6325 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
6326 | { |
6327 | struct c_expr next; |
6328 | location_t comma_loc, exp_loc; |
6329 | comma_loc = c_parser_peek_token (parser)->location; |
6330 | c_parser_consume_token (parser); |
6331 | exp_loc = c_parser_peek_token (parser)->location; |
6332 | next = c_parser_expr_no_commas (parser, NULL); |
6333 | next = convert_lvalue_to_rvalue (exp_loc, next, |
6334 | true, true); |
6335 | rec = build_compound_expr (comma_loc, rec, next.value); |
6336 | } |
6337 | parse_message_args: |
6338 | /* Now parse the objc-message-args. */ |
6339 | args = c_parser_objc_message_args (parser); |
6340 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
6341 | msgid: "expected %<]%>" ); |
6342 | mexpr.value |
6343 | = objc_build_message_expr (rec, args); |
6344 | mexpr.original_code = ERROR_MARK; |
6345 | mexpr.original_type = NULL; |
6346 | mexpr.m_decimal = 0; |
6347 | /* Now parse and process the remainder of the |
6348 | initializer, starting with this message |
6349 | expression as a primary-expression. */ |
6350 | c_parser_initval (parser, &mexpr, braced_init_obstack); |
6351 | return; |
6352 | } |
6353 | c_parser_consume_token (parser); |
6354 | array_index_loc = c_parser_peek_token (parser)->location; |
6355 | first_expr = c_parser_expr_no_commas (parser, NULL); |
6356 | mark_exp_read (first_expr.value); |
6357 | array_desig_after_first: |
6358 | first_expr = convert_lvalue_to_rvalue (array_index_loc, |
6359 | first_expr, |
6360 | true, true); |
6361 | first = first_expr.value; |
6362 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
6363 | { |
6364 | ellipsis_loc = c_parser_peek_token (parser)->location; |
6365 | c_parser_consume_token (parser); |
6366 | second = convert_lvalue_to_rvalue (ellipsis_loc, |
6367 | (c_parser_expr_no_commas |
6368 | (parser, NULL)), |
6369 | true, true).value; |
6370 | mark_exp_read (second); |
6371 | } |
6372 | else |
6373 | second = NULL_TREE; |
6374 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
6375 | { |
6376 | c_parser_consume_token (parser); |
6377 | set_init_index (array_index_loc, first, second, |
6378 | braced_init_obstack); |
6379 | if (second) |
6380 | pedwarn (ellipsis_loc, OPT_Wpedantic, |
6381 | "ISO C forbids specifying range of elements to initialize" ); |
6382 | } |
6383 | else |
6384 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
6385 | msgid: "expected %<]%>" ); |
6386 | } |
6387 | } |
6388 | if (des_seen >= 1) |
6389 | { |
6390 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
6391 | { |
6392 | pedwarn_c90 (des_loc, opt: OPT_Wpedantic, |
6393 | "ISO C90 forbids specifying subobject " |
6394 | "to initialize" ); |
6395 | c_parser_consume_token (parser); |
6396 | } |
6397 | else |
6398 | { |
6399 | if (des_seen == 1) |
6400 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
6401 | "obsolete use of designated initializer without %<=%>" ); |
6402 | else |
6403 | { |
6404 | struct c_expr init; |
6405 | init.set_error (); |
6406 | init.original_code = ERROR_MARK; |
6407 | init.original_type = NULL; |
6408 | c_parser_error (parser, gmsgid: "expected %<=%>" ); |
6409 | c_parser_skip_until_found (parser, type: CPP_COMMA, NULL); |
6410 | process_init_element (input_location, init, false, |
6411 | braced_init_obstack); |
6412 | return; |
6413 | } |
6414 | } |
6415 | } |
6416 | } |
6417 | c_parser_initval (parser, NULL, braced_init_obstack); |
6418 | } |
6419 | |
6420 | /* Parse a nested initializer; as c_parser_initializer but parses |
6421 | initializers within braced lists, after any designators have been |
6422 | applied. If AFTER is not NULL then it is an Objective-C message |
6423 | expression which is the primary-expression starting the |
6424 | initializer. */ |
6425 | |
6426 | static void |
6427 | c_parser_initval (c_parser *parser, struct c_expr *after, |
6428 | struct obstack * braced_init_obstack) |
6429 | { |
6430 | struct c_expr init; |
6431 | gcc_assert (!after || c_dialect_objc ()); |
6432 | location_t loc = c_parser_peek_token (parser)->location; |
6433 | |
6434 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE) && !after) |
6435 | init = c_parser_braced_init (parser, NULL_TREE, nested_p: true, |
6436 | outer_obstack: braced_init_obstack, NULL_TREE); |
6437 | else |
6438 | { |
6439 | init = c_parser_expr_no_commas (parser, after); |
6440 | if (init.value != NULL_TREE |
6441 | && TREE_CODE (init.value) != STRING_CST |
6442 | && (TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR |
6443 | || C_DECL_DECLARED_CONSTEXPR (COMPOUND_LITERAL_EXPR_DECL |
6444 | (init.value)))) |
6445 | init = convert_lvalue_to_rvalue (loc, init, true, true, true); |
6446 | } |
6447 | process_init_element (loc, init, false, braced_init_obstack); |
6448 | } |
6449 | |
6450 | /* Parse a compound statement (possibly a function body) (C90 6.6.2, |
6451 | C99 6.8.2, C11 6.8.2, C23 6.8.2). |
6452 | |
6453 | compound-statement: |
6454 | { block-item-list[opt] } |
6455 | { label-declarations block-item-list } |
6456 | |
6457 | block-item-list: |
6458 | block-item |
6459 | block-item-list block-item |
6460 | |
6461 | block-item: |
6462 | label |
6463 | nested-declaration |
6464 | statement |
6465 | |
6466 | nested-declaration: |
6467 | declaration |
6468 | |
6469 | GNU extensions: |
6470 | |
6471 | compound-statement: |
6472 | { label-declarations block-item-list } |
6473 | |
6474 | nested-declaration: |
6475 | __extension__ nested-declaration |
6476 | nested-function-definition |
6477 | |
6478 | label-declarations: |
6479 | label-declaration |
6480 | label-declarations label-declaration |
6481 | |
6482 | label-declaration: |
6483 | __label__ identifier-list ; |
6484 | |
6485 | Allowing the mixing of declarations and code is new in C99. The |
6486 | GNU syntax also permits (not shown above) labels at the end of |
6487 | compound statements, which yield an error. We don't allow labels |
6488 | on declarations; this might seem like a natural extension, but |
6489 | there would be a conflict between gnu-attributes on the label and |
6490 | prefix gnu-attributes on the declaration. ??? The syntax follows the |
6491 | old parser in requiring something after label declarations. |
6492 | Although they are erroneous if the labels declared aren't defined, |
6493 | is it useful for the syntax to be this way? |
6494 | |
6495 | OpenACC: |
6496 | |
6497 | block-item: |
6498 | openacc-directive |
6499 | |
6500 | openacc-directive: |
6501 | update-directive |
6502 | |
6503 | OpenMP: |
6504 | |
6505 | block-item: |
6506 | openmp-directive |
6507 | |
6508 | openmp-directive: |
6509 | barrier-directive |
6510 | flush-directive |
6511 | taskwait-directive |
6512 | taskyield-directive |
6513 | cancel-directive |
6514 | cancellation-point-directive */ |
6515 | |
6516 | static tree |
6517 | c_parser_compound_statement (c_parser *parser, location_t *endlocp) |
6518 | { |
6519 | tree stmt; |
6520 | location_t brace_loc; |
6521 | brace_loc = c_parser_peek_token (parser)->location; |
6522 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
6523 | { |
6524 | /* Ensure a scope is entered and left anyway to avoid confusion |
6525 | if we have just prepared to enter a function body. */ |
6526 | stmt = c_begin_compound_stmt (true); |
6527 | c_end_compound_stmt (brace_loc, stmt, true); |
6528 | return error_mark_node; |
6529 | } |
6530 | stmt = c_begin_compound_stmt (true); |
6531 | location_t end_loc = c_parser_compound_statement_nostart (parser); |
6532 | if (endlocp) |
6533 | *endlocp = end_loc; |
6534 | |
6535 | return c_end_compound_stmt (brace_loc, stmt, true); |
6536 | } |
6537 | |
6538 | /* Diagnose errors related to imperfectly nested loops in an OMP |
6539 | loop construct. This function is called when such code is seen. |
6540 | Only issue one such diagnostic no matter how much invalid |
6541 | intervening code there is in the loop. |
6542 | FIXME: maybe the location associated with the diagnostic should |
6543 | be the current parser token instead of the location of the outer loop |
6544 | nest. */ |
6545 | |
6546 | static void |
6547 | check_omp_intervening_code (c_parser *parser) |
6548 | { |
6549 | struct omp_for_parse_data *omp_for_parse_state = parser->omp_for_parse_state; |
6550 | gcc_assert (omp_for_parse_state); |
6551 | |
6552 | if (!omp_for_parse_state->in_intervening_code) |
6553 | return; |
6554 | omp_for_parse_state->saw_intervening_code = true; |
6555 | |
6556 | /* Only diagnose errors related to perfect nesting once. */ |
6557 | if (!omp_for_parse_state->perfect_nesting_fail) |
6558 | { |
6559 | |
6560 | /* OpenACC does not (yet) permit intervening code, in |
6561 | addition to situations forbidden by the OpenMP spec. */ |
6562 | if (omp_for_parse_state->code == OACC_LOOP) |
6563 | { |
6564 | error_at (omp_for_parse_state->for_loc, |
6565 | "inner loops must be perfectly nested in " |
6566 | "%<#pragma acc loop%>" ); |
6567 | omp_for_parse_state->perfect_nesting_fail = true; |
6568 | } |
6569 | else if (omp_for_parse_state->ordered) |
6570 | { |
6571 | error_at (omp_for_parse_state->for_loc, |
6572 | "inner loops must be perfectly nested with " |
6573 | "%<ordered%> clause" ); |
6574 | omp_for_parse_state->perfect_nesting_fail = true; |
6575 | } |
6576 | else if (omp_for_parse_state->inscan) |
6577 | { |
6578 | error_at (omp_for_parse_state->for_loc, |
6579 | "inner loops must be perfectly nested with " |
6580 | "%<reduction%> %<inscan%> clause" ); |
6581 | omp_for_parse_state->perfect_nesting_fail = true; |
6582 | } |
6583 | /* TODO: Also reject loops with TILE directive. */ |
6584 | if (omp_for_parse_state->perfect_nesting_fail) |
6585 | omp_for_parse_state->fail = true; |
6586 | } |
6587 | } |
6588 | |
6589 | /* Helper function for below: wrap an OMP_STRUCTURED_BLOCK around SL |
6590 | and add the statement to the current list. If SL is an empty statement |
6591 | list, do nothing. */ |
6592 | static void |
6593 | add_structured_block_stmt (tree sl) |
6594 | { |
6595 | if (TREE_CODE (sl) != STATEMENT_LIST |
6596 | || !tsi_end_p (i: tsi_start (t: sl))) |
6597 | add_stmt (build1 (OMP_STRUCTURED_BLOCK, void_type_node, sl)); |
6598 | } |
6599 | |
6600 | struct c_omp_attribute_data |
6601 | { |
6602 | vec<c_token, va_gc> *tokens; |
6603 | const c_omp_directive *dir; |
6604 | c_omp_directive_kind kind; |
6605 | }; |
6606 | |
6607 | /* Handle omp::directive and omp::sequence attributes in ATTRS |
6608 | (if any) at the start of a statement or in attribute-declaration. */ |
6609 | |
6610 | static bool |
6611 | c_parser_handle_statement_omp_attributes (c_parser *parser, tree &attrs, |
6612 | bool *have_std_attrs) |
6613 | { |
6614 | if (!flag_openmp && !flag_openmp_simd) |
6615 | return false; |
6616 | |
6617 | auto_vec<c_omp_attribute_data, 16> vd; |
6618 | int cnt = 0; |
6619 | int tokens = 0; |
6620 | bool bad = false; |
6621 | for (tree *pa = &attrs; *pa; ) |
6622 | if (is_attribute_namespace_p (attr_ns: "omp" , attr: *pa) |
6623 | && is_attribute_p (attr_name: "directive" , ident: get_attribute_name (*pa))) |
6624 | { |
6625 | cnt++; |
6626 | for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) |
6627 | { |
6628 | tree d = TREE_VALUE (a); |
6629 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
6630 | vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d); |
6631 | c_token *first = toks->address (); |
6632 | c_token *last = first + toks->length (); |
6633 | if (parser->omp_attrs_forbidden_p) |
6634 | { |
6635 | error_at (first->location, |
6636 | "mixing OpenMP directives with attribute and pragma " |
6637 | "syntax on the same statement" ); |
6638 | parser->omp_attrs_forbidden_p = false; |
6639 | bad = true; |
6640 | } |
6641 | else if (TREE_PUBLIC (d)) |
6642 | { |
6643 | error_at (first->location, |
6644 | "OpenMP %<omp::decl%> attribute on a statement" ); |
6645 | bad = true; |
6646 | } |
6647 | const char *directive[3] = {}; |
6648 | for (int i = 0; i < 3; i++) |
6649 | { |
6650 | tree id = NULL_TREE; |
6651 | if (first + i == last) |
6652 | break; |
6653 | if (first[i].type == CPP_NAME) |
6654 | id = first[i].value; |
6655 | else if (first[i].type == CPP_KEYWORD) |
6656 | id = ridpointers[(int) first[i].keyword]; |
6657 | else |
6658 | break; |
6659 | directive[i] = IDENTIFIER_POINTER (id); |
6660 | } |
6661 | const c_omp_directive *dir = NULL; |
6662 | if (directive[0]) |
6663 | dir = c_omp_categorize_directive (directive[0], directive[1], |
6664 | directive[2]); |
6665 | if (dir == NULL) |
6666 | { |
6667 | error_at (first->location, |
6668 | "unknown OpenMP directive name in %qs attribute " |
6669 | "argument" , |
6670 | TREE_PUBLIC (d) ? "omp::decl" : "omp::directive" ); |
6671 | continue; |
6672 | } |
6673 | c_omp_directive_kind kind = dir->kind; |
6674 | if (dir->id == PRAGMA_OMP_ORDERED) |
6675 | { |
6676 | /* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain |
6677 | depend/doacross clause. */ |
6678 | if (directive[1] |
6679 | && (strcmp (s1: directive[1], s2: "depend" ) == 0 |
6680 | || strcmp (s1: directive[1], s2: "doacross" ) == 0)) |
6681 | kind = C_OMP_DIR_STANDALONE; |
6682 | else if (first + 2 < last |
6683 | && first[1].type == CPP_COMMA |
6684 | && first[2].type == CPP_NAME |
6685 | && (strcmp (IDENTIFIER_POINTER (first[2].value), |
6686 | s2: "depend" ) == 0 |
6687 | || strcmp (IDENTIFIER_POINTER (first[2].value), |
6688 | s2: "doacross" ) == 0)) |
6689 | kind = C_OMP_DIR_STANDALONE; |
6690 | } |
6691 | else if (dir->id == PRAGMA_OMP_ERROR) |
6692 | { |
6693 | /* error with at(execution) clause is C_OMP_DIR_STANDALONE. */ |
6694 | int paren_depth = 0; |
6695 | for (int i = 1; first + i < last; i++) |
6696 | if (first[i].type == CPP_OPEN_PAREN) |
6697 | paren_depth++; |
6698 | else if (first[i].type == CPP_CLOSE_PAREN) |
6699 | paren_depth--; |
6700 | else if (paren_depth == 0 |
6701 | && first + i + 2 < last |
6702 | && first[i].type == CPP_NAME |
6703 | && first[i + 1].type == CPP_OPEN_PAREN |
6704 | && first[i + 2].type == CPP_NAME |
6705 | && !strcmp (IDENTIFIER_POINTER (first[i].value), |
6706 | s2: "at" ) |
6707 | && !strcmp (IDENTIFIER_POINTER (first[i |
6708 | + 2].value), |
6709 | s2: "execution" )) |
6710 | { |
6711 | kind = C_OMP_DIR_STANDALONE; |
6712 | break; |
6713 | } |
6714 | } |
6715 | c_omp_attribute_data v = { .tokens: toks, .dir: dir, .kind: kind }; |
6716 | vd.safe_push (obj: v); |
6717 | if (flag_openmp || dir->simd) |
6718 | tokens += (last - first) + 1; |
6719 | } |
6720 | c_omp_attribute_data v = {}; |
6721 | vd.safe_push (obj: v); |
6722 | *pa = TREE_CHAIN (*pa); |
6723 | } |
6724 | else |
6725 | pa = &TREE_CHAIN (*pa); |
6726 | |
6727 | if (bad) |
6728 | { |
6729 | fail: |
6730 | if (have_std_attrs && attrs == NULL) |
6731 | *have_std_attrs = false; |
6732 | return false; |
6733 | } |
6734 | |
6735 | unsigned int i; |
6736 | c_omp_attribute_data *v; |
6737 | c_omp_attribute_data *construct_seen = nullptr; |
6738 | c_omp_attribute_data *standalone_seen = nullptr; |
6739 | c_omp_attribute_data *prev_standalone_seen = nullptr; |
6740 | FOR_EACH_VEC_ELT (vd, i, v) |
6741 | if (v->tokens) |
6742 | { |
6743 | if (v->kind == C_OMP_DIR_CONSTRUCT && !construct_seen) |
6744 | construct_seen = v; |
6745 | else if (v->kind == C_OMP_DIR_STANDALONE && !standalone_seen) |
6746 | standalone_seen = v; |
6747 | } |
6748 | else |
6749 | { |
6750 | if (standalone_seen && !prev_standalone_seen) |
6751 | { |
6752 | prev_standalone_seen = standalone_seen; |
6753 | standalone_seen = nullptr; |
6754 | } |
6755 | } |
6756 | |
6757 | if (cnt > 1 && construct_seen) |
6758 | { |
6759 | error_at ((*construct_seen->tokens)[0].location, |
6760 | "OpenMP construct among %<omp::directive%> attributes" |
6761 | " requires all %<omp::directive%> attributes on the" |
6762 | " same statement to be in the same %<omp::sequence%>" ); |
6763 | goto fail; |
6764 | } |
6765 | if (cnt > 1 && standalone_seen && prev_standalone_seen) |
6766 | { |
6767 | error_at ((*standalone_seen->tokens)[0].location, |
6768 | "multiple OpenMP standalone directives among" |
6769 | " %<omp::directive%> attributes must be all within the" |
6770 | " same %<omp::sequence%>" ); |
6771 | goto fail; |
6772 | } |
6773 | |
6774 | if (prev_standalone_seen) |
6775 | standalone_seen = prev_standalone_seen; |
6776 | if (standalone_seen |
6777 | && !c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
6778 | { |
6779 | error_at (standalone_seen->tokens->address ()->location, |
6780 | "standalone OpenMP directives in %<omp::directive%> attribute" |
6781 | " can only appear on an empty statement" ); |
6782 | goto fail; |
6783 | } |
6784 | if (cnt && c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
6785 | { |
6786 | c_token *token = c_parser_peek_token (parser); |
6787 | enum pragma_kind kind = token->pragma_kind; |
6788 | if (kind >= PRAGMA_OMP__START_ && kind <= PRAGMA_OMP__LAST_) |
6789 | { |
6790 | error_at (token->location, |
6791 | "mixing OpenMP directives with attribute and pragma " |
6792 | "syntax on the same statement" ); |
6793 | goto fail; |
6794 | } |
6795 | } |
6796 | |
6797 | if (!tokens) |
6798 | return false; |
6799 | |
6800 | unsigned int tokens_avail = parser->tokens_avail; |
6801 | gcc_assert (parser->tokens == &parser->tokens_buf[0]); |
6802 | |
6803 | tokens++; |
6804 | vec<c_token, va_gc> *toks = NULL; |
6805 | vec_safe_reserve (v&: toks, nelems: tokens, exact: true); |
6806 | FOR_EACH_VEC_ELT (vd, i, v) |
6807 | { |
6808 | if (!v->tokens) |
6809 | continue; |
6810 | if (!flag_openmp && !v->dir->simd) |
6811 | continue; |
6812 | c_token *first = v->tokens->address (); |
6813 | c_token *last = first + v->tokens->length (); |
6814 | c_token tok = {}; |
6815 | tok.type = CPP_PRAGMA; |
6816 | tok.keyword = RID_MAX; |
6817 | tok.pragma_kind = pragma_kind (v->dir->id); |
6818 | tok.location = first->location; |
6819 | toks->quick_push (obj: tok); |
6820 | while (++first < last) |
6821 | toks->quick_push (obj: *first); |
6822 | tok = {}; |
6823 | tok.type = CPP_PRAGMA_EOL; |
6824 | tok.keyword = RID_MAX; |
6825 | tok.location = last[-1].location; |
6826 | toks->quick_push (obj: tok); |
6827 | } |
6828 | |
6829 | c_token tok = {}; |
6830 | tok.type = CPP_EOF; |
6831 | tok.keyword = RID_MAX; |
6832 | tok.location = toks->last ().location; |
6833 | tok.flags = tokens_avail; |
6834 | toks->quick_push (obj: tok); |
6835 | |
6836 | parser->tokens = toks->address (); |
6837 | parser->tokens_avail = tokens; |
6838 | parser->in_omp_attribute_pragma = toks; |
6839 | return true; |
6840 | } |
6841 | |
6842 | /* Handle omp::directive and omp::sequence attributes in ATTRS |
6843 | (if any) at the start or after declaration-id of a declaration. */ |
6844 | |
6845 | static void |
6846 | c_parser_handle_directive_omp_attributes (tree &attrs, |
6847 | vec<c_token> *&pragma_clauses, |
6848 | vec<c_token> *attr_clauses) |
6849 | { |
6850 | if (!flag_openmp && !flag_openmp_simd) |
6851 | return; |
6852 | |
6853 | for (tree *pa = &attrs; *pa; ) |
6854 | if (is_attribute_namespace_p (attr_ns: "omp" , attr: *pa) |
6855 | && is_attribute_p (attr_name: "directive" , ident: get_attribute_name (*pa))) |
6856 | { |
6857 | int cnt = 0; |
6858 | for (tree *pa2 = &TREE_VALUE (*pa); *pa2; ) |
6859 | { |
6860 | tree a = *pa2; |
6861 | tree d = TREE_VALUE (a); |
6862 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
6863 | vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d); |
6864 | c_token *first = toks->address (); |
6865 | c_token *last = first + toks->length (); |
6866 | const char *directive[3] = {}; |
6867 | for (int i = 0; i < 3; i++) |
6868 | { |
6869 | tree id = NULL_TREE; |
6870 | if (first + i == last) |
6871 | break; |
6872 | if (first[i].type == CPP_NAME) |
6873 | id = first[i].value; |
6874 | else if (first[i].type == CPP_KEYWORD) |
6875 | id = ridpointers[(int) first[i].keyword]; |
6876 | else |
6877 | break; |
6878 | directive[i] = IDENTIFIER_POINTER (id); |
6879 | } |
6880 | const c_omp_directive *dir = NULL; |
6881 | if (directive[0]) |
6882 | dir = c_omp_categorize_directive (directive[0], directive[1], |
6883 | directive[2]); |
6884 | if (dir == NULL) |
6885 | { |
6886 | error_at (first->location, |
6887 | "unknown OpenMP directive name in " |
6888 | "%qs attribute argument" , |
6889 | TREE_PUBLIC (d) ? "omp::decl" : "omp::directive" ); |
6890 | *pa2 = TREE_CHAIN (a); |
6891 | } |
6892 | else if (dir->id == PRAGMA_OMP_DECLARE |
6893 | && (strcmp (s1: directive[1], s2: "simd" ) == 0 |
6894 | || strcmp (s1: directive[1], s2: "variant" ) == 0)) |
6895 | { |
6896 | if (pragma_clauses) |
6897 | { |
6898 | error_at (first->location, |
6899 | "mixing OpenMP directives with attribute and " |
6900 | "pragma syntax on the same declaration" ); |
6901 | for (pa = &attrs; *pa; ) |
6902 | if (is_attribute_namespace_p (attr_ns: "omp" , attr: *pa) |
6903 | && is_attribute_p (attr_name: "directive" , |
6904 | ident: get_attribute_name (*pa))) |
6905 | *pa = TREE_CHAIN (*pa); |
6906 | else |
6907 | pa = &TREE_CHAIN (*pa); |
6908 | return; |
6909 | } |
6910 | ++cnt; |
6911 | attr_clauses->reserve (nelems: attr_clauses->length () |
6912 | + toks->length () + 2); |
6913 | for (++first; first < last; ++first) |
6914 | attr_clauses->quick_push (obj: *first); |
6915 | c_token tok = {}; |
6916 | tok.type = CPP_PRAGMA_EOL; |
6917 | tok.keyword = RID_MAX; |
6918 | tok.location = last[-1].location; |
6919 | attr_clauses->quick_push (obj: tok); |
6920 | *pa2 = TREE_CHAIN (a); |
6921 | } |
6922 | else |
6923 | pa2 = &TREE_CHAIN (a); |
6924 | } |
6925 | if (cnt && TREE_VALUE (*pa) == NULL_TREE) |
6926 | *pa = TREE_CHAIN (*pa); |
6927 | else |
6928 | pa = &TREE_CHAIN (*pa); |
6929 | } |
6930 | else |
6931 | pa = &TREE_CHAIN (*pa); |
6932 | if (attr_clauses->length ()) |
6933 | { |
6934 | c_token tok = {}; |
6935 | tok.type = CPP_EOF; |
6936 | tok.keyword = RID_MAX; |
6937 | tok.location = attr_clauses->last ().location; |
6938 | attr_clauses->quick_push (obj: tok); |
6939 | attr_clauses->quick_push (obj: tok); |
6940 | pragma_clauses = attr_clauses; |
6941 | } |
6942 | } |
6943 | |
6944 | /* Parse a compound statement except for the opening brace. This is |
6945 | used for parsing both compound statements and statement expressions |
6946 | (which follow different paths to handling the opening). */ |
6947 | |
6948 | static location_t |
6949 | c_parser_compound_statement_nostart (c_parser *parser) |
6950 | { |
6951 | bool last_stmt = false; |
6952 | bool last_label = false; |
6953 | bool save_valid_for_pragma = valid_location_for_stdc_pragma_p (); |
6954 | location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
6955 | struct omp_for_parse_data *omp_for_parse_state |
6956 | = parser->omp_for_parse_state; |
6957 | bool in_omp_loop_block |
6958 | = omp_for_parse_state ? omp_for_parse_state->want_nested_loop : false; |
6959 | tree sl = NULL_TREE; |
6960 | |
6961 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
6962 | { |
6963 | location_t endloc = c_parser_peek_token (parser)->location; |
6964 | add_debug_begin_stmt (loc: endloc); |
6965 | c_parser_consume_token (parser); |
6966 | return endloc; |
6967 | } |
6968 | |
6969 | /* If we're parsing a {} sequence in an OMP_FOR body, start a |
6970 | statement list for intervening code. */ |
6971 | if (in_omp_loop_block) |
6972 | sl = push_stmt_list (); |
6973 | |
6974 | mark_valid_location_for_stdc_pragma (true); |
6975 | if (c_parser_next_token_is_keyword (parser, keyword: RID_LABEL)) |
6976 | { |
6977 | /* Read zero or more forward-declarations for labels that nested |
6978 | functions can jump to. */ |
6979 | mark_valid_location_for_stdc_pragma (false); |
6980 | if (in_omp_loop_block) |
6981 | check_omp_intervening_code (parser); |
6982 | while (c_parser_next_token_is_keyword (parser, keyword: RID_LABEL)) |
6983 | { |
6984 | label_loc = c_parser_peek_token (parser)->location; |
6985 | c_parser_consume_token (parser); |
6986 | /* Any identifiers, including those declared as type names, |
6987 | are OK here. */ |
6988 | while (true) |
6989 | { |
6990 | tree label; |
6991 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
6992 | { |
6993 | c_parser_error (parser, gmsgid: "expected identifier" ); |
6994 | break; |
6995 | } |
6996 | label |
6997 | = declare_label (c_parser_peek_token (parser)->value); |
6998 | C_DECLARED_LABEL_FLAG (label) = 1; |
6999 | add_stmt (build_stmt (label_loc, DECL_EXPR, label)); |
7000 | c_parser_consume_token (parser); |
7001 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
7002 | c_parser_consume_token (parser); |
7003 | else |
7004 | break; |
7005 | } |
7006 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
7007 | } |
7008 | pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations" ); |
7009 | } |
7010 | /* We must now have at least one statement, label or declaration. */ |
7011 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
7012 | { |
7013 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7014 | c_parser_error (parser, gmsgid: "expected declaration or statement" ); |
7015 | location_t endloc = c_parser_peek_token (parser)->location; |
7016 | c_parser_consume_token (parser); |
7017 | return endloc; |
7018 | } |
7019 | while (c_parser_next_token_is_not (parser, type: CPP_CLOSE_BRACE)) |
7020 | { |
7021 | location_t loc = c_parser_peek_token (parser)->location; |
7022 | loc = expansion_point_location_if_in_system_header (loc); |
7023 | |
7024 | bool want_nested_loop = (omp_for_parse_state |
7025 | ? omp_for_parse_state->want_nested_loop |
7026 | : false); |
7027 | |
7028 | /* First take care of special cases for OpenMP "canonical loop |
7029 | nest form", that do not allow standard attributes, labels, or |
7030 | __extension__ before the nested statement. */ |
7031 | if (in_omp_loop_block && !last_label) |
7032 | { |
7033 | if (want_nested_loop |
7034 | && c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
7035 | { |
7036 | /* Found the next nested loop. If there were intervening |
7037 | code statements collected before now, wrap them in an |
7038 | OMP_STRUCTURED_BLOCK node, and start a new structured |
7039 | block to hold statements that may come after the FOR. */ |
7040 | gcc_assert (sl); |
7041 | add_structured_block_stmt (sl: pop_stmt_list (sl)); |
7042 | omp_for_parse_state->depth++; |
7043 | add_stmt (c_parser_omp_loop_nest (parser, NULL)); |
7044 | omp_for_parse_state->depth--; |
7045 | sl = push_stmt_list (); |
7046 | parser->error = false; |
7047 | continue; |
7048 | } |
7049 | else if (want_nested_loop |
7050 | && c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
7051 | { |
7052 | /* If this nested compound statement contains the nested loop, |
7053 | we need to separate the other statements in the current |
7054 | statement into separate blocks of intervening code. If |
7055 | there's no nested loop, it's all part of the same |
7056 | chunk of intervening code. */ |
7057 | tree pre_sl = pop_stmt_list (sl); |
7058 | tree nested_sl = push_stmt_list (); |
7059 | mark_valid_location_for_stdc_pragma (false); |
7060 | c_parser_statement_after_labels (parser, NULL); |
7061 | nested_sl = pop_stmt_list (nested_sl); |
7062 | if (omp_for_parse_state->want_nested_loop) |
7063 | { |
7064 | /* This block didn't contain a loop-nest, so it's |
7065 | all part of the same chunk of intervening code. */ |
7066 | check_omp_intervening_code (parser); |
7067 | sl = push_stmt_list (); |
7068 | add_stmt (pre_sl); |
7069 | add_stmt (nested_sl); |
7070 | } |
7071 | else |
7072 | { |
7073 | /* It contains the nested loop. */ |
7074 | add_structured_block_stmt (sl: pre_sl); |
7075 | add_stmt (nested_sl); |
7076 | sl = push_stmt_list (); |
7077 | } |
7078 | parser->error = false; |
7079 | continue; |
7080 | } |
7081 | else if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7082 | { |
7083 | /* Prior to implementing the OpenMP 5.1 syntax for canonical |
7084 | loop form, GCC used to accept an empty statements that |
7085 | would now be flagged as intervening code. Continue to |
7086 | do that, as an extension. */ |
7087 | /* FIXME: Maybe issue a warning or something here? */ |
7088 | c_parser_consume_token (parser); |
7089 | continue; |
7090 | } |
7091 | } |
7092 | |
7093 | /* Standard attributes may start a label, statement or declaration. */ |
7094 | bool have_std_attrs |
7095 | = c_parser_nth_token_starts_std_attributes (parser, n: 1); |
7096 | tree std_attrs = NULL_TREE; |
7097 | if (have_std_attrs) |
7098 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
7099 | if (c_parser_next_token_is_keyword (parser, keyword: RID_CASE) |
7100 | || c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT) |
7101 | || (c_parser_next_token_is (parser, type: CPP_NAME) |
7102 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
7103 | { |
7104 | if (c_parser_next_token_is_keyword (parser, keyword: RID_CASE)) |
7105 | label_loc = c_parser_peek_2nd_token (parser)->location; |
7106 | else |
7107 | label_loc = c_parser_peek_token (parser)->location; |
7108 | last_label = true; |
7109 | last_stmt = false; |
7110 | mark_valid_location_for_stdc_pragma (false); |
7111 | if (in_omp_loop_block) |
7112 | check_omp_intervening_code (parser); |
7113 | c_parser_label (parser, std_attrs); |
7114 | } |
7115 | else if (c_parser_next_tokens_start_declaration (parser) |
7116 | || (have_std_attrs |
7117 | && !c_parser_handle_statement_omp_attributes |
7118 | (parser, attrs&: std_attrs, have_std_attrs: &have_std_attrs) |
7119 | && c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
7120 | && (have_std_attrs = true))) |
7121 | { |
7122 | if (last_label) |
7123 | pedwarn_c11 (c_parser_peek_token (parser)->location, opt: OPT_Wpedantic, |
7124 | "a label can only be part of a statement and " |
7125 | "a declaration is not a statement" ); |
7126 | /* It's unlikely we'll see a nested loop in a declaration in |
7127 | intervening code in an OMP loop, but disallow it anyway. */ |
7128 | if (in_omp_loop_block) |
7129 | { |
7130 | check_omp_intervening_code (parser); |
7131 | omp_for_parse_state->want_nested_loop = false; |
7132 | } |
7133 | mark_valid_location_for_stdc_pragma (false); |
7134 | bool fallthru_attr_p = false; |
7135 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: !have_std_attrs, |
7136 | empty_ok: true, nested: true, start_attr_ok: true, NULL, |
7137 | NULL, have_attrs: have_std_attrs, attrs: std_attrs, |
7138 | NULL, fallthru_attr_p: &fallthru_attr_p); |
7139 | |
7140 | if (in_omp_loop_block) |
7141 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7142 | if (last_stmt && !fallthru_attr_p) |
7143 | pedwarn_c90 (loc, opt: OPT_Wdeclaration_after_statement, |
7144 | "ISO C90 forbids mixed declarations and code" ); |
7145 | last_stmt = fallthru_attr_p; |
7146 | last_label = false; |
7147 | } |
7148 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
7149 | { |
7150 | /* __extension__ can start a declaration, but is also an |
7151 | unary operator that can start an expression. Consume all |
7152 | but the last of a possible series of __extension__ to |
7153 | determine which. If standard attributes have already |
7154 | been seen, it must start a statement, not a declaration, |
7155 | but standard attributes starting a declaration may appear |
7156 | after __extension__. */ |
7157 | while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD |
7158 | && (c_parser_peek_2nd_token (parser)->keyword |
7159 | == RID_EXTENSION)) |
7160 | c_parser_consume_token (parser); |
7161 | if (!have_std_attrs |
7162 | && (c_token_starts_declaration (token: c_parser_peek_2nd_token (parser)) |
7163 | || c_parser_nth_token_starts_std_attributes (parser, n: 2))) |
7164 | { |
7165 | int ext; |
7166 | ext = disable_extension_diagnostics (); |
7167 | c_parser_consume_token (parser); |
7168 | last_label = false; |
7169 | /* It's unlikely we'll see a nested loop in a declaration in |
7170 | intervening code in an OMP loop, but disallow it anyway. */ |
7171 | if (in_omp_loop_block) |
7172 | { |
7173 | check_omp_intervening_code (parser); |
7174 | omp_for_parse_state->want_nested_loop = false; |
7175 | } |
7176 | mark_valid_location_for_stdc_pragma (false); |
7177 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, |
7178 | start_attr_ok: true); |
7179 | if (in_omp_loop_block) |
7180 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7181 | /* Following the old parser, __extension__ does not |
7182 | disable this diagnostic. */ |
7183 | restore_extension_diagnostics (flags: ext); |
7184 | if (last_stmt) |
7185 | pedwarn_c90 (loc, opt: OPT_Wdeclaration_after_statement, |
7186 | "ISO C90 forbids mixed declarations and code" ); |
7187 | last_stmt = false; |
7188 | } |
7189 | else |
7190 | goto statement; |
7191 | } |
7192 | else if (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
7193 | { |
7194 | if (have_std_attrs && !parser->in_omp_attribute_pragma) |
7195 | c_parser_error (parser, gmsgid: "expected declaration or statement" ); |
7196 | else if (std_attrs) |
7197 | c_warn_unused_attributes (std_attrs); |
7198 | /* External pragmas, and some omp pragmas, are not associated |
7199 | with regular c code, and so are not to be considered statements |
7200 | syntactically. This ensures that the user doesn't put them |
7201 | places that would turn into syntax errors if the directive |
7202 | were ignored. */ |
7203 | if (omp_for_parse_state) |
7204 | omp_for_parse_state->want_nested_loop = false; |
7205 | if (c_parser_pragma (parser, |
7206 | last_label ? pragma_stmt : pragma_compound, |
7207 | NULL)) |
7208 | { |
7209 | last_label = false; |
7210 | last_stmt = true; |
7211 | if (omp_for_parse_state) |
7212 | check_omp_intervening_code (parser); |
7213 | } |
7214 | if (omp_for_parse_state) |
7215 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7216 | } |
7217 | else if (c_parser_next_token_is (parser, type: CPP_EOF)) |
7218 | { |
7219 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7220 | c_parser_error (parser, gmsgid: "expected declaration or statement" ); |
7221 | return c_parser_peek_token (parser)->location; |
7222 | } |
7223 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
7224 | { |
7225 | if (parser->in_if_block) |
7226 | { |
7227 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7228 | error_at (loc, "expected %<}%> before %<else%>" ); |
7229 | return c_parser_peek_token (parser)->location; |
7230 | } |
7231 | else |
7232 | { |
7233 | error_at (loc, "%<else%> without a previous %<if%>" ); |
7234 | c_parser_consume_token (parser); |
7235 | continue; |
7236 | } |
7237 | } |
7238 | else |
7239 | { |
7240 | statement: |
7241 | c_warn_unused_attributes (std_attrs); |
7242 | last_label = false; |
7243 | last_stmt = true; |
7244 | mark_valid_location_for_stdc_pragma (false); |
7245 | if (!omp_for_parse_state) |
7246 | c_parser_statement_after_labels (parser, NULL); |
7247 | else |
7248 | { |
7249 | /* In canonical loop nest form, nested loops can only appear |
7250 | directly, or in a directly nested compound statement. We |
7251 | already took care of those cases above, so now we have |
7252 | something else. This statement and everything inside |
7253 | it must be intervening code. */ |
7254 | omp_for_parse_state->want_nested_loop = false; |
7255 | check_omp_intervening_code (parser); |
7256 | c_parser_statement_after_labels (parser, NULL); |
7257 | omp_for_parse_state->want_nested_loop = want_nested_loop; |
7258 | } |
7259 | } |
7260 | |
7261 | parser->error = false; |
7262 | } |
7263 | if (last_label) |
7264 | pedwarn_c11 (label_loc, opt: OPT_Wpedantic, "label at end of compound statement" ); |
7265 | location_t endloc = c_parser_peek_token (parser)->location; |
7266 | c_parser_consume_token (parser); |
7267 | |
7268 | /* Restore the value we started with. */ |
7269 | mark_valid_location_for_stdc_pragma (save_valid_for_pragma); |
7270 | |
7271 | /* Package leftover intervening code, or the whole contents of the |
7272 | compound statement if we were looking for a nested loop in an OMP_FOR |
7273 | construct and didn't find one. */ |
7274 | if (sl) |
7275 | { |
7276 | sl = pop_stmt_list (sl); |
7277 | if (omp_for_parse_state->want_nested_loop) |
7278 | add_stmt (sl); |
7279 | else |
7280 | add_structured_block_stmt (sl); |
7281 | } |
7282 | return endloc; |
7283 | } |
7284 | |
7285 | /* Parse all consecutive labels, possibly preceded by standard |
7286 | attributes. In this context, a statement is required, not a |
7287 | declaration, so attributes must be followed by a statement that is |
7288 | not just a semicolon. */ |
7289 | |
7290 | static void |
7291 | c_parser_all_labels (c_parser *parser) |
7292 | { |
7293 | bool have_std_attrs; |
7294 | tree std_attrs = NULL; |
7295 | if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, n: 1))) |
7296 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
7297 | while (c_parser_next_token_is_keyword (parser, keyword: RID_CASE) |
7298 | || c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT) |
7299 | || (c_parser_next_token_is (parser, type: CPP_NAME) |
7300 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON)) |
7301 | { |
7302 | c_parser_label (parser, std_attrs); |
7303 | std_attrs = NULL; |
7304 | if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, |
7305 | n: 1))) |
7306 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
7307 | } |
7308 | if (std_attrs |
7309 | && (!c_parser_handle_statement_omp_attributes (parser, attrs&: std_attrs, have_std_attrs: &have_std_attrs) |
7310 | || std_attrs)) |
7311 | { |
7312 | if (have_std_attrs && c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7313 | c_parser_error (parser, gmsgid: "expected statement" ); |
7314 | c_warn_unused_attributes (std_attrs); |
7315 | } |
7316 | else if (have_std_attrs && c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7317 | c_parser_error (parser, gmsgid: "expected statement" ); |
7318 | } |
7319 | |
7320 | /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). |
7321 | |
7322 | label: |
7323 | identifier : gnu-attributes[opt] |
7324 | case constant-expression : |
7325 | default : |
7326 | |
7327 | GNU extensions: |
7328 | |
7329 | label: |
7330 | case constant-expression ... constant-expression : |
7331 | |
7332 | The use of gnu-attributes on labels is a GNU extension. The syntax in |
7333 | GNU C accepts any expressions without commas, non-constant |
7334 | expressions being rejected later. Any standard |
7335 | attribute-specifier-sequence before the first label has been parsed |
7336 | in the caller, to distinguish statements from declarations. Any |
7337 | attribute-specifier-sequence after the label is parsed in this |
7338 | function. */ |
7339 | static void |
7340 | c_parser_label (c_parser *parser, tree std_attrs) |
7341 | { |
7342 | location_t loc1 = c_parser_peek_token (parser)->location; |
7343 | tree label = NULL_TREE; |
7344 | |
7345 | /* Remember whether this case or a user-defined label is allowed to fall |
7346 | through to. */ |
7347 | bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH; |
7348 | |
7349 | if (c_parser_next_token_is_keyword (parser, keyword: RID_CASE)) |
7350 | { |
7351 | tree exp1, exp2; |
7352 | c_parser_consume_token (parser); |
7353 | exp1 = convert_lvalue_to_rvalue (loc1, |
7354 | c_parser_expr_no_commas (parser, NULL), |
7355 | true, true).value; |
7356 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
7357 | { |
7358 | c_parser_consume_token (parser); |
7359 | label = do_case (loc1, exp1, NULL_TREE, std_attrs); |
7360 | } |
7361 | else if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
7362 | { |
7363 | c_parser_consume_token (parser); |
7364 | exp2 = convert_lvalue_to_rvalue (loc1, |
7365 | c_parser_expr_no_commas (parser, |
7366 | NULL), |
7367 | true, true).value; |
7368 | if (c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
7369 | label = do_case (loc1, exp1, exp2, std_attrs); |
7370 | } |
7371 | else |
7372 | c_parser_error (parser, gmsgid: "expected %<:%> or %<...%>" ); |
7373 | } |
7374 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT)) |
7375 | { |
7376 | c_parser_consume_token (parser); |
7377 | if (c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
7378 | label = do_case (loc1, NULL_TREE, NULL_TREE, std_attrs); |
7379 | } |
7380 | else |
7381 | { |
7382 | tree name = c_parser_peek_token (parser)->value; |
7383 | tree tlab; |
7384 | tree attrs; |
7385 | location_t loc2 = c_parser_peek_token (parser)->location; |
7386 | gcc_assert (c_parser_next_token_is (parser, CPP_NAME)); |
7387 | c_parser_consume_token (parser); |
7388 | gcc_assert (c_parser_next_token_is (parser, CPP_COLON)); |
7389 | c_parser_consume_token (parser); |
7390 | attrs = c_parser_gnu_attributes (parser); |
7391 | tlab = define_label (loc2, name); |
7392 | if (tlab) |
7393 | { |
7394 | decl_attributes (&tlab, attrs, 0); |
7395 | decl_attributes (&tlab, std_attrs, 0); |
7396 | label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab)); |
7397 | } |
7398 | if (attrs |
7399 | && c_parser_next_tokens_start_declaration (parser)) |
7400 | warning_at (loc2, OPT_Wattributes, "GNU-style attribute between" |
7401 | " label and declaration appertains to the label" ); |
7402 | } |
7403 | if (label) |
7404 | { |
7405 | if (TREE_CODE (label) == LABEL_EXPR) |
7406 | FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p; |
7407 | else |
7408 | FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p; |
7409 | } |
7410 | } |
7411 | |
7412 | /* Parse a statement (C90 6.6, C99 6.8, C11 6.8). |
7413 | |
7414 | statement: |
7415 | labeled-statement |
7416 | attribute-specifier-sequence[opt] compound-statement |
7417 | expression-statement |
7418 | attribute-specifier-sequence[opt] selection-statement |
7419 | attribute-specifier-sequence[opt] iteration-statement |
7420 | attribute-specifier-sequence[opt] jump-statement |
7421 | |
7422 | labeled-statement: |
7423 | attribute-specifier-sequence[opt] label statement |
7424 | |
7425 | expression-statement: |
7426 | expression[opt] ; |
7427 | attribute-specifier-sequence expression ; |
7428 | |
7429 | selection-statement: |
7430 | if-statement |
7431 | switch-statement |
7432 | |
7433 | iteration-statement: |
7434 | while-statement |
7435 | do-statement |
7436 | for-statement |
7437 | |
7438 | jump-statement: |
7439 | goto identifier ; |
7440 | continue ; |
7441 | break ; |
7442 | return expression[opt] ; |
7443 | |
7444 | GNU extensions: |
7445 | |
7446 | statement: |
7447 | attribute-specifier-sequence[opt] asm-statement |
7448 | |
7449 | jump-statement: |
7450 | goto * expression ; |
7451 | |
7452 | expression-statement: |
7453 | gnu-attributes ; |
7454 | |
7455 | Objective-C: |
7456 | |
7457 | statement: |
7458 | attribute-specifier-sequence[opt] objc-throw-statement |
7459 | attribute-specifier-sequence[opt] objc-try-catch-statement |
7460 | attribute-specifier-sequence[opt] objc-synchronized-statement |
7461 | |
7462 | objc-throw-statement: |
7463 | @throw expression ; |
7464 | @throw ; |
7465 | |
7466 | OpenACC: |
7467 | |
7468 | statement: |
7469 | attribute-specifier-sequence[opt] openacc-construct |
7470 | |
7471 | openacc-construct: |
7472 | parallel-construct |
7473 | kernels-construct |
7474 | data-construct |
7475 | loop-construct |
7476 | |
7477 | parallel-construct: |
7478 | parallel-directive structured-block |
7479 | |
7480 | kernels-construct: |
7481 | kernels-directive structured-block |
7482 | |
7483 | data-construct: |
7484 | data-directive structured-block |
7485 | |
7486 | loop-construct: |
7487 | loop-directive structured-block |
7488 | |
7489 | OpenMP: |
7490 | |
7491 | statement: |
7492 | attribute-specifier-sequence[opt] openmp-construct |
7493 | |
7494 | openmp-construct: |
7495 | parallel-construct |
7496 | for-construct |
7497 | simd-construct |
7498 | for-simd-construct |
7499 | sections-construct |
7500 | single-construct |
7501 | parallel-for-construct |
7502 | parallel-for-simd-construct |
7503 | parallel-sections-construct |
7504 | master-construct |
7505 | critical-construct |
7506 | atomic-construct |
7507 | ordered-construct |
7508 | |
7509 | parallel-construct: |
7510 | parallel-directive structured-block |
7511 | |
7512 | for-construct: |
7513 | for-directive iteration-statement |
7514 | |
7515 | simd-construct: |
7516 | simd-directive iteration-statements |
7517 | |
7518 | for-simd-construct: |
7519 | for-simd-directive iteration-statements |
7520 | |
7521 | sections-construct: |
7522 | sections-directive section-scope |
7523 | |
7524 | single-construct: |
7525 | single-directive structured-block |
7526 | |
7527 | parallel-for-construct: |
7528 | parallel-for-directive iteration-statement |
7529 | |
7530 | parallel-for-simd-construct: |
7531 | parallel-for-simd-directive iteration-statement |
7532 | |
7533 | parallel-sections-construct: |
7534 | parallel-sections-directive section-scope |
7535 | |
7536 | master-construct: |
7537 | master-directive structured-block |
7538 | |
7539 | critical-construct: |
7540 | critical-directive structured-block |
7541 | |
7542 | atomic-construct: |
7543 | atomic-directive expression-statement |
7544 | |
7545 | ordered-construct: |
7546 | ordered-directive structured-block |
7547 | |
7548 | Transactional Memory: |
7549 | |
7550 | statement: |
7551 | attribute-specifier-sequence[opt] transaction-statement |
7552 | attribute-specifier-sequence[opt] transaction-cancel-statement |
7553 | |
7554 | IF_P is used to track whether there's a (possibly labeled) if statement |
7555 | which is not enclosed in braces and has an else clause. This is used to |
7556 | implement -Wparentheses. */ |
7557 | |
7558 | static void |
7559 | c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) |
7560 | { |
7561 | c_parser_all_labels (parser); |
7562 | if (loc_after_labels) |
7563 | *loc_after_labels = c_parser_peek_token (parser)->location; |
7564 | parser->omp_attrs_forbidden_p = false; |
7565 | c_parser_statement_after_labels (parser, if_p, NULL); |
7566 | } |
7567 | |
7568 | /* Parse a statement, other than a labeled statement. CHAIN is a vector |
7569 | of if-else-if conditions. All labels and standard attributes have |
7570 | been parsed in the caller. |
7571 | |
7572 | IF_P is used to track whether there's a (possibly labeled) if statement |
7573 | which is not enclosed in braces and has an else clause. This is used to |
7574 | implement -Wparentheses. */ |
7575 | |
7576 | static void |
7577 | c_parser_statement_after_labels (c_parser *parser, bool *if_p, |
7578 | vec<tree> *chain) |
7579 | { |
7580 | location_t loc = c_parser_peek_token (parser)->location; |
7581 | tree stmt = NULL_TREE; |
7582 | bool in_if_block = parser->in_if_block; |
7583 | parser->in_if_block = false; |
7584 | if (if_p != NULL) |
7585 | *if_p = false; |
7586 | |
7587 | if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) |
7588 | add_debug_begin_stmt (loc); |
7589 | |
7590 | restart: |
7591 | switch (c_parser_peek_token (parser)->type) |
7592 | { |
7593 | case CPP_OPEN_BRACE: |
7594 | add_stmt (c_parser_compound_statement (parser)); |
7595 | break; |
7596 | case CPP_KEYWORD: |
7597 | switch (c_parser_peek_token (parser)->keyword) |
7598 | { |
7599 | case RID_IF: |
7600 | c_parser_if_statement (parser, if_p, chain); |
7601 | break; |
7602 | case RID_SWITCH: |
7603 | c_parser_switch_statement (parser, if_p); |
7604 | break; |
7605 | case RID_WHILE: |
7606 | c_parser_while_statement (parser, false, 0, false, if_p); |
7607 | break; |
7608 | case RID_DO: |
7609 | c_parser_do_statement (parser, false, 0, false); |
7610 | break; |
7611 | case RID_FOR: |
7612 | c_parser_for_statement (parser, false, 0, false, if_p); |
7613 | break; |
7614 | case RID_GOTO: |
7615 | c_parser_consume_token (parser); |
7616 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
7617 | { |
7618 | stmt = c_finish_goto_label (loc, |
7619 | c_parser_peek_token (parser)->value); |
7620 | c_parser_consume_token (parser); |
7621 | } |
7622 | else if (c_parser_next_token_is (parser, type: CPP_MULT)) |
7623 | { |
7624 | struct c_expr val; |
7625 | |
7626 | c_parser_consume_token (parser); |
7627 | val = c_parser_expression (parser); |
7628 | val = convert_lvalue_to_rvalue (loc, val, false, true); |
7629 | stmt = c_finish_goto_ptr (loc, val); |
7630 | } |
7631 | else |
7632 | c_parser_error (parser, gmsgid: "expected identifier or %<*%>" ); |
7633 | goto expect_semicolon; |
7634 | case RID_CONTINUE: |
7635 | c_parser_consume_token (parser); |
7636 | stmt = c_finish_bc_stmt (loc, objc_foreach_continue_label, false); |
7637 | goto expect_semicolon; |
7638 | case RID_BREAK: |
7639 | c_parser_consume_token (parser); |
7640 | stmt = c_finish_bc_stmt (loc, objc_foreach_break_label, true); |
7641 | goto expect_semicolon; |
7642 | case RID_RETURN: |
7643 | c_parser_consume_token (parser); |
7644 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7645 | { |
7646 | stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); |
7647 | c_parser_consume_token (parser); |
7648 | } |
7649 | else |
7650 | { |
7651 | location_t xloc = c_parser_peek_token (parser)->location; |
7652 | struct c_expr expr = c_parser_expression_conv (parser); |
7653 | mark_exp_read (expr.value); |
7654 | stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), |
7655 | expr.value, expr.original_type); |
7656 | goto expect_semicolon; |
7657 | } |
7658 | break; |
7659 | case RID_ASM: |
7660 | stmt = c_parser_asm_statement (parser); |
7661 | break; |
7662 | case RID_TRANSACTION_ATOMIC: |
7663 | case RID_TRANSACTION_RELAXED: |
7664 | stmt = c_parser_transaction (parser, |
7665 | c_parser_peek_token (parser)->keyword); |
7666 | break; |
7667 | case RID_TRANSACTION_CANCEL: |
7668 | stmt = c_parser_transaction_cancel (parser); |
7669 | goto expect_semicolon; |
7670 | case RID_AT_THROW: |
7671 | gcc_assert (c_dialect_objc ()); |
7672 | c_parser_consume_token (parser); |
7673 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7674 | { |
7675 | stmt = objc_build_throw_stmt (loc, NULL_TREE); |
7676 | c_parser_consume_token (parser); |
7677 | } |
7678 | else |
7679 | { |
7680 | struct c_expr expr = c_parser_expression (parser); |
7681 | expr = convert_lvalue_to_rvalue (loc, expr, false, false); |
7682 | expr.value = c_fully_fold (expr.value, false, NULL); |
7683 | stmt = objc_build_throw_stmt (loc, expr.value); |
7684 | goto expect_semicolon; |
7685 | } |
7686 | break; |
7687 | case RID_AT_TRY: |
7688 | gcc_assert (c_dialect_objc ()); |
7689 | c_parser_objc_try_catch_finally_statement (parser); |
7690 | break; |
7691 | case RID_AT_SYNCHRONIZED: |
7692 | gcc_assert (c_dialect_objc ()); |
7693 | c_parser_objc_synchronized_statement (parser); |
7694 | break; |
7695 | case RID_ATTRIBUTE: |
7696 | { |
7697 | /* Allow '__attribute__((fallthrough));' or |
7698 | '__attribute__((assume(cond)));'. */ |
7699 | tree attrs = c_parser_gnu_attributes (parser); |
7700 | bool has_assume = lookup_attribute (attr_name: "assume" , list: attrs); |
7701 | if (has_assume) |
7702 | { |
7703 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7704 | attrs = handle_assume_attribute (here: loc, attrs, nested: true); |
7705 | else |
7706 | { |
7707 | warning_at (loc, OPT_Wattributes, |
7708 | "%<assume%> attribute not followed by %<;%>" ); |
7709 | has_assume = false; |
7710 | } |
7711 | } |
7712 | if (attribute_fallthrough_p (attrs)) |
7713 | { |
7714 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7715 | { |
7716 | tree fn = build_call_expr_internal_loc (loc, |
7717 | IFN_FALLTHROUGH, |
7718 | void_type_node, 0); |
7719 | add_stmt (fn); |
7720 | /* Eat the ';'. */ |
7721 | c_parser_consume_token (parser); |
7722 | } |
7723 | else |
7724 | warning_at (loc, OPT_Wattributes, |
7725 | "%<fallthrough%> attribute not followed " |
7726 | "by %<;%>" ); |
7727 | } |
7728 | else if (has_assume) |
7729 | /* Eat the ';'. */ |
7730 | c_parser_consume_token (parser); |
7731 | else if (attrs != NULL_TREE) |
7732 | warning_at (loc, OPT_Wattributes, |
7733 | "only attribute %<fallthrough%> or %<assume%> can " |
7734 | "be applied to a null statement" ); |
7735 | break; |
7736 | } |
7737 | default: |
7738 | goto expr_stmt; |
7739 | } |
7740 | break; |
7741 | case CPP_SEMICOLON: |
7742 | c_parser_consume_token (parser); |
7743 | break; |
7744 | case CPP_CLOSE_PAREN: |
7745 | case CPP_CLOSE_SQUARE: |
7746 | /* Avoid infinite loop in error recovery: |
7747 | c_parser_skip_until_found stops at a closing nesting |
7748 | delimiter without consuming it, but here we need to consume |
7749 | it to proceed further. */ |
7750 | c_parser_error (parser, gmsgid: "expected statement" ); |
7751 | c_parser_consume_token (parser); |
7752 | break; |
7753 | case CPP_PRAGMA: |
7754 | if (!c_parser_pragma (parser, pragma_stmt, if_p)) |
7755 | goto restart; |
7756 | break; |
7757 | default: |
7758 | expr_stmt: |
7759 | stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value); |
7760 | expect_semicolon: |
7761 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
7762 | break; |
7763 | } |
7764 | /* Two cases cannot and do not have line numbers associated: If stmt |
7765 | is degenerate, such as "2;", then stmt is an INTEGER_CST, which |
7766 | cannot hold line numbers. But that's OK because the statement |
7767 | will either be changed to a MODIFY_EXPR during gimplification of |
7768 | the statement expr, or discarded. If stmt was compound, but |
7769 | without new variables, we will have skipped the creation of a |
7770 | BIND and will have a bare STATEMENT_LIST. But that's OK because |
7771 | (recursively) all of the component statements should already have |
7772 | line numbers assigned. ??? Can we discard no-op statements |
7773 | earlier? */ |
7774 | if (EXPR_LOCATION (stmt) == UNKNOWN_LOCATION) |
7775 | protected_set_expr_location (stmt, loc); |
7776 | |
7777 | parser->in_if_block = in_if_block; |
7778 | } |
7779 | |
7780 | /* Parse the condition from an if, do, while or for statements. */ |
7781 | |
7782 | static tree |
7783 | c_parser_condition (c_parser *parser) |
7784 | { |
7785 | location_t loc = c_parser_peek_token (parser)->location; |
7786 | tree cond; |
7787 | cond = c_parser_expression_conv (parser).value; |
7788 | cond = c_objc_common_truthvalue_conversion (loc, cond); |
7789 | cond = c_fully_fold (cond, false, NULL); |
7790 | if (warn_sequence_point) |
7791 | verify_sequence_points (cond); |
7792 | return cond; |
7793 | } |
7794 | |
7795 | /* Parse a parenthesized condition from an if, do or while statement. |
7796 | |
7797 | condition: |
7798 | ( expression ) |
7799 | */ |
7800 | static tree |
7801 | c_parser_paren_condition (c_parser *parser) |
7802 | { |
7803 | tree cond; |
7804 | matching_parens parens; |
7805 | if (!parens.require_open (parser)) |
7806 | return error_mark_node; |
7807 | cond = c_parser_condition (parser); |
7808 | parens.skip_until_found_close (parser); |
7809 | return cond; |
7810 | } |
7811 | |
7812 | /* Parse a statement which is a block in C99. |
7813 | |
7814 | IF_P is used to track whether there's a (possibly labeled) if statement |
7815 | which is not enclosed in braces and has an else clause. This is used to |
7816 | implement -Wparentheses. */ |
7817 | |
7818 | static tree |
7819 | c_parser_c99_block_statement (c_parser *parser, bool *if_p, |
7820 | location_t *loc_after_labels) |
7821 | { |
7822 | tree block = c_begin_compound_stmt (flag_isoc99); |
7823 | location_t loc = c_parser_peek_token (parser)->location; |
7824 | c_parser_statement (parser, if_p, loc_after_labels); |
7825 | return c_end_compound_stmt (loc, block, flag_isoc99); |
7826 | } |
7827 | |
7828 | /* Parse the body of an if statement. This is just parsing a |
7829 | statement but (a) it is a block in C99, (b) we track whether the |
7830 | body is an if statement for the sake of -Wparentheses warnings, (c) |
7831 | we handle an empty body specially for the sake of -Wempty-body |
7832 | warnings, and (d) we call parser_compound_statement directly |
7833 | because c_parser_statement_after_labels resets |
7834 | parser->in_if_block. |
7835 | |
7836 | IF_P is used to track whether there's a (possibly labeled) if statement |
7837 | which is not enclosed in braces and has an else clause. This is used to |
7838 | implement -Wparentheses. */ |
7839 | |
7840 | static tree |
7841 | c_parser_if_body (c_parser *parser, bool *if_p, |
7842 | const token_indent_info &if_tinfo) |
7843 | { |
7844 | tree block = c_begin_compound_stmt (flag_isoc99); |
7845 | location_t body_loc = c_parser_peek_token (parser)->location; |
7846 | location_t body_loc_after_labels = UNKNOWN_LOCATION; |
7847 | token_indent_info body_tinfo |
7848 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7849 | |
7850 | c_parser_all_labels (parser); |
7851 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7852 | { |
7853 | location_t loc = c_parser_peek_token (parser)->location; |
7854 | add_stmt (build_empty_stmt (loc)); |
7855 | c_parser_consume_token (parser); |
7856 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
7857 | warning_at (loc, OPT_Wempty_body, |
7858 | "suggest braces around empty body in an %<if%> statement" ); |
7859 | } |
7860 | else if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
7861 | add_stmt (c_parser_compound_statement (parser)); |
7862 | else |
7863 | { |
7864 | body_loc_after_labels = c_parser_peek_token (parser)->location; |
7865 | c_parser_statement_after_labels (parser, if_p); |
7866 | } |
7867 | |
7868 | token_indent_info next_tinfo |
7869 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7870 | warn_for_misleading_indentation (guard_tinfo: if_tinfo, body_tinfo, next_tinfo); |
7871 | if (body_loc_after_labels != UNKNOWN_LOCATION |
7872 | && next_tinfo.type != CPP_SEMICOLON) |
7873 | warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, |
7874 | if_tinfo.location, RID_IF); |
7875 | |
7876 | return c_end_compound_stmt (body_loc, block, flag_isoc99); |
7877 | } |
7878 | |
7879 | /* Parse the else body of an if statement. This is just parsing a |
7880 | statement but (a) it is a block in C99, (b) we handle an empty body |
7881 | specially for the sake of -Wempty-body warnings. CHAIN is a vector |
7882 | of if-else-if conditions. */ |
7883 | |
7884 | static tree |
7885 | c_parser_else_body (c_parser *parser, const token_indent_info &else_tinfo, |
7886 | vec<tree> *chain) |
7887 | { |
7888 | location_t body_loc = c_parser_peek_token (parser)->location; |
7889 | tree block = c_begin_compound_stmt (flag_isoc99); |
7890 | token_indent_info body_tinfo |
7891 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7892 | location_t body_loc_after_labels = UNKNOWN_LOCATION; |
7893 | |
7894 | c_parser_all_labels (parser); |
7895 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
7896 | { |
7897 | location_t loc = c_parser_peek_token (parser)->location; |
7898 | warning_at (loc, |
7899 | OPT_Wempty_body, |
7900 | "suggest braces around empty body in an %<else%> statement" ); |
7901 | add_stmt (build_empty_stmt (loc)); |
7902 | c_parser_consume_token (parser); |
7903 | } |
7904 | else |
7905 | { |
7906 | if (!c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
7907 | body_loc_after_labels = c_parser_peek_token (parser)->location; |
7908 | c_parser_statement_after_labels (parser, NULL, chain); |
7909 | } |
7910 | |
7911 | token_indent_info next_tinfo |
7912 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7913 | warn_for_misleading_indentation (guard_tinfo: else_tinfo, body_tinfo, next_tinfo); |
7914 | if (body_loc_after_labels != UNKNOWN_LOCATION |
7915 | && next_tinfo.type != CPP_SEMICOLON) |
7916 | warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location, |
7917 | else_tinfo.location, RID_ELSE); |
7918 | |
7919 | return c_end_compound_stmt (body_loc, block, flag_isoc99); |
7920 | } |
7921 | |
7922 | /* We might need to reclassify any previously-lexed identifier, e.g. |
7923 | when we've left a for loop with an if-statement without else in the |
7924 | body - we might have used a wrong scope for the token. See PR67784. */ |
7925 | |
7926 | static void |
7927 | c_parser_maybe_reclassify_token (c_parser *parser) |
7928 | { |
7929 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
7930 | { |
7931 | c_token *token = c_parser_peek_token (parser); |
7932 | |
7933 | if (token->id_kind != C_ID_CLASSNAME) |
7934 | { |
7935 | tree decl = lookup_name (token->value); |
7936 | |
7937 | token->id_kind = C_ID_ID; |
7938 | if (decl) |
7939 | { |
7940 | if (TREE_CODE (decl) == TYPE_DECL) |
7941 | token->id_kind = C_ID_TYPENAME; |
7942 | } |
7943 | else if (c_dialect_objc ()) |
7944 | { |
7945 | tree objc_interface_decl = objc_is_class_name (token->value); |
7946 | /* Objective-C class names are in the same namespace as |
7947 | variables and typedefs, and hence are shadowed by local |
7948 | declarations. */ |
7949 | if (objc_interface_decl) |
7950 | { |
7951 | token->value = objc_interface_decl; |
7952 | token->id_kind = C_ID_CLASSNAME; |
7953 | } |
7954 | } |
7955 | } |
7956 | } |
7957 | } |
7958 | |
7959 | /* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). |
7960 | |
7961 | if-statement: |
7962 | if ( expression ) statement |
7963 | if ( expression ) statement else statement |
7964 | |
7965 | CHAIN is a vector of if-else-if conditions. |
7966 | IF_P is used to track whether there's a (possibly labeled) if statement |
7967 | which is not enclosed in braces and has an else clause. This is used to |
7968 | implement -Wparentheses. */ |
7969 | |
7970 | static void |
7971 | c_parser_if_statement (c_parser *parser, bool *if_p, vec<tree> *chain) |
7972 | { |
7973 | tree block; |
7974 | location_t loc; |
7975 | tree cond; |
7976 | bool nested_if = false; |
7977 | tree first_body, second_body; |
7978 | bool in_if_block; |
7979 | |
7980 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF)); |
7981 | token_indent_info if_tinfo |
7982 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7983 | c_parser_consume_token (parser); |
7984 | block = c_begin_compound_stmt (flag_isoc99); |
7985 | loc = c_parser_peek_token (parser)->location; |
7986 | cond = c_parser_paren_condition (parser); |
7987 | in_if_block = parser->in_if_block; |
7988 | parser->in_if_block = true; |
7989 | first_body = c_parser_if_body (parser, if_p: &nested_if, if_tinfo); |
7990 | parser->in_if_block = in_if_block; |
7991 | |
7992 | if (warn_duplicated_cond) |
7993 | warn_duplicated_cond_add_or_warn (EXPR_LOCATION (cond), cond, &chain); |
7994 | |
7995 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
7996 | { |
7997 | token_indent_info else_tinfo |
7998 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
7999 | c_parser_consume_token (parser); |
8000 | if (warn_duplicated_cond) |
8001 | { |
8002 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IF) |
8003 | && chain == NULL) |
8004 | { |
8005 | /* We've got "if (COND) else if (COND2)". Start the |
8006 | condition chain and add COND as the first element. */ |
8007 | chain = new vec<tree> (); |
8008 | if (!CONSTANT_CLASS_P (cond) && !TREE_SIDE_EFFECTS (cond)) |
8009 | chain->safe_push (obj: cond); |
8010 | } |
8011 | else if (!c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
8012 | /* This is if-else without subsequent if. Zap the condition |
8013 | chain; we would have already warned at this point. */ |
8014 | vec_free (v&: chain); |
8015 | } |
8016 | second_body = c_parser_else_body (parser, else_tinfo, chain); |
8017 | /* Set IF_P to true to indicate that this if statement has an |
8018 | else clause. This may trigger the Wparentheses warning |
8019 | below when we get back up to the parent if statement. */ |
8020 | if (if_p != NULL) |
8021 | *if_p = true; |
8022 | } |
8023 | else |
8024 | { |
8025 | second_body = NULL_TREE; |
8026 | |
8027 | /* Diagnose an ambiguous else if if-then-else is nested inside |
8028 | if-then. */ |
8029 | if (nested_if) |
8030 | warning_at (loc, OPT_Wdangling_else, |
8031 | "suggest explicit braces to avoid ambiguous %<else%>" ); |
8032 | |
8033 | if (warn_duplicated_cond) |
8034 | /* This if statement does not have an else clause. We don't |
8035 | need the condition chain anymore. */ |
8036 | vec_free (v&: chain); |
8037 | } |
8038 | c_finish_if_stmt (loc, cond, first_body, second_body); |
8039 | add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); |
8040 | |
8041 | c_parser_maybe_reclassify_token (parser); |
8042 | } |
8043 | |
8044 | /* Parse a switch statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). |
8045 | |
8046 | switch-statement: |
8047 | switch (expression) statement |
8048 | */ |
8049 | |
8050 | static void |
8051 | c_parser_switch_statement (c_parser *parser, bool *if_p) |
8052 | { |
8053 | struct c_expr ce; |
8054 | tree block, expr, body; |
8055 | unsigned char save_in_statement; |
8056 | location_t switch_loc = c_parser_peek_token (parser)->location; |
8057 | location_t switch_cond_loc; |
8058 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH)); |
8059 | c_parser_consume_token (parser); |
8060 | block = c_begin_compound_stmt (flag_isoc99); |
8061 | bool explicit_cast_p = false; |
8062 | matching_parens parens; |
8063 | if (parens.require_open (parser)) |
8064 | { |
8065 | switch_cond_loc = c_parser_peek_token (parser)->location; |
8066 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
8067 | && c_token_starts_typename (token: c_parser_peek_2nd_token (parser))) |
8068 | explicit_cast_p = true; |
8069 | ce = c_parser_expression (parser); |
8070 | ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true); |
8071 | expr = ce.value; |
8072 | /* ??? expr has no valid location? */ |
8073 | parens.skip_until_found_close (parser); |
8074 | } |
8075 | else |
8076 | { |
8077 | switch_cond_loc = UNKNOWN_LOCATION; |
8078 | expr = error_mark_node; |
8079 | ce.original_type = error_mark_node; |
8080 | } |
8081 | c_start_switch (switch_loc, switch_cond_loc, expr, explicit_cast_p); |
8082 | save_in_statement = in_statement; |
8083 | in_statement |= IN_SWITCH_STMT; |
8084 | location_t loc_after_labels; |
8085 | bool open_brace_p = c_parser_peek_token (parser)->type == CPP_OPEN_BRACE; |
8086 | body = c_parser_c99_block_statement (parser, if_p, loc_after_labels: &loc_after_labels); |
8087 | location_t next_loc = c_parser_peek_token (parser)->location; |
8088 | if (!open_brace_p && c_parser_peek_token (parser)->type != CPP_SEMICOLON) |
8089 | warn_for_multistatement_macros (loc_after_labels, next_loc, switch_loc, |
8090 | RID_SWITCH); |
8091 | c_finish_switch (body, ce.original_type); |
8092 | in_statement = save_in_statement; |
8093 | add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99)); |
8094 | c_parser_maybe_reclassify_token (parser); |
8095 | } |
8096 | |
8097 | /* Parse a while statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). |
8098 | |
8099 | while-statement: |
8100 | while (expression) statement |
8101 | |
8102 | IF_P is used to track whether there's a (possibly labeled) if statement |
8103 | which is not enclosed in braces and has an else clause. This is used to |
8104 | implement -Wparentheses. */ |
8105 | |
8106 | static void |
8107 | c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, |
8108 | bool novector, bool *if_p) |
8109 | { |
8110 | tree block, cond, body; |
8111 | unsigned char save_in_statement; |
8112 | location_t loc; |
8113 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE)); |
8114 | token_indent_info while_tinfo |
8115 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8116 | |
8117 | if (parser->omp_for_parse_state) |
8118 | { |
8119 | error_at (c_parser_peek_token (parser)->location, |
8120 | "loop not permitted in intervening code in OpenMP loop body" ); |
8121 | parser->omp_for_parse_state->fail = true; |
8122 | } |
8123 | |
8124 | c_parser_consume_token (parser); |
8125 | block = c_begin_compound_stmt (flag_isoc99); |
8126 | loc = c_parser_peek_token (parser)->location; |
8127 | cond = c_parser_paren_condition (parser); |
8128 | if (ivdep && cond != error_mark_node) |
8129 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8130 | build_int_cst (integer_type_node, |
8131 | annot_expr_ivdep_kind), |
8132 | integer_zero_node); |
8133 | if (unroll && cond != error_mark_node) |
8134 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8135 | build_int_cst (integer_type_node, |
8136 | annot_expr_unroll_kind), |
8137 | build_int_cst (integer_type_node, unroll)); |
8138 | if (novector && cond != error_mark_node) |
8139 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8140 | build_int_cst (integer_type_node, |
8141 | annot_expr_no_vector_kind), |
8142 | integer_zero_node); |
8143 | save_in_statement = in_statement; |
8144 | in_statement = IN_ITERATION_STMT; |
8145 | |
8146 | token_indent_info body_tinfo |
8147 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8148 | |
8149 | location_t loc_after_labels; |
8150 | bool open_brace = c_parser_next_token_is (parser, type: CPP_OPEN_BRACE); |
8151 | body = c_parser_c99_block_statement (parser, if_p, loc_after_labels: &loc_after_labels); |
8152 | add_stmt (build_stmt (loc, WHILE_STMT, cond, body)); |
8153 | add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); |
8154 | c_parser_maybe_reclassify_token (parser); |
8155 | |
8156 | token_indent_info next_tinfo |
8157 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8158 | warn_for_misleading_indentation (guard_tinfo: while_tinfo, body_tinfo, next_tinfo); |
8159 | |
8160 | if (next_tinfo.type != CPP_SEMICOLON && !open_brace) |
8161 | warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, |
8162 | while_tinfo.location, RID_WHILE); |
8163 | |
8164 | in_statement = save_in_statement; |
8165 | } |
8166 | |
8167 | /* Parse a do statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). |
8168 | |
8169 | do-statement: |
8170 | do statement while ( expression ) ; |
8171 | */ |
8172 | |
8173 | static void |
8174 | c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll, |
8175 | bool novector) |
8176 | { |
8177 | tree block, cond, body; |
8178 | unsigned char save_in_statement; |
8179 | location_t loc; |
8180 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO)); |
8181 | |
8182 | if (parser->omp_for_parse_state) |
8183 | { |
8184 | error_at (c_parser_peek_token (parser)->location, |
8185 | "loop not permitted in intervening code in OpenMP loop body" ); |
8186 | parser->omp_for_parse_state->fail = true; |
8187 | } |
8188 | |
8189 | c_parser_consume_token (parser); |
8190 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
8191 | warning_at (c_parser_peek_token (parser)->location, |
8192 | OPT_Wempty_body, |
8193 | "suggest braces around empty body in %<do%> statement" ); |
8194 | block = c_begin_compound_stmt (flag_isoc99); |
8195 | loc = c_parser_peek_token (parser)->location; |
8196 | save_in_statement = in_statement; |
8197 | in_statement = IN_ITERATION_STMT; |
8198 | body = c_parser_c99_block_statement (parser, NULL); |
8199 | c_parser_require_keyword (parser, keyword: RID_WHILE, msgid: "expected %<while%>" ); |
8200 | in_statement = save_in_statement; |
8201 | cond = c_parser_paren_condition (parser); |
8202 | if (ivdep && cond != error_mark_node) |
8203 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8204 | build_int_cst (integer_type_node, |
8205 | annot_expr_ivdep_kind), |
8206 | integer_zero_node); |
8207 | if (unroll && cond != error_mark_node) |
8208 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8209 | build_int_cst (integer_type_node, |
8210 | annot_expr_unroll_kind), |
8211 | build_int_cst (integer_type_node, unroll)); |
8212 | if (novector && cond != error_mark_node) |
8213 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8214 | build_int_cst (integer_type_node, |
8215 | annot_expr_no_vector_kind), |
8216 | integer_zero_node); |
8217 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
8218 | c_parser_skip_to_end_of_block_or_statement (parser); |
8219 | |
8220 | add_stmt (build_stmt (loc, DO_STMT, cond, body)); |
8221 | add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); |
8222 | } |
8223 | |
8224 | /* Parse a for statement (C90 6.6.5, C99 6.8.5, C11 6.8.5). |
8225 | |
8226 | for-statement: |
8227 | for ( expression[opt] ; expression[opt] ; expression[opt] ) statement |
8228 | for ( nested-declaration expression[opt] ; expression[opt] ) statement |
8229 | |
8230 | The form with a declaration is new in C99. |
8231 | |
8232 | ??? In accordance with the old parser, the declaration may be a |
8233 | nested function, which is then rejected in check_for_loop_decls, |
8234 | but does it make any sense for this to be included in the grammar? |
8235 | Note in particular that the nested function does not include a |
8236 | trailing ';', whereas the "declaration" production includes one. |
8237 | Also, can we reject bad declarations earlier and cheaper than |
8238 | check_for_loop_decls? |
8239 | |
8240 | In Objective-C, there are two additional variants: |
8241 | |
8242 | foreach-statement: |
8243 | for ( expression in expresssion ) statement |
8244 | for ( declaration in expression ) statement |
8245 | |
8246 | This is inconsistent with C, because the second variant is allowed |
8247 | even if c99 is not enabled. |
8248 | |
8249 | The rest of the comment documents these Objective-C foreach-statement. |
8250 | |
8251 | Here is the canonical example of the first variant: |
8252 | for (object in array) { do something with object } |
8253 | we call the first expression ("object") the "object_expression" and |
8254 | the second expression ("array") the "collection_expression". |
8255 | object_expression must be an lvalue of type "id" (a generic Objective-C |
8256 | object) because the loop works by assigning to object_expression the |
8257 | various objects from the collection_expression. collection_expression |
8258 | must evaluate to something of type "id" which responds to the method |
8259 | countByEnumeratingWithState:objects:count:. |
8260 | |
8261 | The canonical example of the second variant is: |
8262 | for (id object in array) { do something with object } |
8263 | which is completely equivalent to |
8264 | { |
8265 | id object; |
8266 | for (object in array) { do something with object } |
8267 | } |
8268 | Note that initizializing 'object' in some way (eg, "for ((object = |
8269 | xxx) in array) { do something with object }") is possibly |
8270 | technically valid, but completely pointless as 'object' will be |
8271 | assigned to something else as soon as the loop starts. We should |
8272 | most likely reject it (TODO). |
8273 | |
8274 | The beginning of the Objective-C foreach-statement looks exactly |
8275 | like the beginning of the for-statement, and we can tell it is a |
8276 | foreach-statement only because the initial declaration or |
8277 | expression is terminated by 'in' instead of ';'. |
8278 | |
8279 | IF_P is used to track whether there's a (possibly labeled) if statement |
8280 | which is not enclosed in braces and has an else clause. This is used to |
8281 | implement -Wparentheses. */ |
8282 | |
8283 | static void |
8284 | c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, |
8285 | bool novector, bool *if_p) |
8286 | { |
8287 | tree block, cond, incr, body; |
8288 | unsigned char save_in_statement; |
8289 | tree save_objc_foreach_break_label, save_objc_foreach_continue_label; |
8290 | /* The following are only used when parsing an ObjC foreach statement. */ |
8291 | tree object_expression; |
8292 | /* Silence the bogus uninitialized warning. */ |
8293 | tree collection_expression = NULL; |
8294 | location_t loc = c_parser_peek_token (parser)->location; |
8295 | location_t for_loc = loc; |
8296 | bool is_foreach_statement = false; |
8297 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); |
8298 | token_indent_info for_tinfo |
8299 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8300 | |
8301 | if (parser->omp_for_parse_state) |
8302 | { |
8303 | error_at (for_loc, |
8304 | "loop not permitted in intervening code in OpenMP loop body" ); |
8305 | parser->omp_for_parse_state->fail = true; |
8306 | } |
8307 | |
8308 | c_parser_consume_token (parser); |
8309 | /* Open a compound statement in Objective-C as well, just in case this is |
8310 | as foreach expression. */ |
8311 | block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ()); |
8312 | cond = error_mark_node; |
8313 | incr = error_mark_node; |
8314 | matching_parens parens; |
8315 | if (parens.require_open (parser)) |
8316 | { |
8317 | /* Parse the initialization declaration or expression. */ |
8318 | object_expression = error_mark_node; |
8319 | parser->objc_could_be_foreach_context = c_dialect_objc (); |
8320 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
8321 | { |
8322 | parser->objc_could_be_foreach_context = false; |
8323 | c_parser_consume_token (parser); |
8324 | c_finish_expr_stmt (loc, NULL_TREE); |
8325 | } |
8326 | else if (c_parser_next_tokens_start_declaration (parser) |
8327 | || c_parser_nth_token_starts_std_attributes (parser, n: 1)) |
8328 | { |
8329 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, start_attr_ok: true, |
8330 | objc_foreach_object_declaration: &object_expression); |
8331 | parser->objc_could_be_foreach_context = false; |
8332 | |
8333 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
8334 | { |
8335 | c_parser_consume_token (parser); |
8336 | is_foreach_statement = true; |
8337 | if (check_for_loop_decls (for_loc, true) == NULL_TREE) |
8338 | c_parser_error (parser, gmsgid: "multiple iterating variables in " |
8339 | "fast enumeration" ); |
8340 | } |
8341 | else |
8342 | check_for_loop_decls (for_loc, flag_isoc99); |
8343 | } |
8344 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_EXTENSION)) |
8345 | { |
8346 | /* __extension__ can start a declaration, but is also an |
8347 | unary operator that can start an expression. Consume all |
8348 | but the last of a possible series of __extension__ to |
8349 | determine which. */ |
8350 | while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD |
8351 | && (c_parser_peek_2nd_token (parser)->keyword |
8352 | == RID_EXTENSION)) |
8353 | c_parser_consume_token (parser); |
8354 | if (c_token_starts_declaration (token: c_parser_peek_2nd_token (parser)) |
8355 | || c_parser_nth_token_starts_std_attributes (parser, n: 2)) |
8356 | { |
8357 | int ext; |
8358 | ext = disable_extension_diagnostics (); |
8359 | c_parser_consume_token (parser); |
8360 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, |
8361 | start_attr_ok: true, objc_foreach_object_declaration: &object_expression); |
8362 | parser->objc_could_be_foreach_context = false; |
8363 | |
8364 | restore_extension_diagnostics (flags: ext); |
8365 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
8366 | { |
8367 | c_parser_consume_token (parser); |
8368 | is_foreach_statement = true; |
8369 | if (check_for_loop_decls (for_loc, true) == NULL_TREE) |
8370 | c_parser_error (parser, gmsgid: "multiple iterating variables in " |
8371 | "fast enumeration" ); |
8372 | } |
8373 | else |
8374 | check_for_loop_decls (for_loc, flag_isoc99); |
8375 | } |
8376 | else |
8377 | goto init_expr; |
8378 | } |
8379 | else |
8380 | { |
8381 | init_expr: |
8382 | { |
8383 | struct c_expr ce; |
8384 | tree init_expression; |
8385 | ce = c_parser_expression (parser); |
8386 | init_expression = ce.value; |
8387 | parser->objc_could_be_foreach_context = false; |
8388 | if (c_parser_next_token_is_keyword (parser, keyword: RID_IN)) |
8389 | { |
8390 | c_parser_consume_token (parser); |
8391 | is_foreach_statement = true; |
8392 | if (! lvalue_p (init_expression)) |
8393 | c_parser_error (parser, gmsgid: "invalid iterating variable in " |
8394 | "fast enumeration" ); |
8395 | object_expression |
8396 | = c_fully_fold (init_expression, false, NULL); |
8397 | } |
8398 | else |
8399 | { |
8400 | ce = convert_lvalue_to_rvalue (loc, ce, true, false); |
8401 | init_expression = ce.value; |
8402 | c_finish_expr_stmt (loc, init_expression); |
8403 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, |
8404 | msgid: "expected %<;%>" ); |
8405 | } |
8406 | } |
8407 | } |
8408 | /* Parse the loop condition. In the case of a foreach |
8409 | statement, there is no loop condition. */ |
8410 | gcc_assert (!parser->objc_could_be_foreach_context); |
8411 | if (!is_foreach_statement) |
8412 | { |
8413 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
8414 | { |
8415 | if (ivdep) |
8416 | { |
8417 | c_parser_error (parser, gmsgid: "missing loop condition in loop " |
8418 | "with %<GCC ivdep%> pragma" ); |
8419 | cond = error_mark_node; |
8420 | } |
8421 | else if (unroll) |
8422 | { |
8423 | c_parser_error (parser, gmsgid: "missing loop condition in loop " |
8424 | "with %<GCC unroll%> pragma" ); |
8425 | cond = error_mark_node; |
8426 | } |
8427 | else |
8428 | { |
8429 | c_parser_consume_token (parser); |
8430 | cond = NULL_TREE; |
8431 | } |
8432 | } |
8433 | else |
8434 | { |
8435 | cond = c_parser_condition (parser); |
8436 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, |
8437 | msgid: "expected %<;%>" ); |
8438 | } |
8439 | if (ivdep && cond != error_mark_node) |
8440 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8441 | build_int_cst (integer_type_node, |
8442 | annot_expr_ivdep_kind), |
8443 | integer_zero_node); |
8444 | if (unroll && cond != error_mark_node) |
8445 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8446 | build_int_cst (integer_type_node, |
8447 | annot_expr_unroll_kind), |
8448 | build_int_cst (integer_type_node, unroll)); |
8449 | if (novector && cond && cond != error_mark_node) |
8450 | cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, |
8451 | build_int_cst (integer_type_node, |
8452 | annot_expr_no_vector_kind), |
8453 | integer_zero_node); |
8454 | } |
8455 | /* Parse the increment expression (the third expression in a |
8456 | for-statement). In the case of a foreach-statement, this is |
8457 | the expression that follows the 'in'. */ |
8458 | loc = c_parser_peek_token (parser)->location; |
8459 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
8460 | { |
8461 | if (is_foreach_statement) |
8462 | { |
8463 | c_parser_error (parser, |
8464 | gmsgid: "missing collection in fast enumeration" ); |
8465 | collection_expression = error_mark_node; |
8466 | } |
8467 | else |
8468 | incr = c_process_expr_stmt (loc, NULL_TREE); |
8469 | } |
8470 | else |
8471 | { |
8472 | if (is_foreach_statement) |
8473 | collection_expression |
8474 | = c_fully_fold (c_parser_expression (parser).value, false, NULL); |
8475 | else |
8476 | { |
8477 | struct c_expr ce = c_parser_expression (parser); |
8478 | ce = convert_lvalue_to_rvalue (loc, ce, true, false); |
8479 | incr = c_process_expr_stmt (loc, ce.value); |
8480 | } |
8481 | } |
8482 | parens.skip_until_found_close (parser); |
8483 | } |
8484 | save_in_statement = in_statement; |
8485 | if (is_foreach_statement) |
8486 | { |
8487 | in_statement = IN_OBJC_FOREACH; |
8488 | save_objc_foreach_break_label = objc_foreach_break_label; |
8489 | save_objc_foreach_continue_label = objc_foreach_continue_label; |
8490 | objc_foreach_break_label = create_artificial_label (loc); |
8491 | objc_foreach_continue_label = create_artificial_label (loc); |
8492 | } |
8493 | else |
8494 | in_statement = IN_ITERATION_STMT; |
8495 | |
8496 | token_indent_info body_tinfo |
8497 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8498 | |
8499 | location_t loc_after_labels; |
8500 | bool open_brace = c_parser_next_token_is (parser, type: CPP_OPEN_BRACE); |
8501 | body = c_parser_c99_block_statement (parser, if_p, loc_after_labels: &loc_after_labels); |
8502 | |
8503 | if (is_foreach_statement) |
8504 | objc_finish_foreach_loop (for_loc, object_expression, |
8505 | collection_expression, body, |
8506 | objc_foreach_break_label, |
8507 | objc_foreach_continue_label); |
8508 | else |
8509 | add_stmt (build_stmt (for_loc, FOR_STMT, NULL_TREE, cond, incr, |
8510 | body, NULL_TREE)); |
8511 | add_stmt (c_end_compound_stmt (for_loc, block, |
8512 | flag_isoc99 || c_dialect_objc ())); |
8513 | c_parser_maybe_reclassify_token (parser); |
8514 | |
8515 | token_indent_info next_tinfo |
8516 | = get_token_indent_info (token: c_parser_peek_token (parser)); |
8517 | warn_for_misleading_indentation (guard_tinfo: for_tinfo, body_tinfo, next_tinfo); |
8518 | |
8519 | if (next_tinfo.type != CPP_SEMICOLON && !open_brace) |
8520 | warn_for_multistatement_macros (loc_after_labels, next_tinfo.location, |
8521 | for_tinfo.location, RID_FOR); |
8522 | |
8523 | in_statement = save_in_statement; |
8524 | if (is_foreach_statement) |
8525 | { |
8526 | objc_foreach_break_label = save_objc_foreach_break_label; |
8527 | objc_foreach_continue_label = save_objc_foreach_continue_label; |
8528 | } |
8529 | } |
8530 | |
8531 | /* Parse an asm statement, a GNU extension. This is a full-blown asm |
8532 | statement with inputs, outputs, clobbers, and volatile, inline, and goto |
8533 | tags allowed. |
8534 | |
8535 | asm-qualifier: |
8536 | volatile |
8537 | inline |
8538 | goto |
8539 | |
8540 | asm-qualifier-list: |
8541 | asm-qualifier-list asm-qualifier |
8542 | asm-qualifier |
8543 | |
8544 | asm-statement: |
8545 | asm asm-qualifier-list[opt] ( asm-argument ) ; |
8546 | |
8547 | asm-argument: |
8548 | asm-string-literal |
8549 | asm-string-literal : asm-operands[opt] |
8550 | asm-string-literal : asm-operands[opt] : asm-operands[opt] |
8551 | asm-string-literal : asm-operands[opt] : asm-operands[opt] \ |
8552 | : asm-clobbers[opt] |
8553 | asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \ |
8554 | : asm-goto-operands |
8555 | |
8556 | The form with asm-goto-operands is valid if and only if the |
8557 | asm-qualifier-list contains goto, and is the only allowed form in that case. |
8558 | Duplicate asm-qualifiers are not allowed. |
8559 | |
8560 | The :: token is considered equivalent to two consecutive : tokens. */ |
8561 | |
8562 | static tree |
8563 | c_parser_asm_statement (c_parser *parser) |
8564 | { |
8565 | tree str, outputs, inputs, clobbers, labels, ret; |
8566 | bool simple; |
8567 | location_t asm_loc = c_parser_peek_token (parser)->location; |
8568 | int section, nsections; |
8569 | |
8570 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); |
8571 | c_parser_consume_token (parser); |
8572 | |
8573 | /* Handle the asm-qualifier-list. */ |
8574 | location_t volatile_loc = UNKNOWN_LOCATION; |
8575 | location_t inline_loc = UNKNOWN_LOCATION; |
8576 | location_t goto_loc = UNKNOWN_LOCATION; |
8577 | for (;;) |
8578 | { |
8579 | c_token *token = c_parser_peek_token (parser); |
8580 | location_t loc = token->location; |
8581 | switch (token->keyword) |
8582 | { |
8583 | case RID_VOLATILE: |
8584 | if (volatile_loc) |
8585 | { |
8586 | error_at (loc, "duplicate %<asm%> qualifier %qE" , token->value); |
8587 | inform (volatile_loc, "first seen here" ); |
8588 | } |
8589 | else |
8590 | volatile_loc = loc; |
8591 | c_parser_consume_token (parser); |
8592 | continue; |
8593 | |
8594 | case RID_INLINE: |
8595 | if (inline_loc) |
8596 | { |
8597 | error_at (loc, "duplicate %<asm%> qualifier %qE" , token->value); |
8598 | inform (inline_loc, "first seen here" ); |
8599 | } |
8600 | else |
8601 | inline_loc = loc; |
8602 | c_parser_consume_token (parser); |
8603 | continue; |
8604 | |
8605 | case RID_GOTO: |
8606 | if (goto_loc) |
8607 | { |
8608 | error_at (loc, "duplicate %<asm%> qualifier %qE" , token->value); |
8609 | inform (goto_loc, "first seen here" ); |
8610 | } |
8611 | else |
8612 | goto_loc = loc; |
8613 | c_parser_consume_token (parser); |
8614 | continue; |
8615 | |
8616 | case RID_CONST: |
8617 | case RID_RESTRICT: |
8618 | error_at (loc, "%qE is not a valid %<asm%> qualifier" , token->value); |
8619 | c_parser_consume_token (parser); |
8620 | continue; |
8621 | |
8622 | default: |
8623 | break; |
8624 | } |
8625 | break; |
8626 | } |
8627 | |
8628 | bool is_volatile = (volatile_loc != UNKNOWN_LOCATION); |
8629 | bool is_inline = (inline_loc != UNKNOWN_LOCATION); |
8630 | bool is_goto = (goto_loc != UNKNOWN_LOCATION); |
8631 | |
8632 | ret = NULL; |
8633 | |
8634 | matching_parens parens; |
8635 | if (!parens.require_open (parser)) |
8636 | goto error; |
8637 | |
8638 | str = c_parser_asm_string_literal (parser); |
8639 | if (str == NULL_TREE) |
8640 | goto error_close_paren; |
8641 | |
8642 | simple = true; |
8643 | outputs = NULL_TREE; |
8644 | inputs = NULL_TREE; |
8645 | clobbers = NULL_TREE; |
8646 | labels = NULL_TREE; |
8647 | |
8648 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN) && !is_goto) |
8649 | goto done_asm; |
8650 | |
8651 | /* Parse each colon-delimited section of operands. */ |
8652 | nsections = 3 + is_goto; |
8653 | for (section = 0; section < nsections; ++section) |
8654 | { |
8655 | if (c_parser_next_token_is (parser, type: CPP_SCOPE)) |
8656 | { |
8657 | ++section; |
8658 | if (section == nsections) |
8659 | { |
8660 | c_parser_error (parser, gmsgid: "expected %<)%>" ); |
8661 | goto error_close_paren; |
8662 | } |
8663 | c_parser_consume_token (parser); |
8664 | } |
8665 | else if (!c_parser_require (parser, type: CPP_COLON, |
8666 | msgid: is_goto |
8667 | ? G_("expected %<:%>" ) |
8668 | : G_("expected %<:%> or %<)%>" ), |
8669 | UNKNOWN_LOCATION, type_is_unique: is_goto)) |
8670 | goto error_close_paren; |
8671 | |
8672 | /* Once past any colon, we're no longer a simple asm. */ |
8673 | simple = false; |
8674 | |
8675 | if ((!c_parser_next_token_is (parser, type: CPP_COLON) |
8676 | && !c_parser_next_token_is (parser, type: CPP_SCOPE) |
8677 | && !c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
8678 | || section == 3) |
8679 | switch (section) |
8680 | { |
8681 | case 0: |
8682 | outputs = c_parser_asm_operands (parser); |
8683 | break; |
8684 | case 1: |
8685 | inputs = c_parser_asm_operands (parser); |
8686 | break; |
8687 | case 2: |
8688 | clobbers = c_parser_asm_clobbers (parser); |
8689 | break; |
8690 | case 3: |
8691 | labels = c_parser_asm_goto_operands (parser); |
8692 | break; |
8693 | default: |
8694 | gcc_unreachable (); |
8695 | } |
8696 | |
8697 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN) && !is_goto) |
8698 | goto done_asm; |
8699 | } |
8700 | |
8701 | done_asm: |
8702 | if (!parens.require_close (parser)) |
8703 | { |
8704 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
8705 | goto error; |
8706 | } |
8707 | |
8708 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
8709 | c_parser_skip_to_end_of_block_or_statement (parser); |
8710 | |
8711 | ret = build_asm_stmt (is_volatile, |
8712 | build_asm_expr (asm_loc, str, outputs, inputs, |
8713 | clobbers, labels, simple, is_inline)); |
8714 | |
8715 | error: |
8716 | return ret; |
8717 | |
8718 | error_close_paren: |
8719 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
8720 | goto error; |
8721 | } |
8722 | |
8723 | /* Parse asm operands, a GNU extension. |
8724 | |
8725 | asm-operands: |
8726 | asm-operand |
8727 | asm-operands , asm-operand |
8728 | |
8729 | asm-operand: |
8730 | asm-string-literal ( expression ) |
8731 | [ identifier ] asm-string-literal ( expression ) |
8732 | */ |
8733 | |
8734 | static tree |
8735 | c_parser_asm_operands (c_parser *parser) |
8736 | { |
8737 | tree list = NULL_TREE; |
8738 | while (true) |
8739 | { |
8740 | tree name, str; |
8741 | struct c_expr expr; |
8742 | if (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE)) |
8743 | { |
8744 | c_parser_consume_token (parser); |
8745 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
8746 | { |
8747 | tree id = c_parser_peek_token (parser)->value; |
8748 | c_parser_consume_token (parser); |
8749 | name = build_string (IDENTIFIER_LENGTH (id), |
8750 | IDENTIFIER_POINTER (id)); |
8751 | } |
8752 | else |
8753 | { |
8754 | c_parser_error (parser, gmsgid: "expected identifier" ); |
8755 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, NULL); |
8756 | return NULL_TREE; |
8757 | } |
8758 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
8759 | msgid: "expected %<]%>" ); |
8760 | } |
8761 | else |
8762 | name = NULL_TREE; |
8763 | str = c_parser_asm_string_literal (parser); |
8764 | if (str == NULL_TREE) |
8765 | return NULL_TREE; |
8766 | matching_parens parens; |
8767 | if (!parens.require_open (parser)) |
8768 | return NULL_TREE; |
8769 | expr = c_parser_expression (parser); |
8770 | mark_exp_read (expr.value); |
8771 | if (!parens.require_close (parser)) |
8772 | { |
8773 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
8774 | return NULL_TREE; |
8775 | } |
8776 | list = chainon (list, build_tree_list (build_tree_list (name, str), |
8777 | expr.value)); |
8778 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
8779 | c_parser_consume_token (parser); |
8780 | else |
8781 | break; |
8782 | } |
8783 | return list; |
8784 | } |
8785 | |
8786 | /* Parse asm clobbers, a GNU extension. |
8787 | |
8788 | asm-clobbers: |
8789 | asm-string-literal |
8790 | asm-clobbers , asm-string-literal |
8791 | */ |
8792 | |
8793 | static tree |
8794 | c_parser_asm_clobbers (c_parser *parser) |
8795 | { |
8796 | tree list = NULL_TREE; |
8797 | while (true) |
8798 | { |
8799 | tree str = c_parser_asm_string_literal (parser); |
8800 | if (str) |
8801 | list = tree_cons (NULL_TREE, str, list); |
8802 | else |
8803 | return NULL_TREE; |
8804 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
8805 | c_parser_consume_token (parser); |
8806 | else |
8807 | break; |
8808 | } |
8809 | return list; |
8810 | } |
8811 | |
8812 | /* Parse asm goto labels, a GNU extension. |
8813 | |
8814 | asm-goto-operands: |
8815 | identifier |
8816 | asm-goto-operands , identifier |
8817 | */ |
8818 | |
8819 | static tree |
8820 | c_parser_asm_goto_operands (c_parser *parser) |
8821 | { |
8822 | tree list = NULL_TREE; |
8823 | while (true) |
8824 | { |
8825 | tree name, label; |
8826 | |
8827 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
8828 | { |
8829 | c_token *tok = c_parser_peek_token (parser); |
8830 | name = tok->value; |
8831 | label = lookup_label_for_goto (tok->location, name); |
8832 | c_parser_consume_token (parser); |
8833 | TREE_USED (label) = 1; |
8834 | } |
8835 | else |
8836 | { |
8837 | c_parser_error (parser, gmsgid: "expected identifier" ); |
8838 | return NULL_TREE; |
8839 | } |
8840 | |
8841 | name = build_string (IDENTIFIER_LENGTH (name), |
8842 | IDENTIFIER_POINTER (name)); |
8843 | list = tree_cons (name, label, list); |
8844 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
8845 | c_parser_consume_token (parser); |
8846 | else |
8847 | return nreverse (list); |
8848 | } |
8849 | } |
8850 | |
8851 | /* Parse a possibly concatenated sequence of string literals. |
8852 | TRANSLATE says whether to translate them to the execution character |
8853 | set; WIDE_OK says whether any kind of prefixed string literal is |
8854 | permitted in this context. This code is based on that in |
8855 | lex_string. */ |
8856 | |
8857 | struct c_expr |
8858 | c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) |
8859 | { |
8860 | struct c_expr ret; |
8861 | size_t count; |
8862 | struct obstack str_ob; |
8863 | struct obstack loc_ob; |
8864 | cpp_string str, istr, *strs; |
8865 | c_token *tok; |
8866 | location_t loc, last_tok_loc; |
8867 | enum cpp_ttype type; |
8868 | tree value, string_tree; |
8869 | |
8870 | tok = c_parser_peek_token (parser); |
8871 | loc = tok->location; |
8872 | last_tok_loc = linemap_resolve_location (line_table, loc, |
8873 | lrk: LRK_MACRO_DEFINITION_LOCATION, |
8874 | NULL); |
8875 | type = tok->type; |
8876 | switch (type) |
8877 | { |
8878 | case CPP_STRING: |
8879 | case CPP_WSTRING: |
8880 | case CPP_STRING16: |
8881 | case CPP_STRING32: |
8882 | case CPP_UTF8STRING: |
8883 | string_tree = tok->value; |
8884 | break; |
8885 | |
8886 | default: |
8887 | c_parser_error (parser, gmsgid: "expected string literal" ); |
8888 | ret.set_error (); |
8889 | ret.value = NULL_TREE; |
8890 | ret.original_code = ERROR_MARK; |
8891 | ret.original_type = NULL_TREE; |
8892 | return ret; |
8893 | } |
8894 | |
8895 | /* Try to avoid the overhead of creating and destroying an obstack |
8896 | for the common case of just one string. */ |
8897 | switch (c_parser_peek_2nd_token (parser)->type) |
8898 | { |
8899 | default: |
8900 | c_parser_consume_token (parser); |
8901 | str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); |
8902 | str.len = TREE_STRING_LENGTH (string_tree); |
8903 | count = 1; |
8904 | strs = &str; |
8905 | break; |
8906 | |
8907 | case CPP_STRING: |
8908 | case CPP_WSTRING: |
8909 | case CPP_STRING16: |
8910 | case CPP_STRING32: |
8911 | case CPP_UTF8STRING: |
8912 | gcc_obstack_init (&str_ob); |
8913 | gcc_obstack_init (&loc_ob); |
8914 | count = 0; |
8915 | do |
8916 | { |
8917 | c_parser_consume_token (parser); |
8918 | count++; |
8919 | str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree); |
8920 | str.len = TREE_STRING_LENGTH (string_tree); |
8921 | if (type != tok->type) |
8922 | { |
8923 | if (type == CPP_STRING) |
8924 | type = tok->type; |
8925 | else if (tok->type != CPP_STRING) |
8926 | error ("unsupported non-standard concatenation " |
8927 | "of string literals" ); |
8928 | } |
8929 | obstack_grow (&str_ob, &str, sizeof (cpp_string)); |
8930 | obstack_grow (&loc_ob, &last_tok_loc, sizeof (location_t)); |
8931 | tok = c_parser_peek_token (parser); |
8932 | string_tree = tok->value; |
8933 | last_tok_loc |
8934 | = linemap_resolve_location (line_table, loc: tok->location, |
8935 | lrk: LRK_MACRO_DEFINITION_LOCATION, NULL); |
8936 | } |
8937 | while (tok->type == CPP_STRING |
8938 | || tok->type == CPP_WSTRING |
8939 | || tok->type == CPP_STRING16 |
8940 | || tok->type == CPP_STRING32 |
8941 | || tok->type == CPP_UTF8STRING); |
8942 | strs = (cpp_string *) obstack_finish (&str_ob); |
8943 | } |
8944 | |
8945 | if (count > 1 && !in_system_header_at (loc: input_location)) |
8946 | warning (OPT_Wtraditional, |
8947 | "traditional C rejects string constant concatenation" ); |
8948 | |
8949 | if ((type == CPP_STRING || wide_ok) |
8950 | && ((translate |
8951 | ? cpp_interpret_string : cpp_interpret_string_notranslate) |
8952 | (parse_in, strs, count, &istr, type))) |
8953 | { |
8954 | value = build_string (istr.len, (const char *) istr.text); |
8955 | free (CONST_CAST (unsigned char *, istr.text)); |
8956 | if (count > 1) |
8957 | { |
8958 | location_t *locs = (location_t *) obstack_finish (&loc_ob); |
8959 | gcc_assert (g_string_concat_db); |
8960 | g_string_concat_db->record_string_concatenation (num: count, locs); |
8961 | } |
8962 | } |
8963 | else |
8964 | { |
8965 | if (type != CPP_STRING && !wide_ok) |
8966 | { |
8967 | error_at (loc, "a wide string is invalid in this context" ); |
8968 | type = CPP_STRING; |
8969 | } |
8970 | /* Callers cannot generally handle error_mark_node in this |
8971 | context, so return the empty string instead. An error has |
8972 | been issued, either above or from cpp_interpret_string. */ |
8973 | switch (type) |
8974 | { |
8975 | default: |
8976 | case CPP_STRING: |
8977 | case CPP_UTF8STRING: |
8978 | if (type == CPP_UTF8STRING && flag_char8_t) |
8979 | { |
8980 | value = build_string (TYPE_PRECISION (char8_type_node) |
8981 | / TYPE_PRECISION (char_type_node), |
8982 | "" ); /* char8_t is 8 bits */ |
8983 | } |
8984 | else |
8985 | value = build_string (1, "" ); |
8986 | break; |
8987 | case CPP_STRING16: |
8988 | value = build_string (TYPE_PRECISION (char16_type_node) |
8989 | / TYPE_PRECISION (char_type_node), |
8990 | "\0" ); /* char16_t is 16 bits */ |
8991 | break; |
8992 | case CPP_STRING32: |
8993 | value = build_string (TYPE_PRECISION (char32_type_node) |
8994 | / TYPE_PRECISION (char_type_node), |
8995 | "\0\0\0" ); /* char32_t is 32 bits */ |
8996 | break; |
8997 | case CPP_WSTRING: |
8998 | value = build_string (TYPE_PRECISION (wchar_type_node) |
8999 | / TYPE_PRECISION (char_type_node), |
9000 | "\0\0\0" ); /* widest supported wchar_t |
9001 | is 32 bits */ |
9002 | break; |
9003 | } |
9004 | } |
9005 | |
9006 | switch (type) |
9007 | { |
9008 | default: |
9009 | case CPP_STRING: |
9010 | TREE_TYPE (value) = char_array_type_node; |
9011 | break; |
9012 | case CPP_UTF8STRING: |
9013 | if (flag_char8_t) |
9014 | TREE_TYPE (value) = char8_array_type_node; |
9015 | else |
9016 | TREE_TYPE (value) = char_array_type_node; |
9017 | break; |
9018 | case CPP_STRING16: |
9019 | TREE_TYPE (value) = char16_array_type_node; |
9020 | break; |
9021 | case CPP_STRING32: |
9022 | TREE_TYPE (value) = char32_array_type_node; |
9023 | break; |
9024 | case CPP_WSTRING: |
9025 | TREE_TYPE (value) = wchar_array_type_node; |
9026 | } |
9027 | value = fix_string_type (value); |
9028 | |
9029 | if (count > 1) |
9030 | { |
9031 | obstack_free (&str_ob, 0); |
9032 | obstack_free (&loc_ob, 0); |
9033 | } |
9034 | |
9035 | ret.value = value; |
9036 | ret.original_code = STRING_CST; |
9037 | ret.original_type = NULL_TREE; |
9038 | set_c_expr_source_range (expr: &ret, src_range: get_range_from_loc (set: line_table, loc)); |
9039 | ret.m_decimal = 0; |
9040 | parser->seen_string_literal = true; |
9041 | return ret; |
9042 | } |
9043 | |
9044 | /* Parse an expression other than a compound expression; that is, an |
9045 | assignment expression (C90 6.3.16, C99 6.5.16, C11 6.5.16). If |
9046 | AFTER is not NULL then it is an Objective-C message expression which |
9047 | is the primary-expression starting the expression as an initializer. |
9048 | |
9049 | assignment-expression: |
9050 | conditional-expression |
9051 | unary-expression assignment-operator assignment-expression |
9052 | |
9053 | assignment-operator: one of |
9054 | = *= /= %= += -= <<= >>= &= ^= |= |
9055 | |
9056 | In GNU C we accept any conditional expression on the LHS and |
9057 | diagnose the invalid lvalue rather than producing a syntax |
9058 | error. */ |
9059 | |
9060 | static struct c_expr |
9061 | c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, |
9062 | tree omp_atomic_lhs) |
9063 | { |
9064 | struct c_expr lhs, rhs, ret; |
9065 | enum tree_code code; |
9066 | location_t op_location, exp_location; |
9067 | bool save_in_omp_for = c_in_omp_for; |
9068 | c_in_omp_for = false; |
9069 | gcc_assert (!after || c_dialect_objc ()); |
9070 | lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs); |
9071 | op_location = c_parser_peek_token (parser)->location; |
9072 | switch (c_parser_peek_token (parser)->type) |
9073 | { |
9074 | case CPP_EQ: |
9075 | code = NOP_EXPR; |
9076 | break; |
9077 | case CPP_MULT_EQ: |
9078 | code = MULT_EXPR; |
9079 | break; |
9080 | case CPP_DIV_EQ: |
9081 | code = TRUNC_DIV_EXPR; |
9082 | break; |
9083 | case CPP_MOD_EQ: |
9084 | code = TRUNC_MOD_EXPR; |
9085 | break; |
9086 | case CPP_PLUS_EQ: |
9087 | code = PLUS_EXPR; |
9088 | break; |
9089 | case CPP_MINUS_EQ: |
9090 | code = MINUS_EXPR; |
9091 | break; |
9092 | case CPP_LSHIFT_EQ: |
9093 | code = LSHIFT_EXPR; |
9094 | break; |
9095 | case CPP_RSHIFT_EQ: |
9096 | code = RSHIFT_EXPR; |
9097 | break; |
9098 | case CPP_AND_EQ: |
9099 | code = BIT_AND_EXPR; |
9100 | break; |
9101 | case CPP_XOR_EQ: |
9102 | code = BIT_XOR_EXPR; |
9103 | break; |
9104 | case CPP_OR_EQ: |
9105 | code = BIT_IOR_EXPR; |
9106 | break; |
9107 | default: |
9108 | c_in_omp_for = save_in_omp_for; |
9109 | return lhs; |
9110 | } |
9111 | c_parser_consume_token (parser); |
9112 | exp_location = c_parser_peek_token (parser)->location; |
9113 | rhs = c_parser_expr_no_commas (parser, NULL); |
9114 | rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true); |
9115 | |
9116 | ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, |
9117 | code, exp_location, rhs.value, |
9118 | rhs.original_type); |
9119 | ret.m_decimal = 0; |
9120 | set_c_expr_source_range (expr: &ret, start: lhs.get_start (), finish: rhs.get_finish ()); |
9121 | if (code == NOP_EXPR) |
9122 | ret.original_code = MODIFY_EXPR; |
9123 | else |
9124 | { |
9125 | suppress_warning (ret.value, OPT_Wparentheses); |
9126 | ret.original_code = ERROR_MARK; |
9127 | } |
9128 | ret.original_type = NULL; |
9129 | c_in_omp_for = save_in_omp_for; |
9130 | return ret; |
9131 | } |
9132 | |
9133 | /* Parse a conditional expression (C90 6.3.15, C99 6.5.15, C11 6.5.15). If |
9134 | AFTER is not NULL then it is an Objective-C message expression which is |
9135 | the primary-expression starting the expression as an initializer. |
9136 | |
9137 | conditional-expression: |
9138 | logical-OR-expression |
9139 | logical-OR-expression ? expression : conditional-expression |
9140 | |
9141 | GNU extensions: |
9142 | |
9143 | conditional-expression: |
9144 | logical-OR-expression ? : conditional-expression |
9145 | */ |
9146 | |
9147 | static struct c_expr |
9148 | c_parser_conditional_expression (c_parser *parser, struct c_expr *after, |
9149 | tree omp_atomic_lhs) |
9150 | { |
9151 | struct c_expr cond, exp1, exp2, ret; |
9152 | location_t start, cond_loc, colon_loc; |
9153 | bool save_c_omp_array_section_p = c_omp_array_section_p; |
9154 | |
9155 | gcc_assert (!after || c_dialect_objc ()); |
9156 | |
9157 | cond = c_parser_binary_expression (parser, after, omp_atomic_lhs); |
9158 | |
9159 | if (c_parser_next_token_is_not (parser, type: CPP_QUERY)) |
9160 | return cond; |
9161 | c_omp_array_section_p = false; |
9162 | if (cond.value != error_mark_node) |
9163 | start = cond.get_start (); |
9164 | else |
9165 | start = UNKNOWN_LOCATION; |
9166 | cond_loc = c_parser_peek_token (parser)->location; |
9167 | cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true); |
9168 | c_parser_consume_token (parser); |
9169 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
9170 | { |
9171 | tree eptype = NULL_TREE; |
9172 | |
9173 | location_t middle_loc = c_parser_peek_token (parser)->location; |
9174 | pedwarn (middle_loc, OPT_Wpedantic, |
9175 | "ISO C forbids omitting the middle term of a %<?:%> expression" ); |
9176 | if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) |
9177 | { |
9178 | eptype = TREE_TYPE (cond.value); |
9179 | cond.value = TREE_OPERAND (cond.value, 0); |
9180 | } |
9181 | tree e = cond.value; |
9182 | while (TREE_CODE (e) == COMPOUND_EXPR) |
9183 | e = TREE_OPERAND (e, 1); |
9184 | warn_for_omitted_condop (middle_loc, e); |
9185 | /* Make sure first operand is calculated only once. */ |
9186 | exp1.value = save_expr (default_conversion (cond.value)); |
9187 | if (eptype) |
9188 | exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); |
9189 | exp1.original_type = NULL; |
9190 | exp1.src_range = cond.src_range; |
9191 | cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); |
9192 | c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node; |
9193 | } |
9194 | else |
9195 | { |
9196 | cond.value |
9197 | = c_objc_common_truthvalue_conversion |
9198 | (cond_loc, default_conversion (cond.value)); |
9199 | c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node; |
9200 | exp1 = c_parser_expression_conv (parser); |
9201 | mark_exp_read (exp1.value); |
9202 | c_inhibit_evaluation_warnings += |
9203 | ((cond.value == truthvalue_true_node) |
9204 | - (cond.value == truthvalue_false_node)); |
9205 | } |
9206 | |
9207 | colon_loc = c_parser_peek_token (parser)->location; |
9208 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
9209 | { |
9210 | c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; |
9211 | ret.set_error (); |
9212 | ret.original_code = ERROR_MARK; |
9213 | ret.original_type = NULL; |
9214 | c_omp_array_section_p = save_c_omp_array_section_p; |
9215 | return ret; |
9216 | } |
9217 | { |
9218 | location_t exp2_loc = c_parser_peek_token (parser)->location; |
9219 | exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE); |
9220 | exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true); |
9221 | } |
9222 | c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node; |
9223 | location_t loc1 = make_location (caret: exp1.get_start (), src_range: exp1.src_range); |
9224 | location_t loc2 = make_location (caret: exp2.get_start (), src_range: exp2.src_range); |
9225 | if (UNLIKELY (omp_atomic_lhs != NULL) |
9226 | && (TREE_CODE (cond.value) == GT_EXPR |
9227 | || TREE_CODE (cond.value) == LT_EXPR |
9228 | || TREE_CODE (cond.value) == EQ_EXPR) |
9229 | && c_tree_equal (exp2.value, omp_atomic_lhs) |
9230 | && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs) |
9231 | || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs))) |
9232 | ret.value = build3_loc (loc: colon_loc, code: COND_EXPR, TREE_TYPE (omp_atomic_lhs), |
9233 | arg0: cond.value, arg1: exp1.value, arg2: exp2.value); |
9234 | else |
9235 | ret.value |
9236 | = build_conditional_expr (colon_loc, cond.value, |
9237 | cond.original_code == C_MAYBE_CONST_EXPR, |
9238 | exp1.value, exp1.original_type, loc1, |
9239 | exp2.value, exp2.original_type, loc2); |
9240 | ret.original_code = ERROR_MARK; |
9241 | if (exp1.value == error_mark_node || exp2.value == error_mark_node) |
9242 | ret.original_type = NULL; |
9243 | else |
9244 | { |
9245 | tree t1, t2; |
9246 | |
9247 | /* If both sides are enum type, the default conversion will have |
9248 | made the type of the result be an integer type. We want to |
9249 | remember the enum types we started with. */ |
9250 | t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); |
9251 | t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); |
9252 | ret.original_type = ((t1 != error_mark_node |
9253 | && t2 != error_mark_node |
9254 | && (TYPE_MAIN_VARIANT (t1) |
9255 | == TYPE_MAIN_VARIANT (t2))) |
9256 | ? t1 |
9257 | : NULL); |
9258 | } |
9259 | set_c_expr_source_range (expr: &ret, start, finish: exp2.get_finish ()); |
9260 | ret.m_decimal = 0; |
9261 | c_omp_array_section_p = save_c_omp_array_section_p; |
9262 | return ret; |
9263 | } |
9264 | |
9265 | /* Parse a binary expression; that is, a logical-OR-expression (C90 |
9266 | 6.3.5-6.3.14, C99 6.5.5-6.5.14, C11 6.5.5-6.5.14). If AFTER is not |
9267 | NULL then it is an Objective-C message expression which is the |
9268 | primary-expression starting the expression as an initializer. |
9269 | |
9270 | OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic, |
9271 | when it should be the unfolded lhs. In a valid OpenMP source, |
9272 | one of the operands of the toplevel binary expression must be equal |
9273 | to it. In that case, just return a build2 created binary operation |
9274 | rather than result of parser_build_binary_op. |
9275 | |
9276 | multiplicative-expression: |
9277 | cast-expression |
9278 | multiplicative-expression * cast-expression |
9279 | multiplicative-expression / cast-expression |
9280 | multiplicative-expression % cast-expression |
9281 | |
9282 | additive-expression: |
9283 | multiplicative-expression |
9284 | additive-expression + multiplicative-expression |
9285 | additive-expression - multiplicative-expression |
9286 | |
9287 | shift-expression: |
9288 | additive-expression |
9289 | shift-expression << additive-expression |
9290 | shift-expression >> additive-expression |
9291 | |
9292 | relational-expression: |
9293 | shift-expression |
9294 | relational-expression < shift-expression |
9295 | relational-expression > shift-expression |
9296 | relational-expression <= shift-expression |
9297 | relational-expression >= shift-expression |
9298 | |
9299 | equality-expression: |
9300 | relational-expression |
9301 | equality-expression == relational-expression |
9302 | equality-expression != relational-expression |
9303 | |
9304 | AND-expression: |
9305 | equality-expression |
9306 | AND-expression & equality-expression |
9307 | |
9308 | exclusive-OR-expression: |
9309 | AND-expression |
9310 | exclusive-OR-expression ^ AND-expression |
9311 | |
9312 | inclusive-OR-expression: |
9313 | exclusive-OR-expression |
9314 | inclusive-OR-expression | exclusive-OR-expression |
9315 | |
9316 | logical-AND-expression: |
9317 | inclusive-OR-expression |
9318 | logical-AND-expression && inclusive-OR-expression |
9319 | |
9320 | logical-OR-expression: |
9321 | logical-AND-expression |
9322 | logical-OR-expression || logical-AND-expression |
9323 | */ |
9324 | |
9325 | static struct c_expr |
9326 | c_parser_binary_expression (c_parser *parser, struct c_expr *after, |
9327 | tree omp_atomic_lhs) |
9328 | { |
9329 | /* A binary expression is parsed using operator-precedence parsing, |
9330 | with the operands being cast expressions. All the binary |
9331 | operators are left-associative. Thus a binary expression is of |
9332 | form: |
9333 | |
9334 | E0 op1 E1 op2 E2 ... |
9335 | |
9336 | which we represent on a stack. On the stack, the precedence |
9337 | levels are strictly increasing. When a new operator is |
9338 | encountered of higher precedence than that at the top of the |
9339 | stack, it is pushed; its LHS is the top expression, and its RHS |
9340 | is everything parsed until it is popped. When a new operator is |
9341 | encountered with precedence less than or equal to that at the top |
9342 | of the stack, triples E[i-1] op[i] E[i] are popped and replaced |
9343 | by the result of the operation until the operator at the top of |
9344 | the stack has lower precedence than the new operator or there is |
9345 | only one element on the stack; then the top expression is the LHS |
9346 | of the new operator. In the case of logical AND and OR |
9347 | expressions, we also need to adjust c_inhibit_evaluation_warnings |
9348 | as appropriate when the operators are pushed and popped. */ |
9349 | |
9350 | struct { |
9351 | /* The expression at this stack level. */ |
9352 | struct c_expr expr; |
9353 | /* The precedence of the operator on its left, PREC_NONE at the |
9354 | bottom of the stack. */ |
9355 | enum c_parser_prec prec; |
9356 | /* The operation on its left. */ |
9357 | enum tree_code op; |
9358 | /* The source location of this operation. */ |
9359 | location_t loc; |
9360 | /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */ |
9361 | tree sizeof_arg; |
9362 | } stack[NUM_PRECS]; |
9363 | int sp; |
9364 | /* Location of the binary operator. */ |
9365 | location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */ |
9366 | #define POP \ |
9367 | do { \ |
9368 | switch (stack[sp].op) \ |
9369 | { \ |
9370 | case TRUTH_ANDIF_EXPR: \ |
9371 | c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ |
9372 | == truthvalue_false_node); \ |
9373 | break; \ |
9374 | case TRUTH_ORIF_EXPR: \ |
9375 | c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \ |
9376 | == truthvalue_true_node); \ |
9377 | break; \ |
9378 | case TRUNC_DIV_EXPR: \ |
9379 | if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \ |
9380 | || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \ |
9381 | && (stack[sp].expr.original_code == SIZEOF_EXPR \ |
9382 | || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \ |
9383 | { \ |
9384 | tree type0 = stack[sp - 1].sizeof_arg; \ |
9385 | tree type1 = stack[sp].sizeof_arg; \ |
9386 | tree first_arg = type0; \ |
9387 | if (!TYPE_P (type0)) \ |
9388 | type0 = TREE_TYPE (type0); \ |
9389 | if (!TYPE_P (type1)) \ |
9390 | type1 = TREE_TYPE (type1); \ |
9391 | if (POINTER_TYPE_P (type0) \ |
9392 | && comptypes (TREE_TYPE (type0), type1) \ |
9393 | && !(TREE_CODE (first_arg) == PARM_DECL \ |
9394 | && C_ARRAY_PARAMETER (first_arg) \ |
9395 | && warn_sizeof_array_argument)) \ |
9396 | { \ |
9397 | auto_diagnostic_group d; \ |
9398 | if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \ |
9399 | "division %<sizeof (%T) / sizeof (%T)%> " \ |
9400 | "does not compute the number of array " \ |
9401 | "elements", \ |
9402 | type0, type1)) \ |
9403 | if (DECL_P (first_arg)) \ |
9404 | inform (DECL_SOURCE_LOCATION (first_arg), \ |
9405 | "first %<sizeof%> operand was declared here"); \ |
9406 | } \ |
9407 | else if (TREE_CODE (type0) == ARRAY_TYPE \ |
9408 | && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \ |
9409 | && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \ |
9410 | maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \ |
9411 | stack[sp].sizeof_arg, type1); \ |
9412 | } \ |
9413 | break; \ |
9414 | default: \ |
9415 | break; \ |
9416 | } \ |
9417 | stack[sp - 1].expr \ |
9418 | = convert_lvalue_to_rvalue (stack[sp - 1].loc, \ |
9419 | stack[sp - 1].expr, true, true); \ |
9420 | stack[sp].expr \ |
9421 | = convert_lvalue_to_rvalue (stack[sp].loc, \ |
9422 | stack[sp].expr, true, true); \ |
9423 | if (UNLIKELY (omp_atomic_lhs != NULL_TREE) && sp == 1 \ |
9424 | && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \ |
9425 | && ((1 << stack[sp].prec) \ |
9426 | & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \ |
9427 | | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \ |
9428 | | (1 << PREC_ADD) | (1 << PREC_MULT) \ |
9429 | | (1 << PREC_EQ)))) \ |
9430 | || ((c_parser_next_token_is (parser, CPP_QUERY) \ |
9431 | || (omp_atomic_lhs == void_list_node \ |
9432 | && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \ |
9433 | && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\ |
9434 | && stack[sp].op != TRUNC_MOD_EXPR \ |
9435 | && stack[sp].op != GE_EXPR \ |
9436 | && stack[sp].op != LE_EXPR \ |
9437 | && stack[sp].op != NE_EXPR \ |
9438 | && stack[0].expr.value != error_mark_node \ |
9439 | && stack[1].expr.value != error_mark_node \ |
9440 | && (omp_atomic_lhs == void_list_node \ |
9441 | || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \ |
9442 | || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \ |
9443 | || (stack[sp].op == EQ_EXPR \ |
9444 | && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \ |
9445 | { \ |
9446 | tree t = make_node (stack[1].op); \ |
9447 | TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \ |
9448 | TREE_OPERAND (t, 0) = stack[0].expr.value; \ |
9449 | TREE_OPERAND (t, 1) = stack[1].expr.value; \ |
9450 | stack[0].expr.value = t; \ |
9451 | stack[0].expr.m_decimal = 0; \ |
9452 | } \ |
9453 | else \ |
9454 | stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ |
9455 | stack[sp].op, \ |
9456 | stack[sp - 1].expr, \ |
9457 | stack[sp].expr); \ |
9458 | sp--; \ |
9459 | } while (0) |
9460 | gcc_assert (!after || c_dialect_objc ()); |
9461 | stack[0].loc = c_parser_peek_token (parser)->location; |
9462 | stack[0].expr = c_parser_cast_expression (parser, after); |
9463 | stack[0].prec = PREC_NONE; |
9464 | stack[0].sizeof_arg = c_last_sizeof_arg; |
9465 | sp = 0; |
9466 | while (true) |
9467 | { |
9468 | enum c_parser_prec oprec; |
9469 | enum tree_code ocode; |
9470 | source_range src_range; |
9471 | if (parser->error) |
9472 | goto out; |
9473 | switch (c_parser_peek_token (parser)->type) |
9474 | { |
9475 | case CPP_MULT: |
9476 | oprec = PREC_MULT; |
9477 | ocode = MULT_EXPR; |
9478 | break; |
9479 | case CPP_DIV: |
9480 | oprec = PREC_MULT; |
9481 | ocode = TRUNC_DIV_EXPR; |
9482 | break; |
9483 | case CPP_MOD: |
9484 | oprec = PREC_MULT; |
9485 | ocode = TRUNC_MOD_EXPR; |
9486 | break; |
9487 | case CPP_PLUS: |
9488 | oprec = PREC_ADD; |
9489 | ocode = PLUS_EXPR; |
9490 | break; |
9491 | case CPP_MINUS: |
9492 | oprec = PREC_ADD; |
9493 | ocode = MINUS_EXPR; |
9494 | break; |
9495 | case CPP_LSHIFT: |
9496 | oprec = PREC_SHIFT; |
9497 | ocode = LSHIFT_EXPR; |
9498 | break; |
9499 | case CPP_RSHIFT: |
9500 | oprec = PREC_SHIFT; |
9501 | ocode = RSHIFT_EXPR; |
9502 | break; |
9503 | case CPP_LESS: |
9504 | oprec = PREC_REL; |
9505 | ocode = LT_EXPR; |
9506 | break; |
9507 | case CPP_GREATER: |
9508 | oprec = PREC_REL; |
9509 | ocode = GT_EXPR; |
9510 | break; |
9511 | case CPP_LESS_EQ: |
9512 | oprec = PREC_REL; |
9513 | ocode = LE_EXPR; |
9514 | break; |
9515 | case CPP_GREATER_EQ: |
9516 | oprec = PREC_REL; |
9517 | ocode = GE_EXPR; |
9518 | break; |
9519 | case CPP_EQ_EQ: |
9520 | oprec = PREC_EQ; |
9521 | ocode = EQ_EXPR; |
9522 | break; |
9523 | case CPP_NOT_EQ: |
9524 | oprec = PREC_EQ; |
9525 | ocode = NE_EXPR; |
9526 | break; |
9527 | case CPP_AND: |
9528 | oprec = PREC_BITAND; |
9529 | ocode = BIT_AND_EXPR; |
9530 | break; |
9531 | case CPP_XOR: |
9532 | oprec = PREC_BITXOR; |
9533 | ocode = BIT_XOR_EXPR; |
9534 | break; |
9535 | case CPP_OR: |
9536 | oprec = PREC_BITOR; |
9537 | ocode = BIT_IOR_EXPR; |
9538 | break; |
9539 | case CPP_AND_AND: |
9540 | oprec = PREC_LOGAND; |
9541 | ocode = TRUTH_ANDIF_EXPR; |
9542 | break; |
9543 | case CPP_OR_OR: |
9544 | oprec = PREC_LOGOR; |
9545 | ocode = TRUTH_ORIF_EXPR; |
9546 | break; |
9547 | default: |
9548 | /* Not a binary operator, so end of the binary |
9549 | expression. */ |
9550 | goto out; |
9551 | } |
9552 | binary_loc = c_parser_peek_token (parser)->location; |
9553 | while (oprec <= stack[sp].prec) |
9554 | POP; |
9555 | c_parser_consume_token (parser); |
9556 | switch (ocode) |
9557 | { |
9558 | case TRUTH_ANDIF_EXPR: |
9559 | src_range = stack[sp].expr.src_range; |
9560 | stack[sp].expr |
9561 | = convert_lvalue_to_rvalue (stack[sp].loc, |
9562 | stack[sp].expr, true, true); |
9563 | stack[sp].expr.value = c_objc_common_truthvalue_conversion |
9564 | (stack[sp].loc, default_conversion (stack[sp].expr.value)); |
9565 | c_inhibit_evaluation_warnings += (stack[sp].expr.value |
9566 | == truthvalue_false_node); |
9567 | set_c_expr_source_range (expr: &stack[sp].expr, src_range); |
9568 | break; |
9569 | case TRUTH_ORIF_EXPR: |
9570 | src_range = stack[sp].expr.src_range; |
9571 | stack[sp].expr |
9572 | = convert_lvalue_to_rvalue (stack[sp].loc, |
9573 | stack[sp].expr, true, true); |
9574 | stack[sp].expr.value = c_objc_common_truthvalue_conversion |
9575 | (stack[sp].loc, default_conversion (stack[sp].expr.value)); |
9576 | c_inhibit_evaluation_warnings += (stack[sp].expr.value |
9577 | == truthvalue_true_node); |
9578 | set_c_expr_source_range (expr: &stack[sp].expr, src_range); |
9579 | break; |
9580 | default: |
9581 | break; |
9582 | } |
9583 | sp++; |
9584 | stack[sp].loc = binary_loc; |
9585 | stack[sp].expr = c_parser_cast_expression (parser, NULL); |
9586 | stack[sp].prec = oprec; |
9587 | stack[sp].op = ocode; |
9588 | stack[sp].sizeof_arg = c_last_sizeof_arg; |
9589 | } |
9590 | out: |
9591 | while (sp > 0) |
9592 | POP; |
9593 | return stack[0].expr; |
9594 | #undef POP |
9595 | } |
9596 | |
9597 | /* Parse any storage class specifiers after an open parenthesis in a |
9598 | context where a compound literal is permitted. */ |
9599 | |
9600 | static struct c_declspecs * |
9601 | c_parser_compound_literal_scspecs (c_parser *parser) |
9602 | { |
9603 | bool seen_scspec = false; |
9604 | struct c_declspecs *specs = build_null_declspecs (); |
9605 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD)) |
9606 | { |
9607 | switch (c_parser_peek_token (parser)->keyword) |
9608 | { |
9609 | case RID_CONSTEXPR: |
9610 | case RID_REGISTER: |
9611 | case RID_STATIC: |
9612 | case RID_THREAD: |
9613 | seen_scspec = true; |
9614 | declspecs_add_scspec (c_parser_peek_token (parser)->location, |
9615 | specs, c_parser_peek_token (parser)->value); |
9616 | c_parser_consume_token (parser); |
9617 | break; |
9618 | default: |
9619 | goto out; |
9620 | } |
9621 | } |
9622 | out: |
9623 | return seen_scspec ? specs : NULL; |
9624 | } |
9625 | |
9626 | /* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4). If AFTER |
9627 | is not NULL then it is an Objective-C message expression which is the |
9628 | primary-expression starting the expression as an initializer. |
9629 | |
9630 | cast-expression: |
9631 | unary-expression |
9632 | ( type-name ) unary-expression |
9633 | */ |
9634 | |
9635 | static struct c_expr |
9636 | c_parser_cast_expression (c_parser *parser, struct c_expr *after) |
9637 | { |
9638 | location_t cast_loc = c_parser_peek_token (parser)->location; |
9639 | gcc_assert (!after || c_dialect_objc ()); |
9640 | if (after) |
9641 | return c_parser_postfix_expression_after_primary (parser, |
9642 | loc: cast_loc, *after); |
9643 | /* If the expression begins with a parenthesized type name, it may |
9644 | be either a cast or a compound literal; we need to see whether |
9645 | the next character is '{' to tell the difference. If not, it is |
9646 | an unary expression. Full detection of unknown typenames here |
9647 | would require a 3-token lookahead. */ |
9648 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
9649 | && c_token_starts_compound_literal (token: c_parser_peek_2nd_token (parser))) |
9650 | { |
9651 | struct c_declspecs *scspecs; |
9652 | struct c_type_name *type_name; |
9653 | struct c_expr ret; |
9654 | struct c_expr expr; |
9655 | matching_parens parens; |
9656 | parens.consume_open (parser); |
9657 | scspecs = c_parser_compound_literal_scspecs (parser); |
9658 | type_name = c_parser_type_name (parser, alignas_ok: true); |
9659 | parens.skip_until_found_close (parser); |
9660 | if (type_name == NULL) |
9661 | { |
9662 | ret.set_error (); |
9663 | ret.original_code = ERROR_MARK; |
9664 | ret.original_type = NULL; |
9665 | return ret; |
9666 | } |
9667 | |
9668 | /* Save casted types in the function's used types hash table. */ |
9669 | used_types_insert (type_name->specs->type); |
9670 | |
9671 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
9672 | return c_parser_postfix_expression_after_paren_type (parser, scspecs, |
9673 | type_name, |
9674 | cast_loc); |
9675 | if (scspecs) |
9676 | error_at (cast_loc, "storage class specifier in cast" ); |
9677 | if (type_name->specs->alignas_p) |
9678 | error_at (type_name->specs->locations[cdw_alignas], |
9679 | "alignment specified for type name in cast" ); |
9680 | { |
9681 | location_t expr_loc = c_parser_peek_token (parser)->location; |
9682 | expr = c_parser_cast_expression (parser, NULL); |
9683 | expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); |
9684 | } |
9685 | ret.value = c_cast_expr (cast_loc, type_name, expr.value); |
9686 | if (ret.value && expr.value) |
9687 | set_c_expr_source_range (expr: &ret, start: cast_loc, finish: expr.get_finish ()); |
9688 | ret.original_code = ERROR_MARK; |
9689 | ret.original_type = NULL; |
9690 | ret.m_decimal = 0; |
9691 | return ret; |
9692 | } |
9693 | else |
9694 | return c_parser_unary_expression (parser); |
9695 | } |
9696 | |
9697 | /* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3). |
9698 | |
9699 | unary-expression: |
9700 | postfix-expression |
9701 | ++ unary-expression |
9702 | -- unary-expression |
9703 | unary-operator cast-expression |
9704 | sizeof unary-expression |
9705 | sizeof ( type-name ) |
9706 | |
9707 | unary-operator: one of |
9708 | & * + - ~ ! |
9709 | |
9710 | GNU extensions: |
9711 | |
9712 | unary-expression: |
9713 | __alignof__ unary-expression |
9714 | __alignof__ ( type-name ) |
9715 | && identifier |
9716 | |
9717 | (C11 permits _Alignof with type names only.) |
9718 | |
9719 | unary-operator: one of |
9720 | __extension__ __real__ __imag__ |
9721 | |
9722 | Transactional Memory: |
9723 | |
9724 | unary-expression: |
9725 | transaction-expression |
9726 | |
9727 | In addition, the GNU syntax treats ++ and -- as unary operators, so |
9728 | they may be applied to cast expressions with errors for non-lvalues |
9729 | given later. */ |
9730 | |
9731 | static struct c_expr |
9732 | c_parser_unary_expression (c_parser *parser) |
9733 | { |
9734 | int ext; |
9735 | struct c_expr ret, op; |
9736 | location_t op_loc = c_parser_peek_token (parser)->location; |
9737 | location_t exp_loc; |
9738 | location_t finish; |
9739 | ret.original_code = ERROR_MARK; |
9740 | ret.original_type = NULL; |
9741 | switch (c_parser_peek_token (parser)->type) |
9742 | { |
9743 | case CPP_PLUS_PLUS: |
9744 | c_parser_consume_token (parser); |
9745 | exp_loc = c_parser_peek_token (parser)->location; |
9746 | op = c_parser_cast_expression (parser, NULL); |
9747 | |
9748 | op = default_function_array_read_conversion (exp_loc, op); |
9749 | return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op); |
9750 | case CPP_MINUS_MINUS: |
9751 | c_parser_consume_token (parser); |
9752 | exp_loc = c_parser_peek_token (parser)->location; |
9753 | op = c_parser_cast_expression (parser, NULL); |
9754 | |
9755 | op = default_function_array_read_conversion (exp_loc, op); |
9756 | return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op); |
9757 | case CPP_AND: |
9758 | c_parser_consume_token (parser); |
9759 | op = c_parser_cast_expression (parser, NULL); |
9760 | mark_exp_read (op.value); |
9761 | return parser_build_unary_op (op_loc, ADDR_EXPR, op); |
9762 | case CPP_MULT: |
9763 | { |
9764 | c_parser_consume_token (parser); |
9765 | exp_loc = c_parser_peek_token (parser)->location; |
9766 | op = c_parser_cast_expression (parser, NULL); |
9767 | finish = op.get_finish (); |
9768 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9769 | location_t combined_loc = make_location (caret: op_loc, start: op_loc, finish); |
9770 | ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR); |
9771 | ret.src_range.m_start = op_loc; |
9772 | ret.src_range.m_finish = finish; |
9773 | ret.m_decimal = 0; |
9774 | return ret; |
9775 | } |
9776 | case CPP_PLUS: |
9777 | if (!c_dialect_objc () && !in_system_header_at (loc: input_location)) |
9778 | warning_at (op_loc, |
9779 | OPT_Wtraditional, |
9780 | "traditional C rejects the unary plus operator" ); |
9781 | c_parser_consume_token (parser); |
9782 | exp_loc = c_parser_peek_token (parser)->location; |
9783 | op = c_parser_cast_expression (parser, NULL); |
9784 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9785 | return parser_build_unary_op (op_loc, CONVERT_EXPR, op); |
9786 | case CPP_MINUS: |
9787 | c_parser_consume_token (parser); |
9788 | exp_loc = c_parser_peek_token (parser)->location; |
9789 | op = c_parser_cast_expression (parser, NULL); |
9790 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9791 | return parser_build_unary_op (op_loc, NEGATE_EXPR, op); |
9792 | case CPP_COMPL: |
9793 | c_parser_consume_token (parser); |
9794 | exp_loc = c_parser_peek_token (parser)->location; |
9795 | op = c_parser_cast_expression (parser, NULL); |
9796 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9797 | return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); |
9798 | case CPP_NOT: |
9799 | c_parser_consume_token (parser); |
9800 | exp_loc = c_parser_peek_token (parser)->location; |
9801 | op = c_parser_cast_expression (parser, NULL); |
9802 | op = convert_lvalue_to_rvalue (exp_loc, op, true, true); |
9803 | return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op); |
9804 | case CPP_AND_AND: |
9805 | /* Refer to the address of a label as a pointer. */ |
9806 | c_parser_consume_token (parser); |
9807 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
9808 | { |
9809 | ret.value = finish_label_address_expr |
9810 | (c_parser_peek_token (parser)->value, op_loc); |
9811 | set_c_expr_source_range (expr: &ret, start: op_loc, |
9812 | finish: c_parser_peek_token (parser)->get_finish ()); |
9813 | c_parser_consume_token (parser); |
9814 | } |
9815 | else |
9816 | { |
9817 | c_parser_error (parser, gmsgid: "expected identifier" ); |
9818 | ret.set_error (); |
9819 | } |
9820 | return ret; |
9821 | case CPP_KEYWORD: |
9822 | switch (c_parser_peek_token (parser)->keyword) |
9823 | { |
9824 | case RID_SIZEOF: |
9825 | return c_parser_sizeof_expression (parser); |
9826 | case RID_ALIGNOF: |
9827 | return c_parser_alignof_expression (parser); |
9828 | case RID_BUILTIN_HAS_ATTRIBUTE: |
9829 | return c_parser_has_attribute_expression (parser); |
9830 | case RID_EXTENSION: |
9831 | c_parser_consume_token (parser); |
9832 | ext = disable_extension_diagnostics (); |
9833 | ret = c_parser_cast_expression (parser, NULL); |
9834 | restore_extension_diagnostics (flags: ext); |
9835 | return ret; |
9836 | case RID_REALPART: |
9837 | c_parser_consume_token (parser); |
9838 | exp_loc = c_parser_peek_token (parser)->location; |
9839 | op = c_parser_cast_expression (parser, NULL); |
9840 | op = default_function_array_conversion (exp_loc, op); |
9841 | return parser_build_unary_op (op_loc, REALPART_EXPR, op); |
9842 | case RID_IMAGPART: |
9843 | c_parser_consume_token (parser); |
9844 | exp_loc = c_parser_peek_token (parser)->location; |
9845 | op = c_parser_cast_expression (parser, NULL); |
9846 | op = default_function_array_conversion (exp_loc, op); |
9847 | return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); |
9848 | case RID_TRANSACTION_ATOMIC: |
9849 | case RID_TRANSACTION_RELAXED: |
9850 | return c_parser_transaction_expression (parser, |
9851 | c_parser_peek_token (parser)->keyword); |
9852 | default: |
9853 | return c_parser_postfix_expression (parser); |
9854 | } |
9855 | default: |
9856 | return c_parser_postfix_expression (parser); |
9857 | } |
9858 | } |
9859 | |
9860 | /* Parse a sizeof expression. */ |
9861 | |
9862 | static struct c_expr |
9863 | c_parser_sizeof_expression (c_parser *parser) |
9864 | { |
9865 | struct c_expr expr; |
9866 | struct c_expr result; |
9867 | location_t expr_loc; |
9868 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); |
9869 | |
9870 | location_t start; |
9871 | location_t finish = UNKNOWN_LOCATION; |
9872 | |
9873 | start = c_parser_peek_token (parser)->location; |
9874 | |
9875 | c_parser_consume_token (parser); |
9876 | c_inhibit_evaluation_warnings++; |
9877 | in_sizeof++; |
9878 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
9879 | && c_token_starts_compound_literal (token: c_parser_peek_2nd_token (parser))) |
9880 | { |
9881 | /* Either sizeof ( type-name ) or sizeof unary-expression |
9882 | starting with a compound literal. */ |
9883 | struct c_declspecs *scspecs; |
9884 | struct c_type_name *type_name; |
9885 | matching_parens parens; |
9886 | parens.consume_open (parser); |
9887 | expr_loc = c_parser_peek_token (parser)->location; |
9888 | scspecs = c_parser_compound_literal_scspecs (parser); |
9889 | type_name = c_parser_type_name (parser, alignas_ok: true); |
9890 | parens.skip_until_found_close (parser); |
9891 | finish = parser->tokens_buf[0].location; |
9892 | if (type_name == NULL) |
9893 | { |
9894 | struct c_expr ret; |
9895 | c_inhibit_evaluation_warnings--; |
9896 | in_sizeof--; |
9897 | ret.set_error (); |
9898 | ret.original_code = ERROR_MARK; |
9899 | ret.original_type = NULL; |
9900 | return ret; |
9901 | } |
9902 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
9903 | { |
9904 | expr = c_parser_postfix_expression_after_paren_type (parser, scspecs, |
9905 | type_name, |
9906 | expr_loc); |
9907 | finish = expr.get_finish (); |
9908 | goto sizeof_expr; |
9909 | } |
9910 | /* sizeof ( type-name ). */ |
9911 | if (scspecs) |
9912 | error_at (expr_loc, "storage class specifier in %<sizeof%>" ); |
9913 | if (type_name->specs->alignas_p) |
9914 | error_at (type_name->specs->locations[cdw_alignas], |
9915 | "alignment specified for type name in %<sizeof%>" ); |
9916 | c_inhibit_evaluation_warnings--; |
9917 | in_sizeof--; |
9918 | result = c_expr_sizeof_type (expr_loc, type_name); |
9919 | } |
9920 | else |
9921 | { |
9922 | expr_loc = c_parser_peek_token (parser)->location; |
9923 | expr = c_parser_unary_expression (parser); |
9924 | finish = expr.get_finish (); |
9925 | sizeof_expr: |
9926 | c_inhibit_evaluation_warnings--; |
9927 | in_sizeof--; |
9928 | mark_exp_read (expr.value); |
9929 | if (TREE_CODE (expr.value) == COMPONENT_REF |
9930 | && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) |
9931 | error_at (expr_loc, "%<sizeof%> applied to a bit-field" ); |
9932 | result = c_expr_sizeof_expr (expr_loc, expr); |
9933 | } |
9934 | if (finish == UNKNOWN_LOCATION) |
9935 | finish = start; |
9936 | set_c_expr_source_range (expr: &result, start, finish); |
9937 | return result; |
9938 | } |
9939 | |
9940 | /* Parse an alignof expression. */ |
9941 | |
9942 | static struct c_expr |
9943 | c_parser_alignof_expression (c_parser *parser) |
9944 | { |
9945 | struct c_expr expr; |
9946 | location_t start_loc = c_parser_peek_token (parser)->location; |
9947 | location_t end_loc; |
9948 | tree alignof_spelling = c_parser_peek_token (parser)->value; |
9949 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF)); |
9950 | bool is_c11_alignof = (strcmp (IDENTIFIER_POINTER (alignof_spelling), |
9951 | s2: "_Alignof" ) == 0 |
9952 | || strcmp (IDENTIFIER_POINTER (alignof_spelling), |
9953 | s2: "alignof" ) == 0); |
9954 | /* A diagnostic is not required for the use of this identifier in |
9955 | the implementation namespace; only diagnose it for the C11 or C23 |
9956 | spelling because of existing code using the other spellings. */ |
9957 | if (is_c11_alignof) |
9958 | { |
9959 | if (flag_isoc99) |
9960 | pedwarn_c99 (start_loc, opt: OPT_Wpedantic, "ISO C99 does not support %qE" , |
9961 | alignof_spelling); |
9962 | else |
9963 | pedwarn_c99 (start_loc, opt: OPT_Wpedantic, "ISO C90 does not support %qE" , |
9964 | alignof_spelling); |
9965 | } |
9966 | c_parser_consume_token (parser); |
9967 | c_inhibit_evaluation_warnings++; |
9968 | in_alignof++; |
9969 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
9970 | && c_token_starts_compound_literal (token: c_parser_peek_2nd_token (parser))) |
9971 | { |
9972 | /* Either __alignof__ ( type-name ) or __alignof__ |
9973 | unary-expression starting with a compound literal. */ |
9974 | location_t loc; |
9975 | struct c_declspecs *scspecs; |
9976 | struct c_type_name *type_name; |
9977 | struct c_expr ret; |
9978 | matching_parens parens; |
9979 | parens.consume_open (parser); |
9980 | loc = c_parser_peek_token (parser)->location; |
9981 | scspecs = c_parser_compound_literal_scspecs (parser); |
9982 | type_name = c_parser_type_name (parser, alignas_ok: true); |
9983 | end_loc = c_parser_peek_token (parser)->location; |
9984 | parens.skip_until_found_close (parser); |
9985 | if (type_name == NULL) |
9986 | { |
9987 | struct c_expr ret; |
9988 | c_inhibit_evaluation_warnings--; |
9989 | in_alignof--; |
9990 | ret.set_error (); |
9991 | ret.original_code = ERROR_MARK; |
9992 | ret.original_type = NULL; |
9993 | return ret; |
9994 | } |
9995 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
9996 | { |
9997 | expr = c_parser_postfix_expression_after_paren_type (parser, scspecs, |
9998 | type_name, |
9999 | loc); |
10000 | goto alignof_expr; |
10001 | } |
10002 | /* alignof ( type-name ). */ |
10003 | if (scspecs) |
10004 | error_at (loc, "storage class specifier in %qE" , alignof_spelling); |
10005 | if (type_name->specs->alignas_p) |
10006 | error_at (type_name->specs->locations[cdw_alignas], |
10007 | "alignment specified for type name in %qE" , |
10008 | alignof_spelling); |
10009 | c_inhibit_evaluation_warnings--; |
10010 | in_alignof--; |
10011 | ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name, |
10012 | NULL, NULL), |
10013 | false, is_c11_alignof, 1); |
10014 | ret.original_code = ERROR_MARK; |
10015 | ret.original_type = NULL; |
10016 | set_c_expr_source_range (expr: &ret, start: start_loc, finish: end_loc); |
10017 | ret.m_decimal = 0; |
10018 | return ret; |
10019 | } |
10020 | else |
10021 | { |
10022 | struct c_expr ret; |
10023 | expr = c_parser_unary_expression (parser); |
10024 | end_loc = expr.src_range.m_finish; |
10025 | alignof_expr: |
10026 | mark_exp_read (expr.value); |
10027 | c_inhibit_evaluation_warnings--; |
10028 | in_alignof--; |
10029 | if (is_c11_alignof) |
10030 | pedwarn (start_loc, |
10031 | OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>" , |
10032 | alignof_spelling); |
10033 | ret.value = c_alignof_expr (start_loc, expr.value); |
10034 | ret.original_code = ERROR_MARK; |
10035 | ret.original_type = NULL; |
10036 | set_c_expr_source_range (expr: &ret, start: start_loc, finish: end_loc); |
10037 | ret.m_decimal = 0; |
10038 | return ret; |
10039 | } |
10040 | } |
10041 | |
10042 | /* Parse the __builtin_has_attribute ([expr|type], attribute-spec) |
10043 | expression. */ |
10044 | |
10045 | static struct c_expr |
10046 | c_parser_has_attribute_expression (c_parser *parser) |
10047 | { |
10048 | gcc_assert (c_parser_next_token_is_keyword (parser, |
10049 | RID_BUILTIN_HAS_ATTRIBUTE)); |
10050 | location_t start = c_parser_peek_token (parser)->location; |
10051 | c_parser_consume_token (parser); |
10052 | |
10053 | c_inhibit_evaluation_warnings++; |
10054 | |
10055 | matching_parens parens; |
10056 | if (!parens.require_open (parser)) |
10057 | { |
10058 | c_inhibit_evaluation_warnings--; |
10059 | in_typeof--; |
10060 | |
10061 | struct c_expr result; |
10062 | result.set_error (); |
10063 | result.original_code = ERROR_MARK; |
10064 | result.original_type = NULL; |
10065 | return result; |
10066 | } |
10067 | |
10068 | /* Treat the type argument the same way as in typeof for the purposes |
10069 | of warnings. FIXME: Generalize this so the warning refers to |
10070 | __builtin_has_attribute rather than typeof. */ |
10071 | in_typeof++; |
10072 | |
10073 | /* The first operand: one of DECL, EXPR, or TYPE. */ |
10074 | tree oper = NULL_TREE; |
10075 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
10076 | { |
10077 | struct c_type_name *tname = c_parser_type_name (parser); |
10078 | in_typeof--; |
10079 | if (tname) |
10080 | { |
10081 | oper = groktypename (tname, NULL, NULL); |
10082 | pop_maybe_used (c_type_variably_modified_p (t: oper)); |
10083 | } |
10084 | } |
10085 | else |
10086 | { |
10087 | struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL); |
10088 | c_inhibit_evaluation_warnings--; |
10089 | in_typeof--; |
10090 | if (cexpr.value != error_mark_node) |
10091 | { |
10092 | mark_exp_read (cexpr.value); |
10093 | oper = cexpr.value; |
10094 | tree etype = TREE_TYPE (oper); |
10095 | bool was_vm = c_type_variably_modified_p (t: etype); |
10096 | /* This is returned with the type so that when the type is |
10097 | evaluated, this can be evaluated. */ |
10098 | if (was_vm) |
10099 | oper = c_fully_fold (oper, false, NULL); |
10100 | pop_maybe_used (was_vm); |
10101 | } |
10102 | } |
10103 | |
10104 | struct c_expr result; |
10105 | result.original_code = ERROR_MARK; |
10106 | result.original_type = NULL; |
10107 | |
10108 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10109 | { |
10110 | /* Consume the closing parenthesis if that's the next token |
10111 | in the likely case the built-in was invoked with fewer |
10112 | than two arguments. */ |
10113 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
10114 | c_parser_consume_token (parser); |
10115 | c_inhibit_evaluation_warnings--; |
10116 | result.set_error (); |
10117 | return result; |
10118 | } |
10119 | |
10120 | bool save_translate_strings_p = parser->translate_strings_p; |
10121 | |
10122 | location_t atloc = c_parser_peek_token (parser)->location; |
10123 | /* Parse a single attribute. Require no leading comma and do not |
10124 | allow empty attributes. */ |
10125 | tree attr = c_parser_gnu_attribute (parser, NULL_TREE, expect_comma: false, empty_ok: false); |
10126 | |
10127 | parser->translate_strings_p = save_translate_strings_p; |
10128 | |
10129 | location_t finish = c_parser_peek_token (parser)->location; |
10130 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
10131 | c_parser_consume_token (parser); |
10132 | else |
10133 | { |
10134 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10135 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10136 | |
10137 | result.set_error (); |
10138 | return result; |
10139 | } |
10140 | |
10141 | if (!attr) |
10142 | { |
10143 | error_at (atloc, "expected identifier" ); |
10144 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10145 | msgid: "expected %<)%>" ); |
10146 | result.set_error (); |
10147 | return result; |
10148 | } |
10149 | |
10150 | result.original_code = INTEGER_CST; |
10151 | result.original_type = boolean_type_node; |
10152 | |
10153 | if (has_attribute (atloc, oper, attr, default_conversion)) |
10154 | result.value = boolean_true_node; |
10155 | else |
10156 | result.value = boolean_false_node; |
10157 | |
10158 | set_c_expr_source_range (expr: &result, start, finish); |
10159 | result.m_decimal = 0; |
10160 | return result; |
10161 | } |
10162 | |
10163 | /* Helper function to read arguments of builtins which are interfaces |
10164 | for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and |
10165 | others. The name of the builtin is passed using BNAME parameter. |
10166 | Function returns true if there were no errors while parsing and |
10167 | stores the arguments in CEXPR_LIST. If it returns true, |
10168 | *OUT_CLOSE_PAREN_LOC is written to with the location of the closing |
10169 | parenthesis. */ |
10170 | static bool |
10171 | c_parser_get_builtin_args (c_parser *parser, const char *bname, |
10172 | vec<c_expr_t, va_gc> **ret_cexpr_list, |
10173 | bool choose_expr_p, |
10174 | location_t *out_close_paren_loc) |
10175 | { |
10176 | location_t loc = c_parser_peek_token (parser)->location; |
10177 | vec<c_expr_t, va_gc> *cexpr_list; |
10178 | c_expr_t expr; |
10179 | bool saved_force_folding_builtin_constant_p; |
10180 | |
10181 | *ret_cexpr_list = NULL; |
10182 | if (c_parser_next_token_is_not (parser, type: CPP_OPEN_PAREN)) |
10183 | { |
10184 | error_at (loc, "cannot take address of %qs" , bname); |
10185 | return false; |
10186 | } |
10187 | |
10188 | c_parser_consume_token (parser); |
10189 | |
10190 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
10191 | { |
10192 | *out_close_paren_loc = c_parser_peek_token (parser)->location; |
10193 | c_parser_consume_token (parser); |
10194 | return true; |
10195 | } |
10196 | |
10197 | saved_force_folding_builtin_constant_p |
10198 | = force_folding_builtin_constant_p; |
10199 | force_folding_builtin_constant_p |= choose_expr_p; |
10200 | expr = c_parser_expr_no_commas (parser, NULL); |
10201 | force_folding_builtin_constant_p |
10202 | = saved_force_folding_builtin_constant_p; |
10203 | vec_alloc (v&: cexpr_list, nelems: 1); |
10204 | vec_safe_push (v&: cexpr_list, obj: expr); |
10205 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
10206 | { |
10207 | c_parser_consume_token (parser); |
10208 | expr = c_parser_expr_no_commas (parser, NULL); |
10209 | vec_safe_push (v&: cexpr_list, obj: expr); |
10210 | } |
10211 | |
10212 | *out_close_paren_loc = c_parser_peek_token (parser)->location; |
10213 | if (!c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
10214 | return false; |
10215 | |
10216 | *ret_cexpr_list = cexpr_list; |
10217 | return true; |
10218 | } |
10219 | |
10220 | /* This represents a single generic-association. */ |
10221 | |
10222 | struct c_generic_association |
10223 | { |
10224 | /* The location of the starting token of the type. */ |
10225 | location_t type_location; |
10226 | /* The association's type, or NULL_TREE for 'default'. */ |
10227 | tree type; |
10228 | /* The association's expression. */ |
10229 | struct c_expr expression; |
10230 | }; |
10231 | |
10232 | /* Parse a generic-selection. (C11 6.5.1.1). |
10233 | |
10234 | generic-selection: |
10235 | _Generic ( assignment-expression , generic-assoc-list ) |
10236 | |
10237 | generic-assoc-list: |
10238 | generic-association |
10239 | generic-assoc-list , generic-association |
10240 | |
10241 | generic-association: |
10242 | type-name : assignment-expression |
10243 | default : assignment-expression |
10244 | */ |
10245 | |
10246 | static struct c_expr |
10247 | c_parser_generic_selection (c_parser *parser) |
10248 | { |
10249 | struct c_expr selector, error_expr; |
10250 | tree selector_type; |
10251 | struct c_generic_association matched_assoc; |
10252 | int match_found = -1; |
10253 | location_t generic_loc, selector_loc; |
10254 | |
10255 | error_expr.original_code = ERROR_MARK; |
10256 | error_expr.original_type = NULL; |
10257 | error_expr.set_error (); |
10258 | matched_assoc.type_location = UNKNOWN_LOCATION; |
10259 | matched_assoc.type = NULL_TREE; |
10260 | matched_assoc.expression = error_expr; |
10261 | |
10262 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC)); |
10263 | generic_loc = c_parser_peek_token (parser)->location; |
10264 | c_parser_consume_token (parser); |
10265 | if (flag_isoc99) |
10266 | pedwarn_c99 (generic_loc, opt: OPT_Wpedantic, |
10267 | "ISO C99 does not support %<_Generic%>" ); |
10268 | else |
10269 | pedwarn_c99 (generic_loc, opt: OPT_Wpedantic, |
10270 | "ISO C90 does not support %<_Generic%>" ); |
10271 | |
10272 | matching_parens parens; |
10273 | if (!parens.require_open (parser)) |
10274 | return error_expr; |
10275 | |
10276 | c_inhibit_evaluation_warnings++; |
10277 | selector_loc = c_parser_peek_token (parser)->location; |
10278 | selector = c_parser_expr_no_commas (parser, NULL); |
10279 | selector = default_function_array_conversion (selector_loc, selector); |
10280 | c_inhibit_evaluation_warnings--; |
10281 | |
10282 | if (selector.value == error_mark_node) |
10283 | { |
10284 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10285 | return selector; |
10286 | } |
10287 | mark_exp_read (selector.value); |
10288 | selector_type = TREE_TYPE (selector.value); |
10289 | /* In ISO C terms, rvalues (including the controlling expression of |
10290 | _Generic) do not have qualified types. */ |
10291 | if (TREE_CODE (selector_type) != ARRAY_TYPE) |
10292 | selector_type = TYPE_MAIN_VARIANT (selector_type); |
10293 | /* In ISO C terms, _Noreturn is not part of the type of expressions |
10294 | such as &abort, but in GCC it is represented internally as a type |
10295 | qualifier. */ |
10296 | if (FUNCTION_POINTER_TYPE_P (selector_type) |
10297 | && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED) |
10298 | selector_type |
10299 | = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type))); |
10300 | |
10301 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10302 | { |
10303 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10304 | return error_expr; |
10305 | } |
10306 | |
10307 | auto_vec<c_generic_association> associations; |
10308 | while (1) |
10309 | { |
10310 | struct c_generic_association assoc, *iter; |
10311 | unsigned int ix; |
10312 | c_token *token = c_parser_peek_token (parser); |
10313 | |
10314 | assoc.type_location = token->location; |
10315 | if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT) |
10316 | { |
10317 | c_parser_consume_token (parser); |
10318 | assoc.type = NULL_TREE; |
10319 | } |
10320 | else |
10321 | { |
10322 | struct c_type_name *type_name; |
10323 | |
10324 | type_name = c_parser_type_name (parser); |
10325 | if (type_name == NULL) |
10326 | { |
10327 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10328 | return error_expr; |
10329 | } |
10330 | assoc.type = groktypename (type_name, NULL, NULL); |
10331 | if (assoc.type == error_mark_node) |
10332 | { |
10333 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10334 | return error_expr; |
10335 | } |
10336 | |
10337 | if (TREE_CODE (assoc.type) == FUNCTION_TYPE) |
10338 | error_at (assoc.type_location, |
10339 | "%<_Generic%> association has function type" ); |
10340 | else if (!COMPLETE_TYPE_P (assoc.type)) |
10341 | error_at (assoc.type_location, |
10342 | "%<_Generic%> association has incomplete type" ); |
10343 | |
10344 | if (c_type_variably_modified_p (t: assoc.type)) |
10345 | error_at (assoc.type_location, |
10346 | "%<_Generic%> association has " |
10347 | "variable length type" ); |
10348 | } |
10349 | |
10350 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
10351 | { |
10352 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10353 | return error_expr; |
10354 | } |
10355 | |
10356 | bool match = assoc.type == NULL_TREE |
10357 | || comptypes (assoc.type, selector_type); |
10358 | |
10359 | if (!match) |
10360 | c_inhibit_evaluation_warnings++; |
10361 | |
10362 | assoc.expression = c_parser_expr_no_commas (parser, NULL); |
10363 | |
10364 | if (!match) |
10365 | c_inhibit_evaluation_warnings--; |
10366 | |
10367 | if (assoc.expression.value == error_mark_node) |
10368 | { |
10369 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10370 | return error_expr; |
10371 | } |
10372 | |
10373 | for (ix = 0; associations.iterate (ix, ptr: &iter); ++ix) |
10374 | { |
10375 | if (assoc.type == NULL_TREE) |
10376 | { |
10377 | if (iter->type == NULL_TREE) |
10378 | { |
10379 | error_at (assoc.type_location, |
10380 | "duplicate %<default%> case in %<_Generic%>" ); |
10381 | inform (iter->type_location, "original %<default%> is here" ); |
10382 | } |
10383 | } |
10384 | else if (iter->type != NULL_TREE) |
10385 | { |
10386 | if (comptypes (assoc.type, iter->type)) |
10387 | { |
10388 | error_at (assoc.type_location, |
10389 | "%<_Generic%> specifies two compatible types" ); |
10390 | inform (iter->type_location, "compatible type is here" ); |
10391 | } |
10392 | } |
10393 | } |
10394 | |
10395 | if (assoc.type == NULL_TREE) |
10396 | { |
10397 | if (match_found < 0) |
10398 | { |
10399 | matched_assoc = assoc; |
10400 | match_found = associations.length (); |
10401 | } |
10402 | } |
10403 | else if (match) |
10404 | { |
10405 | if (match_found < 0 || matched_assoc.type == NULL_TREE) |
10406 | { |
10407 | matched_assoc = assoc; |
10408 | match_found = associations.length (); |
10409 | } |
10410 | else |
10411 | { |
10412 | error_at (assoc.type_location, |
10413 | "%<_Generic%> selector matches multiple associations" ); |
10414 | inform (matched_assoc.type_location, |
10415 | "other match is here" ); |
10416 | } |
10417 | } |
10418 | |
10419 | associations.safe_push (obj: assoc); |
10420 | |
10421 | if (c_parser_peek_token (parser)->type != CPP_COMMA) |
10422 | break; |
10423 | c_parser_consume_token (parser); |
10424 | } |
10425 | |
10426 | unsigned int ix; |
10427 | struct c_generic_association *iter; |
10428 | FOR_EACH_VEC_ELT (associations, ix, iter) |
10429 | if (ix != (unsigned) match_found) |
10430 | mark_exp_read (iter->expression.value); |
10431 | |
10432 | if (!parens.require_close (parser)) |
10433 | { |
10434 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10435 | return error_expr; |
10436 | } |
10437 | |
10438 | if (match_found < 0) |
10439 | { |
10440 | error_at (selector_loc, "%<_Generic%> selector of type %qT is not " |
10441 | "compatible with any association" , |
10442 | selector_type); |
10443 | return error_expr; |
10444 | } |
10445 | |
10446 | return matched_assoc.expression; |
10447 | } |
10448 | |
10449 | /* Check the validity of a function pointer argument *EXPR (argument |
10450 | position POS) to __builtin_tgmath. Return the number of function |
10451 | arguments if possibly valid; return 0 having reported an error if |
10452 | not valid. */ |
10453 | |
10454 | static unsigned int |
10455 | check_tgmath_function (c_expr *expr, unsigned int pos) |
10456 | { |
10457 | tree type = TREE_TYPE (expr->value); |
10458 | if (!FUNCTION_POINTER_TYPE_P (type)) |
10459 | { |
10460 | error_at (expr->get_location (), |
10461 | "argument %u of %<__builtin_tgmath%> is not a function pointer" , |
10462 | pos); |
10463 | return 0; |
10464 | } |
10465 | type = TREE_TYPE (type); |
10466 | if (!prototype_p (type)) |
10467 | { |
10468 | error_at (expr->get_location (), |
10469 | "argument %u of %<__builtin_tgmath%> is unprototyped" , pos); |
10470 | return 0; |
10471 | } |
10472 | if (stdarg_p (type)) |
10473 | { |
10474 | error_at (expr->get_location (), |
10475 | "argument %u of %<__builtin_tgmath%> has variable arguments" , |
10476 | pos); |
10477 | return 0; |
10478 | } |
10479 | unsigned int nargs = 0; |
10480 | function_args_iterator iter; |
10481 | tree t; |
10482 | FOREACH_FUNCTION_ARGS (type, t, iter) |
10483 | { |
10484 | if (t == void_type_node) |
10485 | break; |
10486 | nargs++; |
10487 | } |
10488 | if (nargs == 0) |
10489 | { |
10490 | error_at (expr->get_location (), |
10491 | "argument %u of %<__builtin_tgmath%> has no arguments" , pos); |
10492 | return 0; |
10493 | } |
10494 | return nargs; |
10495 | } |
10496 | |
10497 | /* Ways in which a parameter or return value of a type-generic macro |
10498 | may vary between the different functions the macro may call. */ |
10499 | enum tgmath_parm_kind |
10500 | { |
10501 | tgmath_fixed, tgmath_real, tgmath_complex |
10502 | }; |
10503 | |
10504 | /* Helper function for c_parser_postfix_expression. Parse predefined |
10505 | identifiers. */ |
10506 | |
10507 | static struct c_expr |
10508 | c_parser_predefined_identifier (c_parser *parser) |
10509 | { |
10510 | location_t loc = c_parser_peek_token (parser)->location; |
10511 | switch (c_parser_peek_token (parser)->keyword) |
10512 | { |
10513 | case RID_FUNCTION_NAME: |
10514 | pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " |
10515 | "identifier" , "__FUNCTION__" ); |
10516 | break; |
10517 | case RID_PRETTY_FUNCTION_NAME: |
10518 | pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " |
10519 | "identifier" , "__PRETTY_FUNCTION__" ); |
10520 | break; |
10521 | case RID_C99_FUNCTION_NAME: |
10522 | pedwarn_c90 (loc, opt: OPT_Wpedantic, "ISO C90 does not support " |
10523 | "%<__func__%> predefined identifier" ); |
10524 | break; |
10525 | default: |
10526 | gcc_unreachable (); |
10527 | } |
10528 | |
10529 | struct c_expr expr; |
10530 | expr.original_code = ERROR_MARK; |
10531 | expr.original_type = NULL; |
10532 | expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, |
10533 | c_parser_peek_token (parser)->value); |
10534 | set_c_expr_source_range (expr: &expr, start: loc, finish: loc); |
10535 | expr.m_decimal = 0; |
10536 | c_parser_consume_token (parser); |
10537 | return expr; |
10538 | } |
10539 | |
10540 | /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2, |
10541 | C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to |
10542 | call c_parser_postfix_expression_after_paren_type on encountering them. |
10543 | |
10544 | postfix-expression: |
10545 | primary-expression |
10546 | postfix-expression [ expression ] |
10547 | postfix-expression ( argument-expression-list[opt] ) |
10548 | postfix-expression . identifier |
10549 | postfix-expression -> identifier |
10550 | postfix-expression ++ |
10551 | postfix-expression -- |
10552 | ( storage-class-specifiers[opt] type-name ) { initializer-list[opt] } |
10553 | ( storage-class-specifiers[opt] type-name ) { initializer-list , } |
10554 | |
10555 | argument-expression-list: |
10556 | argument-expression |
10557 | argument-expression-list , argument-expression |
10558 | |
10559 | primary-expression: |
10560 | identifier |
10561 | constant |
10562 | string-literal |
10563 | ( expression ) |
10564 | generic-selection |
10565 | |
10566 | GNU extensions: |
10567 | |
10568 | primary-expression: |
10569 | __func__ |
10570 | (treated as a keyword in GNU C) |
10571 | __FUNCTION__ |
10572 | __PRETTY_FUNCTION__ |
10573 | ( compound-statement ) |
10574 | __builtin_va_arg ( assignment-expression , type-name ) |
10575 | __builtin_offsetof ( type-name , offsetof-member-designator ) |
10576 | __builtin_choose_expr ( assignment-expression , |
10577 | assignment-expression , |
10578 | assignment-expression ) |
10579 | __builtin_types_compatible_p ( type-name , type-name ) |
10580 | __builtin_tgmath ( expr-list ) |
10581 | __builtin_complex ( assignment-expression , assignment-expression ) |
10582 | __builtin_shuffle ( assignment-expression , assignment-expression ) |
10583 | __builtin_shuffle ( assignment-expression , |
10584 | assignment-expression , |
10585 | assignment-expression, ) |
10586 | __builtin_convertvector ( assignment-expression , type-name ) |
10587 | __builtin_assoc_barrier ( assignment-expression ) |
10588 | |
10589 | offsetof-member-designator: |
10590 | identifier |
10591 | offsetof-member-designator . identifier |
10592 | offsetof-member-designator [ expression ] |
10593 | |
10594 | Objective-C: |
10595 | |
10596 | primary-expression: |
10597 | [ objc-receiver objc-message-args ] |
10598 | @selector ( objc-selector-arg ) |
10599 | @protocol ( identifier ) |
10600 | @encode ( type-name ) |
10601 | objc-string-literal |
10602 | Classname . identifier |
10603 | */ |
10604 | |
10605 | static struct c_expr |
10606 | c_parser_postfix_expression (c_parser *parser) |
10607 | { |
10608 | struct c_expr expr, e1; |
10609 | struct c_type_name *t1, *t2; |
10610 | location_t loc = c_parser_peek_token (parser)->location; |
10611 | source_range tok_range = c_parser_peek_token (parser)->get_range (); |
10612 | expr.original_code = ERROR_MARK; |
10613 | expr.original_type = NULL; |
10614 | expr.m_decimal = 0; |
10615 | switch (c_parser_peek_token (parser)->type) |
10616 | { |
10617 | case CPP_NUMBER: |
10618 | expr.value = c_parser_peek_token (parser)->value; |
10619 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10620 | loc = c_parser_peek_token (parser)->location; |
10621 | expr.m_decimal = c_parser_peek_token (parser)->flags & DECIMAL_INT; |
10622 | c_parser_consume_token (parser); |
10623 | if (TREE_CODE (expr.value) == FIXED_CST |
10624 | && !targetm.fixed_point_supported_p ()) |
10625 | { |
10626 | error_at (loc, "fixed-point types not supported for this target" ); |
10627 | expr.set_error (); |
10628 | } |
10629 | break; |
10630 | case CPP_CHAR: |
10631 | case CPP_CHAR16: |
10632 | case CPP_CHAR32: |
10633 | case CPP_UTF8CHAR: |
10634 | case CPP_WCHAR: |
10635 | expr.value = c_parser_peek_token (parser)->value; |
10636 | /* For the purpose of warning when a pointer is compared with |
10637 | a zero character constant. */ |
10638 | expr.original_type = char_type_node; |
10639 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10640 | c_parser_consume_token (parser); |
10641 | break; |
10642 | case CPP_STRING: |
10643 | case CPP_STRING16: |
10644 | case CPP_STRING32: |
10645 | case CPP_WSTRING: |
10646 | case CPP_UTF8STRING: |
10647 | expr = c_parser_string_literal (parser, translate: parser->translate_strings_p, |
10648 | wide_ok: true); |
10649 | break; |
10650 | case CPP_OBJC_STRING: |
10651 | gcc_assert (c_dialect_objc ()); |
10652 | expr.value |
10653 | = objc_build_string_object (c_parser_peek_token (parser)->value); |
10654 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10655 | c_parser_consume_token (parser); |
10656 | break; |
10657 | case CPP_NAME: |
10658 | switch (c_parser_peek_token (parser)->id_kind) |
10659 | { |
10660 | case C_ID_ID: |
10661 | { |
10662 | tree id = c_parser_peek_token (parser)->value; |
10663 | c_parser_consume_token (parser); |
10664 | expr.value = build_external_ref (loc, id, |
10665 | (c_parser_peek_token (parser)->type |
10666 | == CPP_OPEN_PAREN), |
10667 | &expr.original_type); |
10668 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
10669 | break; |
10670 | } |
10671 | case C_ID_CLASSNAME: |
10672 | { |
10673 | /* Here we parse the Objective-C 2.0 Class.name dot |
10674 | syntax. */ |
10675 | tree class_name = c_parser_peek_token (parser)->value; |
10676 | tree component; |
10677 | c_parser_consume_token (parser); |
10678 | gcc_assert (c_dialect_objc ()); |
10679 | if (!c_parser_require (parser, type: CPP_DOT, msgid: "expected %<.%>" )) |
10680 | { |
10681 | expr.set_error (); |
10682 | break; |
10683 | } |
10684 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
10685 | { |
10686 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10687 | expr.set_error (); |
10688 | break; |
10689 | } |
10690 | c_token *component_tok = c_parser_peek_token (parser); |
10691 | component = component_tok->value; |
10692 | location_t end_loc = component_tok->get_finish (); |
10693 | c_parser_consume_token (parser); |
10694 | expr.value = objc_build_class_component_ref (class_name, |
10695 | component); |
10696 | set_c_expr_source_range (expr: &expr, start: loc, finish: end_loc); |
10697 | break; |
10698 | } |
10699 | default: |
10700 | c_parser_error (parser, gmsgid: "expected expression" ); |
10701 | expr.set_error (); |
10702 | break; |
10703 | } |
10704 | break; |
10705 | case CPP_OPEN_PAREN: |
10706 | /* A parenthesized expression, statement expression or compound |
10707 | literal. */ |
10708 | if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE) |
10709 | { |
10710 | /* A statement expression. */ |
10711 | tree stmt; |
10712 | location_t brace_loc; |
10713 | bool save_c_omp_array_section_p = c_omp_array_section_p; |
10714 | c_parser_consume_token (parser); |
10715 | brace_loc = c_parser_peek_token (parser)->location; |
10716 | c_parser_consume_token (parser); |
10717 | /* If we've not yet started the current function's statement list, |
10718 | or we're in the parameter scope of an old-style function |
10719 | declaration, statement expressions are not allowed. */ |
10720 | if (!building_stmt_list_p () || old_style_parameter_scope ()) |
10721 | { |
10722 | error_at (loc, "braced-group within expression allowed " |
10723 | "only inside a function" ); |
10724 | parser->error = true; |
10725 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, NULL); |
10726 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10727 | expr.set_error (); |
10728 | break; |
10729 | } |
10730 | c_omp_array_section_p = false; |
10731 | stmt = c_begin_stmt_expr (); |
10732 | c_parser_compound_statement_nostart (parser); |
10733 | location_t close_loc = c_parser_peek_token (parser)->location; |
10734 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10735 | msgid: "expected %<)%>" ); |
10736 | pedwarn (loc, OPT_Wpedantic, |
10737 | "ISO C forbids braced-groups within expressions" ); |
10738 | expr.value = c_finish_stmt_expr (brace_loc, stmt); |
10739 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
10740 | mark_exp_read (expr.value); |
10741 | c_omp_array_section_p = save_c_omp_array_section_p; |
10742 | } |
10743 | else |
10744 | { |
10745 | /* A parenthesized expression. */ |
10746 | location_t loc_open_paren = c_parser_peek_token (parser)->location; |
10747 | c_parser_consume_token (parser); |
10748 | expr = c_parser_expression (parser); |
10749 | if (TREE_CODE (expr.value) == MODIFY_EXPR) |
10750 | suppress_warning (expr.value, OPT_Wparentheses); |
10751 | if (expr.original_code != C_MAYBE_CONST_EXPR |
10752 | && expr.original_code != SIZEOF_EXPR) |
10753 | expr.original_code = ERROR_MARK; |
10754 | /* Remember that we saw ( ) around the sizeof. */ |
10755 | if (expr.original_code == SIZEOF_EXPR) |
10756 | expr.original_code = PAREN_SIZEOF_EXPR; |
10757 | /* Don't change EXPR.ORIGINAL_TYPE. */ |
10758 | location_t loc_close_paren = c_parser_peek_token (parser)->location; |
10759 | set_c_expr_source_range (expr: &expr, start: loc_open_paren, finish: loc_close_paren); |
10760 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10761 | msgid: "expected %<)%>" , matching_location: loc_open_paren); |
10762 | } |
10763 | break; |
10764 | case CPP_KEYWORD: |
10765 | switch (c_parser_peek_token (parser)->keyword) |
10766 | { |
10767 | case RID_FUNCTION_NAME: |
10768 | case RID_PRETTY_FUNCTION_NAME: |
10769 | case RID_C99_FUNCTION_NAME: |
10770 | expr = c_parser_predefined_identifier (parser); |
10771 | break; |
10772 | case RID_VA_ARG: |
10773 | { |
10774 | location_t start_loc = loc; |
10775 | c_parser_consume_token (parser); |
10776 | matching_parens parens; |
10777 | if (!parens.require_open (parser)) |
10778 | { |
10779 | expr.set_error (); |
10780 | break; |
10781 | } |
10782 | e1 = c_parser_expr_no_commas (parser, NULL); |
10783 | mark_exp_read (e1.value); |
10784 | e1.value = c_fully_fold (e1.value, false, NULL); |
10785 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10786 | { |
10787 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10788 | expr.set_error (); |
10789 | break; |
10790 | } |
10791 | loc = c_parser_peek_token (parser)->location; |
10792 | t1 = c_parser_type_name (parser); |
10793 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
10794 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10795 | msgid: "expected %<)%>" ); |
10796 | if (t1 == NULL) |
10797 | { |
10798 | expr.set_error (); |
10799 | } |
10800 | else |
10801 | { |
10802 | tree type_expr = NULL_TREE; |
10803 | expr.value = c_build_va_arg (start_loc, e1.value, loc, |
10804 | groktypename (t1, &type_expr, NULL)); |
10805 | if (type_expr) |
10806 | { |
10807 | expr.value = build2 (C_MAYBE_CONST_EXPR, |
10808 | TREE_TYPE (expr.value), type_expr, |
10809 | expr.value); |
10810 | C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; |
10811 | } |
10812 | set_c_expr_source_range (expr: &expr, start: start_loc, finish: end_loc); |
10813 | } |
10814 | } |
10815 | break; |
10816 | case RID_OFFSETOF: |
10817 | { |
10818 | c_parser_consume_token (parser); |
10819 | matching_parens parens; |
10820 | if (!parens.require_open (parser)) |
10821 | { |
10822 | expr.set_error (); |
10823 | break; |
10824 | } |
10825 | t1 = c_parser_type_name (parser); |
10826 | if (t1 == NULL) |
10827 | parser->error = true; |
10828 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10829 | gcc_assert (parser->error); |
10830 | if (parser->error) |
10831 | { |
10832 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10833 | expr.set_error (); |
10834 | break; |
10835 | } |
10836 | tree type = groktypename (t1, NULL, NULL); |
10837 | tree offsetof_ref; |
10838 | if (type == error_mark_node) |
10839 | offsetof_ref = error_mark_node; |
10840 | else |
10841 | { |
10842 | offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node); |
10843 | SET_EXPR_LOCATION (offsetof_ref, loc); |
10844 | } |
10845 | /* Parse the second argument to __builtin_offsetof. We |
10846 | must have one identifier, and beyond that we want to |
10847 | accept sub structure and sub array references. */ |
10848 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
10849 | { |
10850 | c_token *comp_tok = c_parser_peek_token (parser); |
10851 | offsetof_ref |
10852 | = build_component_ref (loc, offsetof_ref, comp_tok->value, |
10853 | comp_tok->location, UNKNOWN_LOCATION); |
10854 | c_parser_consume_token (parser); |
10855 | while (c_parser_next_token_is (parser, type: CPP_DOT) |
10856 | || c_parser_next_token_is (parser, |
10857 | type: CPP_OPEN_SQUARE) |
10858 | || c_parser_next_token_is (parser, |
10859 | type: CPP_DEREF)) |
10860 | { |
10861 | if (c_parser_next_token_is (parser, type: CPP_DEREF)) |
10862 | { |
10863 | loc = c_parser_peek_token (parser)->location; |
10864 | offsetof_ref = build_array_ref (loc, |
10865 | offsetof_ref, |
10866 | integer_zero_node); |
10867 | goto do_dot; |
10868 | } |
10869 | else if (c_parser_next_token_is (parser, type: CPP_DOT)) |
10870 | { |
10871 | do_dot: |
10872 | c_parser_consume_token (parser); |
10873 | if (c_parser_next_token_is_not (parser, |
10874 | type: CPP_NAME)) |
10875 | { |
10876 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10877 | break; |
10878 | } |
10879 | c_token *comp_tok = c_parser_peek_token (parser); |
10880 | offsetof_ref |
10881 | = build_component_ref (loc, offsetof_ref, |
10882 | comp_tok->value, |
10883 | comp_tok->location, |
10884 | UNKNOWN_LOCATION); |
10885 | c_parser_consume_token (parser); |
10886 | } |
10887 | else |
10888 | { |
10889 | struct c_expr ce; |
10890 | tree idx; |
10891 | loc = c_parser_peek_token (parser)->location; |
10892 | c_parser_consume_token (parser); |
10893 | ce = c_parser_expression (parser); |
10894 | ce = convert_lvalue_to_rvalue (loc, ce, false, false); |
10895 | idx = ce.value; |
10896 | idx = c_fully_fold (idx, false, NULL); |
10897 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
10898 | msgid: "expected %<]%>" ); |
10899 | offsetof_ref = build_array_ref (loc, offsetof_ref, idx); |
10900 | } |
10901 | } |
10902 | } |
10903 | else |
10904 | c_parser_error (parser, gmsgid: "expected identifier" ); |
10905 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
10906 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
10907 | msgid: "expected %<)%>" ); |
10908 | expr.value = fold_offsetof (offsetof_ref); |
10909 | set_c_expr_source_range (expr: &expr, start: loc, finish: end_loc); |
10910 | } |
10911 | break; |
10912 | case RID_CHOOSE_EXPR: |
10913 | { |
10914 | vec<c_expr_t, va_gc> *cexpr_list; |
10915 | c_expr_t *e1_p, *e2_p, *e3_p; |
10916 | tree c; |
10917 | location_t close_paren_loc; |
10918 | |
10919 | c_parser_consume_token (parser); |
10920 | if (!c_parser_get_builtin_args (parser, |
10921 | bname: "__builtin_choose_expr" , |
10922 | ret_cexpr_list: &cexpr_list, choose_expr_p: true, |
10923 | out_close_paren_loc: &close_paren_loc)) |
10924 | { |
10925 | expr.set_error (); |
10926 | break; |
10927 | } |
10928 | |
10929 | if (vec_safe_length (v: cexpr_list) != 3) |
10930 | { |
10931 | error_at (loc, "wrong number of arguments to " |
10932 | "%<__builtin_choose_expr%>" ); |
10933 | expr.set_error (); |
10934 | break; |
10935 | } |
10936 | |
10937 | e1_p = &(*cexpr_list)[0]; |
10938 | e2_p = &(*cexpr_list)[1]; |
10939 | e3_p = &(*cexpr_list)[2]; |
10940 | |
10941 | c = e1_p->value; |
10942 | mark_exp_read (e2_p->value); |
10943 | mark_exp_read (e3_p->value); |
10944 | if (TREE_CODE (c) != INTEGER_CST |
10945 | || !INTEGRAL_TYPE_P (TREE_TYPE (c))) |
10946 | error_at (loc, |
10947 | "first argument to %<__builtin_choose_expr%> not" |
10948 | " a constant" ); |
10949 | constant_expression_warning (c); |
10950 | expr = integer_zerop (c) ? *e3_p : *e2_p; |
10951 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
10952 | break; |
10953 | } |
10954 | case RID_TYPES_COMPATIBLE_P: |
10955 | { |
10956 | c_parser_consume_token (parser); |
10957 | matching_parens parens; |
10958 | if (!parens.require_open (parser)) |
10959 | { |
10960 | expr.set_error (); |
10961 | break; |
10962 | } |
10963 | t1 = c_parser_type_name (parser); |
10964 | if (t1 == NULL) |
10965 | { |
10966 | expr.set_error (); |
10967 | break; |
10968 | } |
10969 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
10970 | { |
10971 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
10972 | expr.set_error (); |
10973 | break; |
10974 | } |
10975 | t2 = c_parser_type_name (parser); |
10976 | if (t2 == NULL) |
10977 | { |
10978 | expr.set_error (); |
10979 | break; |
10980 | } |
10981 | location_t close_paren_loc = c_parser_peek_token (parser)->location; |
10982 | parens.skip_until_found_close (parser); |
10983 | tree e1, e2; |
10984 | e1 = groktypename (t1, NULL, NULL); |
10985 | e2 = groktypename (t2, NULL, NULL); |
10986 | if (e1 == error_mark_node || e2 == error_mark_node) |
10987 | { |
10988 | expr.set_error (); |
10989 | break; |
10990 | } |
10991 | |
10992 | e1 = TYPE_MAIN_VARIANT (e1); |
10993 | e2 = TYPE_MAIN_VARIANT (e2); |
10994 | |
10995 | expr.value |
10996 | = comptypes (e1, e2) ? integer_one_node : integer_zero_node; |
10997 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
10998 | } |
10999 | break; |
11000 | case RID_BUILTIN_TGMATH: |
11001 | { |
11002 | vec<c_expr_t, va_gc> *cexpr_list; |
11003 | location_t close_paren_loc; |
11004 | |
11005 | c_parser_consume_token (parser); |
11006 | if (!c_parser_get_builtin_args (parser, |
11007 | bname: "__builtin_tgmath" , |
11008 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11009 | out_close_paren_loc: &close_paren_loc)) |
11010 | { |
11011 | expr.set_error (); |
11012 | break; |
11013 | } |
11014 | |
11015 | if (vec_safe_length (v: cexpr_list) < 3) |
11016 | { |
11017 | error_at (loc, "too few arguments to %<__builtin_tgmath%>" ); |
11018 | expr.set_error (); |
11019 | break; |
11020 | } |
11021 | |
11022 | unsigned int i; |
11023 | c_expr_t *p; |
11024 | FOR_EACH_VEC_ELT (*cexpr_list, i, p) |
11025 | *p = convert_lvalue_to_rvalue (loc, *p, true, true); |
11026 | unsigned int nargs = check_tgmath_function (expr: &(*cexpr_list)[0], pos: 1); |
11027 | if (nargs == 0) |
11028 | { |
11029 | expr.set_error (); |
11030 | break; |
11031 | } |
11032 | if (vec_safe_length (v: cexpr_list) < nargs) |
11033 | { |
11034 | error_at (loc, "too few arguments to %<__builtin_tgmath%>" ); |
11035 | expr.set_error (); |
11036 | break; |
11037 | } |
11038 | unsigned int num_functions = vec_safe_length (v: cexpr_list) - nargs; |
11039 | if (num_functions < 2) |
11040 | { |
11041 | error_at (loc, "too few arguments to %<__builtin_tgmath%>" ); |
11042 | expr.set_error (); |
11043 | break; |
11044 | } |
11045 | |
11046 | /* The first NUM_FUNCTIONS expressions are the function |
11047 | pointers. The remaining NARGS expressions are the |
11048 | arguments that are to be passed to one of those |
11049 | functions, chosen following <tgmath.h> rules. */ |
11050 | for (unsigned int j = 1; j < num_functions; j++) |
11051 | { |
11052 | unsigned int this_nargs |
11053 | = check_tgmath_function (expr: &(*cexpr_list)[j], pos: j + 1); |
11054 | if (this_nargs == 0) |
11055 | { |
11056 | expr.set_error (); |
11057 | goto out; |
11058 | } |
11059 | if (this_nargs != nargs) |
11060 | { |
11061 | error_at ((*cexpr_list)[j].get_location (), |
11062 | "argument %u of %<__builtin_tgmath%> has " |
11063 | "wrong number of arguments" , j + 1); |
11064 | expr.set_error (); |
11065 | goto out; |
11066 | } |
11067 | } |
11068 | |
11069 | /* The functions all have the same number of arguments. |
11070 | Determine whether arguments and return types vary in |
11071 | ways permitted for <tgmath.h> functions. */ |
11072 | /* The first entry in each of these vectors is for the |
11073 | return type, subsequent entries for parameter |
11074 | types. */ |
11075 | auto_vec<enum tgmath_parm_kind> parm_kind (nargs + 1); |
11076 | auto_vec<tree> parm_first (nargs + 1); |
11077 | auto_vec<bool> parm_complex (nargs + 1); |
11078 | auto_vec<bool> parm_varies (nargs + 1); |
11079 | tree first_type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[0].value)); |
11080 | tree first_ret = TYPE_MAIN_VARIANT (TREE_TYPE (first_type)); |
11081 | parm_first.quick_push (obj: first_ret); |
11082 | parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE); |
11083 | parm_varies.quick_push (obj: false); |
11084 | function_args_iterator iter; |
11085 | tree t; |
11086 | unsigned int argpos; |
11087 | FOREACH_FUNCTION_ARGS (first_type, t, iter) |
11088 | { |
11089 | if (t == void_type_node) |
11090 | break; |
11091 | parm_first.quick_push (TYPE_MAIN_VARIANT (t)); |
11092 | parm_complex.quick_push (TREE_CODE (t) == COMPLEX_TYPE); |
11093 | parm_varies.quick_push (obj: false); |
11094 | } |
11095 | for (unsigned int j = 1; j < num_functions; j++) |
11096 | { |
11097 | tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); |
11098 | tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); |
11099 | if (ret != parm_first[0]) |
11100 | { |
11101 | parm_varies[0] = true; |
11102 | if (!SCALAR_FLOAT_TYPE_P (parm_first[0]) |
11103 | && !COMPLEX_FLOAT_TYPE_P (parm_first[0])) |
11104 | { |
11105 | error_at ((*cexpr_list)[0].get_location (), |
11106 | "invalid type-generic return type for " |
11107 | "argument %u of %<__builtin_tgmath%>" , |
11108 | 1); |
11109 | expr.set_error (); |
11110 | goto out; |
11111 | } |
11112 | if (!SCALAR_FLOAT_TYPE_P (ret) |
11113 | && !COMPLEX_FLOAT_TYPE_P (ret)) |
11114 | { |
11115 | error_at ((*cexpr_list)[j].get_location (), |
11116 | "invalid type-generic return type for " |
11117 | "argument %u of %<__builtin_tgmath%>" , |
11118 | j + 1); |
11119 | expr.set_error (); |
11120 | goto out; |
11121 | } |
11122 | } |
11123 | if (TREE_CODE (ret) == COMPLEX_TYPE) |
11124 | parm_complex[0] = true; |
11125 | argpos = 1; |
11126 | FOREACH_FUNCTION_ARGS (type, t, iter) |
11127 | { |
11128 | if (t == void_type_node) |
11129 | break; |
11130 | t = TYPE_MAIN_VARIANT (t); |
11131 | if (t != parm_first[argpos]) |
11132 | { |
11133 | parm_varies[argpos] = true; |
11134 | if (!SCALAR_FLOAT_TYPE_P (parm_first[argpos]) |
11135 | && !COMPLEX_FLOAT_TYPE_P (parm_first[argpos])) |
11136 | { |
11137 | error_at ((*cexpr_list)[0].get_location (), |
11138 | "invalid type-generic type for " |
11139 | "argument %u of argument %u of " |
11140 | "%<__builtin_tgmath%>" , argpos, 1); |
11141 | expr.set_error (); |
11142 | goto out; |
11143 | } |
11144 | if (!SCALAR_FLOAT_TYPE_P (t) |
11145 | && !COMPLEX_FLOAT_TYPE_P (t)) |
11146 | { |
11147 | error_at ((*cexpr_list)[j].get_location (), |
11148 | "invalid type-generic type for " |
11149 | "argument %u of argument %u of " |
11150 | "%<__builtin_tgmath%>" , argpos, j + 1); |
11151 | expr.set_error (); |
11152 | goto out; |
11153 | } |
11154 | } |
11155 | if (TREE_CODE (t) == COMPLEX_TYPE) |
11156 | parm_complex[argpos] = true; |
11157 | argpos++; |
11158 | } |
11159 | } |
11160 | enum tgmath_parm_kind max_variation = tgmath_fixed; |
11161 | for (unsigned int j = 0; j <= nargs; j++) |
11162 | { |
11163 | enum tgmath_parm_kind this_kind; |
11164 | if (parm_varies[j]) |
11165 | { |
11166 | if (parm_complex[j]) |
11167 | max_variation = this_kind = tgmath_complex; |
11168 | else |
11169 | { |
11170 | this_kind = tgmath_real; |
11171 | if (max_variation != tgmath_complex) |
11172 | max_variation = tgmath_real; |
11173 | } |
11174 | } |
11175 | else |
11176 | this_kind = tgmath_fixed; |
11177 | parm_kind.quick_push (obj: this_kind); |
11178 | } |
11179 | if (max_variation == tgmath_fixed) |
11180 | { |
11181 | error_at (loc, "function arguments of %<__builtin_tgmath%> " |
11182 | "all have the same type" ); |
11183 | expr.set_error (); |
11184 | break; |
11185 | } |
11186 | |
11187 | /* Identify a parameter (not the return type) that varies, |
11188 | including with complex types if any variation includes |
11189 | complex types; there must be at least one such |
11190 | parameter. */ |
11191 | unsigned int tgarg = 0; |
11192 | for (unsigned int j = 1; j <= nargs; j++) |
11193 | if (parm_kind[j] == max_variation) |
11194 | { |
11195 | tgarg = j; |
11196 | break; |
11197 | } |
11198 | if (tgarg == 0) |
11199 | { |
11200 | error_at (loc, "function arguments of %<__builtin_tgmath%> " |
11201 | "lack type-generic parameter" ); |
11202 | expr.set_error (); |
11203 | break; |
11204 | } |
11205 | |
11206 | /* Determine the type of the relevant parameter for each |
11207 | function. */ |
11208 | auto_vec<tree> tg_type (num_functions); |
11209 | for (unsigned int j = 0; j < num_functions; j++) |
11210 | { |
11211 | tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); |
11212 | argpos = 1; |
11213 | FOREACH_FUNCTION_ARGS (type, t, iter) |
11214 | { |
11215 | if (argpos == tgarg) |
11216 | { |
11217 | tg_type.quick_push (TYPE_MAIN_VARIANT (t)); |
11218 | break; |
11219 | } |
11220 | argpos++; |
11221 | } |
11222 | } |
11223 | |
11224 | /* Verify that the corresponding types are different for |
11225 | all the listed functions. Also determine whether all |
11226 | the types are complex, whether all the types are |
11227 | standard or binary, and whether all the types are |
11228 | decimal. */ |
11229 | bool all_complex = true; |
11230 | bool all_binary = true; |
11231 | bool all_decimal = true; |
11232 | hash_set<tree> tg_types; |
11233 | FOR_EACH_VEC_ELT (tg_type, i, t) |
11234 | { |
11235 | if (TREE_CODE (t) == COMPLEX_TYPE) |
11236 | all_decimal = false; |
11237 | else |
11238 | { |
11239 | all_complex = false; |
11240 | if (DECIMAL_FLOAT_TYPE_P (t)) |
11241 | all_binary = false; |
11242 | else |
11243 | all_decimal = false; |
11244 | } |
11245 | if (tg_types.add (k: t)) |
11246 | { |
11247 | error_at ((*cexpr_list)[i].get_location (), |
11248 | "duplicate type-generic parameter type for " |
11249 | "function argument %u of %<__builtin_tgmath%>" , |
11250 | i + 1); |
11251 | expr.set_error (); |
11252 | goto out; |
11253 | } |
11254 | } |
11255 | |
11256 | /* Verify that other parameters and the return type whose |
11257 | types vary have their types varying in the correct |
11258 | way. */ |
11259 | for (unsigned int j = 0; j < num_functions; j++) |
11260 | { |
11261 | tree exp_type = tg_type[j]; |
11262 | tree exp_real_type = exp_type; |
11263 | if (TREE_CODE (exp_type) == COMPLEX_TYPE) |
11264 | exp_real_type = TREE_TYPE (exp_type); |
11265 | tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value)); |
11266 | tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type)); |
11267 | if ((parm_kind[0] == tgmath_complex && ret != exp_type) |
11268 | || (parm_kind[0] == tgmath_real && ret != exp_real_type)) |
11269 | { |
11270 | error_at ((*cexpr_list)[j].get_location (), |
11271 | "bad return type for function argument %u " |
11272 | "of %<__builtin_tgmath%>" , j + 1); |
11273 | expr.set_error (); |
11274 | goto out; |
11275 | } |
11276 | argpos = 1; |
11277 | FOREACH_FUNCTION_ARGS (type, t, iter) |
11278 | { |
11279 | if (t == void_type_node) |
11280 | break; |
11281 | t = TYPE_MAIN_VARIANT (t); |
11282 | if ((parm_kind[argpos] == tgmath_complex |
11283 | && t != exp_type) |
11284 | || (parm_kind[argpos] == tgmath_real |
11285 | && t != exp_real_type)) |
11286 | { |
11287 | error_at ((*cexpr_list)[j].get_location (), |
11288 | "bad type for argument %u of " |
11289 | "function argument %u of " |
11290 | "%<__builtin_tgmath%>" , argpos, j + 1); |
11291 | expr.set_error (); |
11292 | goto out; |
11293 | } |
11294 | argpos++; |
11295 | } |
11296 | } |
11297 | |
11298 | /* The functions listed are a valid set of functions for a |
11299 | <tgmath.h> macro to select between. Identify the |
11300 | matching function, if any. First, the argument types |
11301 | must be combined following <tgmath.h> rules. Integer |
11302 | types are treated as _Decimal64 if any type-generic |
11303 | argument is decimal, or if the only alternatives for |
11304 | type-generic arguments are of decimal types, and are |
11305 | otherwise treated as _Float32x (or _Complex _Float32x |
11306 | for complex integer types) if any type-generic argument |
11307 | has _FloatNx type, otherwise as double (or _Complex |
11308 | double for complex integer types). After that |
11309 | adjustment, types are combined following the usual |
11310 | arithmetic conversions. If the function only accepts |
11311 | complex arguments, a complex type is produced. */ |
11312 | bool arg_complex = all_complex; |
11313 | bool arg_binary = all_binary; |
11314 | bool arg_int_decimal = all_decimal; |
11315 | bool arg_int_floatnx = false; |
11316 | for (unsigned int j = 1; j <= nargs; j++) |
11317 | { |
11318 | if (parm_kind[j] == tgmath_fixed) |
11319 | continue; |
11320 | c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; |
11321 | tree type = TREE_TYPE (ce->value); |
11322 | if (!INTEGRAL_TYPE_P (type) |
11323 | && !SCALAR_FLOAT_TYPE_P (type) |
11324 | && TREE_CODE (type) != COMPLEX_TYPE) |
11325 | { |
11326 | error_at (ce->get_location (), |
11327 | "invalid type of argument %u of type-generic " |
11328 | "function" , j); |
11329 | expr.set_error (); |
11330 | goto out; |
11331 | } |
11332 | if (DECIMAL_FLOAT_TYPE_P (type)) |
11333 | { |
11334 | arg_int_decimal = true; |
11335 | if (all_complex) |
11336 | { |
11337 | error_at (ce->get_location (), |
11338 | "decimal floating-point argument %u to " |
11339 | "complex-only type-generic function" , j); |
11340 | expr.set_error (); |
11341 | goto out; |
11342 | } |
11343 | else if (all_binary) |
11344 | { |
11345 | error_at (ce->get_location (), |
11346 | "decimal floating-point argument %u to " |
11347 | "binary-only type-generic function" , j); |
11348 | expr.set_error (); |
11349 | goto out; |
11350 | } |
11351 | else if (arg_complex) |
11352 | { |
11353 | error_at (ce->get_location (), |
11354 | "both complex and decimal floating-point " |
11355 | "arguments to type-generic function" ); |
11356 | expr.set_error (); |
11357 | goto out; |
11358 | } |
11359 | else if (arg_binary) |
11360 | { |
11361 | error_at (ce->get_location (), |
11362 | "both binary and decimal floating-point " |
11363 | "arguments to type-generic function" ); |
11364 | expr.set_error (); |
11365 | goto out; |
11366 | } |
11367 | } |
11368 | else if (TREE_CODE (type) == COMPLEX_TYPE) |
11369 | { |
11370 | arg_complex = true; |
11371 | if (COMPLEX_FLOAT_TYPE_P (type)) |
11372 | arg_binary = true; |
11373 | if (all_decimal) |
11374 | { |
11375 | error_at (ce->get_location (), |
11376 | "complex argument %u to " |
11377 | "decimal-only type-generic function" , j); |
11378 | expr.set_error (); |
11379 | goto out; |
11380 | } |
11381 | else if (arg_int_decimal) |
11382 | { |
11383 | error_at (ce->get_location (), |
11384 | "both complex and decimal floating-point " |
11385 | "arguments to type-generic function" ); |
11386 | expr.set_error (); |
11387 | goto out; |
11388 | } |
11389 | } |
11390 | else if (SCALAR_FLOAT_TYPE_P (type)) |
11391 | { |
11392 | arg_binary = true; |
11393 | if (all_decimal) |
11394 | { |
11395 | error_at (ce->get_location (), |
11396 | "binary argument %u to " |
11397 | "decimal-only type-generic function" , j); |
11398 | expr.set_error (); |
11399 | goto out; |
11400 | } |
11401 | else if (arg_int_decimal) |
11402 | { |
11403 | error_at (ce->get_location (), |
11404 | "both binary and decimal floating-point " |
11405 | "arguments to type-generic function" ); |
11406 | expr.set_error (); |
11407 | goto out; |
11408 | } |
11409 | } |
11410 | tree rtype = TYPE_MAIN_VARIANT (type); |
11411 | if (TREE_CODE (rtype) == COMPLEX_TYPE) |
11412 | rtype = TREE_TYPE (rtype); |
11413 | if (SCALAR_FLOAT_TYPE_P (rtype)) |
11414 | for (unsigned int j = 0; j < NUM_FLOATNX_TYPES; j++) |
11415 | if (rtype == FLOATNX_TYPE_NODE (j)) |
11416 | { |
11417 | arg_int_floatnx = true; |
11418 | break; |
11419 | } |
11420 | } |
11421 | tree arg_real = NULL_TREE; |
11422 | for (unsigned int j = 1; j <= nargs; j++) |
11423 | { |
11424 | if (parm_kind[j] == tgmath_fixed) |
11425 | continue; |
11426 | c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1]; |
11427 | tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ce->value)); |
11428 | if (TREE_CODE (type) == COMPLEX_TYPE) |
11429 | type = TREE_TYPE (type); |
11430 | if (INTEGRAL_TYPE_P (type)) |
11431 | type = (arg_int_decimal |
11432 | ? dfloat64_type_node |
11433 | : arg_int_floatnx |
11434 | ? float32x_type_node |
11435 | : double_type_node); |
11436 | if (arg_real == NULL_TREE) |
11437 | arg_real = type; |
11438 | else |
11439 | arg_real = common_type (arg_real, type); |
11440 | if (arg_real == error_mark_node) |
11441 | { |
11442 | expr.set_error (); |
11443 | goto out; |
11444 | } |
11445 | } |
11446 | tree arg_type = (arg_complex |
11447 | ? build_complex_type (arg_real) |
11448 | : arg_real); |
11449 | |
11450 | /* Look for a function to call with type-generic parameter |
11451 | type ARG_TYPE. */ |
11452 | c_expr_t *fn = NULL; |
11453 | for (unsigned int j = 0; j < num_functions; j++) |
11454 | { |
11455 | if (tg_type[j] == arg_type) |
11456 | { |
11457 | fn = &(*cexpr_list)[j]; |
11458 | break; |
11459 | } |
11460 | } |
11461 | if (fn == NULL |
11462 | && parm_kind[0] == tgmath_fixed |
11463 | && SCALAR_FLOAT_TYPE_P (parm_first[0])) |
11464 | { |
11465 | /* Presume this is a macro that rounds its result to a |
11466 | narrower type, and look for the first function with |
11467 | at least the range and precision of the argument |
11468 | type. */ |
11469 | for (unsigned int j = 0; j < num_functions; j++) |
11470 | { |
11471 | if (arg_complex |
11472 | != (TREE_CODE (tg_type[j]) == COMPLEX_TYPE)) |
11473 | continue; |
11474 | tree real_tg_type = (arg_complex |
11475 | ? TREE_TYPE (tg_type[j]) |
11476 | : tg_type[j]); |
11477 | if (DECIMAL_FLOAT_TYPE_P (arg_real) |
11478 | != DECIMAL_FLOAT_TYPE_P (real_tg_type)) |
11479 | continue; |
11480 | scalar_float_mode arg_mode |
11481 | = SCALAR_FLOAT_TYPE_MODE (arg_real); |
11482 | scalar_float_mode tg_mode |
11483 | = SCALAR_FLOAT_TYPE_MODE (real_tg_type); |
11484 | const real_format *arg_fmt = REAL_MODE_FORMAT (arg_mode); |
11485 | const real_format *tg_fmt = REAL_MODE_FORMAT (tg_mode); |
11486 | if (arg_fmt->b == tg_fmt->b |
11487 | && arg_fmt->p <= tg_fmt->p |
11488 | && arg_fmt->emax <= tg_fmt->emax |
11489 | && (arg_fmt->emin - arg_fmt->p |
11490 | >= tg_fmt->emin - tg_fmt->p)) |
11491 | { |
11492 | fn = &(*cexpr_list)[j]; |
11493 | break; |
11494 | } |
11495 | } |
11496 | } |
11497 | if (fn == NULL) |
11498 | { |
11499 | error_at (loc, "no matching function for type-generic call" ); |
11500 | expr.set_error (); |
11501 | break; |
11502 | } |
11503 | |
11504 | /* Construct a call to FN. */ |
11505 | vec<tree, va_gc> *args; |
11506 | vec_alloc (v&: args, nelems: nargs); |
11507 | vec<tree, va_gc> *origtypes; |
11508 | vec_alloc (v&: origtypes, nelems: nargs); |
11509 | auto_vec<location_t> arg_loc (nargs); |
11510 | for (unsigned int j = 0; j < nargs; j++) |
11511 | { |
11512 | c_expr_t *ce = &(*cexpr_list)[num_functions + j]; |
11513 | args->quick_push (obj: ce->value); |
11514 | arg_loc.quick_push (obj: ce->get_location ()); |
11515 | origtypes->quick_push (obj: ce->original_type); |
11516 | } |
11517 | expr.value = c_build_function_call_vec (loc, arg_loc, fn->value, |
11518 | args, origtypes); |
11519 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11520 | break; |
11521 | } |
11522 | case RID_BUILTIN_CALL_WITH_STATIC_CHAIN: |
11523 | { |
11524 | vec<c_expr_t, va_gc> *cexpr_list; |
11525 | c_expr_t *e2_p; |
11526 | tree chain_value; |
11527 | location_t close_paren_loc; |
11528 | |
11529 | c_parser_consume_token (parser); |
11530 | if (!c_parser_get_builtin_args (parser, |
11531 | bname: "__builtin_call_with_static_chain" , |
11532 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11533 | out_close_paren_loc: &close_paren_loc)) |
11534 | { |
11535 | expr.set_error (); |
11536 | break; |
11537 | } |
11538 | if (vec_safe_length (v: cexpr_list) != 2) |
11539 | { |
11540 | error_at (loc, "wrong number of arguments to " |
11541 | "%<__builtin_call_with_static_chain%>" ); |
11542 | expr.set_error (); |
11543 | break; |
11544 | } |
11545 | |
11546 | expr = (*cexpr_list)[0]; |
11547 | e2_p = &(*cexpr_list)[1]; |
11548 | *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); |
11549 | chain_value = e2_p->value; |
11550 | mark_exp_read (chain_value); |
11551 | |
11552 | if (TREE_CODE (expr.value) != CALL_EXPR) |
11553 | error_at (loc, "first argument to " |
11554 | "%<__builtin_call_with_static_chain%> " |
11555 | "must be a call expression" ); |
11556 | else if (TREE_CODE (TREE_TYPE (chain_value)) != POINTER_TYPE) |
11557 | error_at (loc, "second argument to " |
11558 | "%<__builtin_call_with_static_chain%> " |
11559 | "must be a pointer type" ); |
11560 | else |
11561 | CALL_EXPR_STATIC_CHAIN (expr.value) = chain_value; |
11562 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11563 | break; |
11564 | } |
11565 | case RID_BUILTIN_COMPLEX: |
11566 | { |
11567 | vec<c_expr_t, va_gc> *cexpr_list; |
11568 | c_expr_t *e1_p, *e2_p; |
11569 | location_t close_paren_loc; |
11570 | |
11571 | c_parser_consume_token (parser); |
11572 | if (!c_parser_get_builtin_args (parser, |
11573 | bname: "__builtin_complex" , |
11574 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11575 | out_close_paren_loc: &close_paren_loc)) |
11576 | { |
11577 | expr.set_error (); |
11578 | break; |
11579 | } |
11580 | |
11581 | if (vec_safe_length (v: cexpr_list) != 2) |
11582 | { |
11583 | error_at (loc, "wrong number of arguments to " |
11584 | "%<__builtin_complex%>" ); |
11585 | expr.set_error (); |
11586 | break; |
11587 | } |
11588 | |
11589 | e1_p = &(*cexpr_list)[0]; |
11590 | e2_p = &(*cexpr_list)[1]; |
11591 | |
11592 | *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true); |
11593 | if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR) |
11594 | e1_p->value = convert (TREE_TYPE (e1_p->value), |
11595 | TREE_OPERAND (e1_p->value, 0)); |
11596 | *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); |
11597 | if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR) |
11598 | e2_p->value = convert (TREE_TYPE (e2_p->value), |
11599 | TREE_OPERAND (e2_p->value, 0)); |
11600 | if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) |
11601 | || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value)) |
11602 | || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)) |
11603 | || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))) |
11604 | { |
11605 | error_at (loc, "%<__builtin_complex%> operand " |
11606 | "not of real binary floating-point type" ); |
11607 | expr.set_error (); |
11608 | break; |
11609 | } |
11610 | if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value)) |
11611 | != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value))) |
11612 | { |
11613 | error_at (loc, |
11614 | "%<__builtin_complex%> operands of different types" ); |
11615 | expr.set_error (); |
11616 | break; |
11617 | } |
11618 | pedwarn_c90 (loc, opt: OPT_Wpedantic, |
11619 | "ISO C90 does not support complex types" ); |
11620 | expr.value = build2_loc (loc, code: COMPLEX_EXPR, |
11621 | type: build_complex_type |
11622 | (TYPE_MAIN_VARIANT |
11623 | (TREE_TYPE (e1_p->value))), |
11624 | arg0: e1_p->value, arg1: e2_p->value); |
11625 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11626 | break; |
11627 | } |
11628 | case RID_BUILTIN_SHUFFLE: |
11629 | { |
11630 | vec<c_expr_t, va_gc> *cexpr_list; |
11631 | unsigned int i; |
11632 | c_expr_t *p; |
11633 | location_t close_paren_loc; |
11634 | |
11635 | c_parser_consume_token (parser); |
11636 | if (!c_parser_get_builtin_args (parser, |
11637 | bname: "__builtin_shuffle" , |
11638 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11639 | out_close_paren_loc: &close_paren_loc)) |
11640 | { |
11641 | expr.set_error (); |
11642 | break; |
11643 | } |
11644 | |
11645 | FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) |
11646 | *p = convert_lvalue_to_rvalue (loc, *p, true, true); |
11647 | |
11648 | if (vec_safe_length (v: cexpr_list) == 2) |
11649 | expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, |
11650 | NULL_TREE, |
11651 | (*cexpr_list)[1].value); |
11652 | |
11653 | else if (vec_safe_length (v: cexpr_list) == 3) |
11654 | expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, |
11655 | (*cexpr_list)[1].value, |
11656 | (*cexpr_list)[2].value); |
11657 | else |
11658 | { |
11659 | error_at (loc, "wrong number of arguments to " |
11660 | "%<__builtin_shuffle%>" ); |
11661 | expr.set_error (); |
11662 | } |
11663 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11664 | break; |
11665 | } |
11666 | case RID_BUILTIN_SHUFFLEVECTOR: |
11667 | { |
11668 | vec<c_expr_t, va_gc> *cexpr_list; |
11669 | unsigned int i; |
11670 | c_expr_t *p; |
11671 | location_t close_paren_loc; |
11672 | |
11673 | c_parser_consume_token (parser); |
11674 | if (!c_parser_get_builtin_args (parser, |
11675 | bname: "__builtin_shufflevector" , |
11676 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11677 | out_close_paren_loc: &close_paren_loc)) |
11678 | { |
11679 | expr.set_error (); |
11680 | break; |
11681 | } |
11682 | |
11683 | FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) |
11684 | *p = convert_lvalue_to_rvalue (loc, *p, true, true); |
11685 | |
11686 | if (vec_safe_length (v: cexpr_list) < 3) |
11687 | { |
11688 | error_at (loc, "wrong number of arguments to " |
11689 | "%<__builtin_shuffle%>" ); |
11690 | expr.set_error (); |
11691 | } |
11692 | else |
11693 | { |
11694 | auto_vec<tree, 16> mask; |
11695 | for (i = 2; i < cexpr_list->length (); ++i) |
11696 | mask.safe_push (obj: (*cexpr_list)[i].value); |
11697 | expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value, |
11698 | (*cexpr_list)[1].value, |
11699 | mask); |
11700 | } |
11701 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
11702 | break; |
11703 | } |
11704 | case RID_BUILTIN_CONVERTVECTOR: |
11705 | { |
11706 | location_t start_loc = loc; |
11707 | c_parser_consume_token (parser); |
11708 | matching_parens parens; |
11709 | if (!parens.require_open (parser)) |
11710 | { |
11711 | expr.set_error (); |
11712 | break; |
11713 | } |
11714 | e1 = c_parser_expr_no_commas (parser, NULL); |
11715 | mark_exp_read (e1.value); |
11716 | if (!c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
11717 | { |
11718 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
11719 | expr.set_error (); |
11720 | break; |
11721 | } |
11722 | loc = c_parser_peek_token (parser)->location; |
11723 | t1 = c_parser_type_name (parser); |
11724 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
11725 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
11726 | msgid: "expected %<)%>" ); |
11727 | if (t1 == NULL) |
11728 | expr.set_error (); |
11729 | else |
11730 | { |
11731 | tree type_expr = NULL_TREE; |
11732 | expr.value = c_build_vec_convert (start_loc, e1.value, loc, |
11733 | groktypename (t1, &type_expr, |
11734 | NULL)); |
11735 | set_c_expr_source_range (expr: &expr, start: start_loc, finish: end_loc); |
11736 | } |
11737 | } |
11738 | break; |
11739 | case RID_BUILTIN_ASSOC_BARRIER: |
11740 | { |
11741 | location_t start_loc = loc; |
11742 | c_parser_consume_token (parser); |
11743 | matching_parens parens; |
11744 | if (!parens.require_open (parser)) |
11745 | { |
11746 | expr.set_error (); |
11747 | break; |
11748 | } |
11749 | e1 = c_parser_expr_no_commas (parser, NULL); |
11750 | mark_exp_read (e1.value); |
11751 | location_t end_loc = c_parser_peek_token (parser)->get_finish (); |
11752 | parens.skip_until_found_close (parser); |
11753 | expr = parser_build_unary_op (loc, PAREN_EXPR, e1); |
11754 | set_c_expr_source_range (expr: &expr, start: start_loc, finish: end_loc); |
11755 | } |
11756 | break; |
11757 | case RID_BUILTIN_STDC: |
11758 | { |
11759 | vec<c_expr_t, va_gc> *cexpr_list; |
11760 | c_expr_t *arg_p; |
11761 | location_t close_paren_loc; |
11762 | enum c_builtin_stdc { |
11763 | C_BUILTIN_STDC_BIT_CEIL, |
11764 | C_BUILTIN_STDC_BIT_FLOOR, |
11765 | C_BUILTIN_STDC_BIT_WIDTH, |
11766 | C_BUILTIN_STDC_COUNT_ONES, |
11767 | C_BUILTIN_STDC_COUNT_ZEROS, |
11768 | C_BUILTIN_STDC_FIRST_LEADING_ONE, |
11769 | C_BUILTIN_STDC_FIRST_LEADING_ZERO, |
11770 | C_BUILTIN_STDC_FIRST_TRAILING_ONE, |
11771 | C_BUILTIN_STDC_FIRST_TRAILING_ZERO, |
11772 | C_BUILTIN_STDC_HAS_SINGLE_BIT, |
11773 | C_BUILTIN_STDC_LEADING_ONES, |
11774 | C_BUILTIN_STDC_LEADING_ZEROS, |
11775 | C_BUILTIN_STDC_TRAILING_ONES, |
11776 | C_BUILTIN_STDC_TRAILING_ZEROS, |
11777 | C_BUILTIN_STDC_MAX |
11778 | } stdc_rid = C_BUILTIN_STDC_MAX; |
11779 | const char *name |
11780 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
11781 | switch (name[sizeof ("__builtin_stdc_" ) - 1]) |
11782 | { |
11783 | case 'b': |
11784 | switch (name[sizeof ("__builtin_stdc_bit_" ) - 1]) |
11785 | { |
11786 | case 'c': |
11787 | stdc_rid = C_BUILTIN_STDC_BIT_CEIL; |
11788 | break; |
11789 | case 'f': |
11790 | stdc_rid = C_BUILTIN_STDC_BIT_FLOOR; |
11791 | break; |
11792 | default: |
11793 | stdc_rid = C_BUILTIN_STDC_BIT_WIDTH; |
11794 | break; |
11795 | } |
11796 | break; |
11797 | case 'c': |
11798 | if (name[sizeof ("__builtin_stdc_count_" ) - 1] == 'o') |
11799 | stdc_rid = C_BUILTIN_STDC_COUNT_ONES; |
11800 | else |
11801 | stdc_rid = C_BUILTIN_STDC_COUNT_ZEROS; |
11802 | break; |
11803 | case 'f': |
11804 | switch (name[sizeof ("__builtin_stdc_first_trailing_" ) - 1]) |
11805 | { |
11806 | case 'n': |
11807 | stdc_rid = C_BUILTIN_STDC_FIRST_LEADING_ONE; |
11808 | break; |
11809 | case 'e': |
11810 | stdc_rid = C_BUILTIN_STDC_FIRST_LEADING_ZERO; |
11811 | break; |
11812 | case 'o': |
11813 | stdc_rid = C_BUILTIN_STDC_FIRST_TRAILING_ONE; |
11814 | break; |
11815 | default: |
11816 | stdc_rid = C_BUILTIN_STDC_FIRST_TRAILING_ZERO; |
11817 | break; |
11818 | } |
11819 | break; |
11820 | case 'h': |
11821 | stdc_rid = C_BUILTIN_STDC_HAS_SINGLE_BIT; |
11822 | break; |
11823 | case 'l': |
11824 | if (name[sizeof ("__builtin_stdc_leading_" ) - 1] == 'o') |
11825 | stdc_rid = C_BUILTIN_STDC_LEADING_ONES; |
11826 | else |
11827 | stdc_rid = C_BUILTIN_STDC_LEADING_ZEROS; |
11828 | break; |
11829 | case 't': |
11830 | if (name[sizeof ("__builtin_stdc_trailing_" ) - 1] == 'o') |
11831 | stdc_rid = C_BUILTIN_STDC_TRAILING_ONES; |
11832 | else |
11833 | stdc_rid = C_BUILTIN_STDC_TRAILING_ZEROS; |
11834 | break; |
11835 | } |
11836 | gcc_checking_assert (stdc_rid != C_BUILTIN_STDC_MAX); |
11837 | |
11838 | c_parser_consume_token (parser); |
11839 | if (!c_parser_get_builtin_args (parser, bname: name, |
11840 | ret_cexpr_list: &cexpr_list, choose_expr_p: false, |
11841 | out_close_paren_loc: &close_paren_loc)) |
11842 | { |
11843 | expr.set_error (); |
11844 | break; |
11845 | } |
11846 | |
11847 | if (vec_safe_length (v: cexpr_list) != 1) |
11848 | { |
11849 | error_at (loc, "wrong number of arguments to %qs" , name); |
11850 | expr.set_error (); |
11851 | break; |
11852 | } |
11853 | |
11854 | arg_p = &(*cexpr_list)[0]; |
11855 | *arg_p = convert_lvalue_to_rvalue (loc, *arg_p, true, true); |
11856 | if (!INTEGRAL_TYPE_P (TREE_TYPE (arg_p->value))) |
11857 | { |
11858 | error_at (loc, "%qs operand not an integral type" , name); |
11859 | expr.set_error (); |
11860 | break; |
11861 | } |
11862 | if (TREE_CODE (TREE_TYPE (arg_p->value)) == ENUMERAL_TYPE) |
11863 | { |
11864 | error_at (loc, "argument %u in call to function " |
11865 | "%qs has enumerated type" , 1, name); |
11866 | expr.set_error (); |
11867 | break; |
11868 | } |
11869 | if (TREE_CODE (TREE_TYPE (arg_p->value)) == BOOLEAN_TYPE) |
11870 | { |
11871 | error_at (loc, "argument %u in call to function " |
11872 | "%qs has boolean type" , 1, name); |
11873 | expr.set_error (); |
11874 | break; |
11875 | } |
11876 | if (!TYPE_UNSIGNED (TREE_TYPE (arg_p->value))) |
11877 | { |
11878 | error_at (loc, "argument 1 in call to function " |
11879 | "%qs has signed type" , name); |
11880 | expr.set_error (); |
11881 | break; |
11882 | } |
11883 | tree arg = arg_p->value; |
11884 | tree type = TYPE_MAIN_VARIANT (TREE_TYPE (arg)); |
11885 | /* Expand: |
11886 | __builtin_stdc_leading_zeros (arg) as |
11887 | (unsigned int) __builtin_clzg (arg, prec) |
11888 | __builtin_stdc_leading_ones (arg) as |
11889 | (unsigned int) __builtin_clzg ((type) ~arg, prec) |
11890 | __builtin_stdc_trailing_zeros (arg) as |
11891 | (unsigned int) __builtin_ctzg (arg, prec) |
11892 | __builtin_stdc_trailing_ones (arg) as |
11893 | (unsigned int) __builtin_ctzg ((type) ~arg, prec) |
11894 | __builtin_stdc_first_leading_zero (arg) as |
11895 | __builtin_clzg ((type) ~arg, -1) + 1U |
11896 | __builtin_stdc_first_leading_one (arg) as |
11897 | __builtin_clzg (arg, -1) + 1U |
11898 | __builtin_stdc_first_trailing_zero (arg) as |
11899 | __builtin_ctzg ((type) ~arg, -1) + 1U |
11900 | __builtin_stdc_first_trailing_one (arg) as |
11901 | __builtin_ctzg (arg, -1) + 1U |
11902 | __builtin_stdc_count_zeros (arg) as |
11903 | (unsigned int) __builtin_popcountg ((type) ~arg) |
11904 | __builtin_stdc_count_ones (arg) as |
11905 | (unsigned int) __builtin_popcountg (arg) |
11906 | __builtin_stdc_has_single_bit (arg) as |
11907 | (_Bool) (__builtin_popcountg (arg) == 1) |
11908 | __builtin_stdc_bit_width (arg) as |
11909 | (unsigned int) (prec - __builtin_clzg (arg, prec)) |
11910 | __builtin_stdc_bit_floor (arg) as |
11911 | arg == 0 ? (type) 0 |
11912 | : (type) 1 << (prec - 1 - __builtin_clzg (arg)) |
11913 | __builtin_stdc_bit_ceil (arg) as |
11914 | arg <= 1 ? (type) 1 |
11915 | : (type) 2 << (prec - 1 - __builtin_clzg (arg - 1)) |
11916 | without evaluating arg multiple times, type being |
11917 | __typeof (arg) and prec __builtin_popcountg ((type) ~0)). */ |
11918 | int prec = TYPE_PRECISION (type); |
11919 | tree barg1 = arg; |
11920 | switch (stdc_rid) |
11921 | { |
11922 | case C_BUILTIN_STDC_BIT_CEIL: |
11923 | arg = save_expr (arg); |
11924 | barg1 = build2_loc (loc, code: PLUS_EXPR, type, arg0: arg, |
11925 | arg1: build_int_cst (type, -1)); |
11926 | break; |
11927 | case C_BUILTIN_STDC_BIT_FLOOR: |
11928 | barg1 = arg = save_expr (arg); |
11929 | break; |
11930 | case C_BUILTIN_STDC_COUNT_ZEROS: |
11931 | case C_BUILTIN_STDC_FIRST_LEADING_ZERO: |
11932 | case C_BUILTIN_STDC_FIRST_TRAILING_ZERO: |
11933 | case C_BUILTIN_STDC_LEADING_ONES: |
11934 | case C_BUILTIN_STDC_TRAILING_ONES: |
11935 | barg1 = build1_loc (loc, code: BIT_NOT_EXPR, type, arg1: arg); |
11936 | break; |
11937 | default: |
11938 | break; |
11939 | } |
11940 | tree barg2 = NULL_TREE; |
11941 | switch (stdc_rid) |
11942 | { |
11943 | case C_BUILTIN_STDC_BIT_WIDTH: |
11944 | case C_BUILTIN_STDC_LEADING_ONES: |
11945 | case C_BUILTIN_STDC_LEADING_ZEROS: |
11946 | case C_BUILTIN_STDC_TRAILING_ONES: |
11947 | case C_BUILTIN_STDC_TRAILING_ZEROS: |
11948 | barg2 = build_int_cst (integer_type_node, prec); |
11949 | break; |
11950 | case C_BUILTIN_STDC_FIRST_LEADING_ONE: |
11951 | case C_BUILTIN_STDC_FIRST_LEADING_ZERO: |
11952 | case C_BUILTIN_STDC_FIRST_TRAILING_ONE: |
11953 | case C_BUILTIN_STDC_FIRST_TRAILING_ZERO: |
11954 | barg2 = integer_minus_one_node; |
11955 | break; |
11956 | default: |
11957 | break; |
11958 | } |
11959 | tree fndecl = NULL_TREE; |
11960 | switch (stdc_rid) |
11961 | { |
11962 | case C_BUILTIN_STDC_BIT_CEIL: |
11963 | case C_BUILTIN_STDC_BIT_FLOOR: |
11964 | case C_BUILTIN_STDC_BIT_WIDTH: |
11965 | case C_BUILTIN_STDC_FIRST_LEADING_ONE: |
11966 | case C_BUILTIN_STDC_FIRST_LEADING_ZERO: |
11967 | case C_BUILTIN_STDC_LEADING_ONES: |
11968 | case C_BUILTIN_STDC_LEADING_ZEROS: |
11969 | fndecl = builtin_decl_explicit (fncode: BUILT_IN_CLZG); |
11970 | break; |
11971 | case C_BUILTIN_STDC_FIRST_TRAILING_ONE: |
11972 | case C_BUILTIN_STDC_FIRST_TRAILING_ZERO: |
11973 | case C_BUILTIN_STDC_TRAILING_ONES: |
11974 | case C_BUILTIN_STDC_TRAILING_ZEROS: |
11975 | fndecl = builtin_decl_explicit (fncode: BUILT_IN_CTZG); |
11976 | break; |
11977 | case C_BUILTIN_STDC_COUNT_ONES: |
11978 | case C_BUILTIN_STDC_COUNT_ZEROS: |
11979 | case C_BUILTIN_STDC_HAS_SINGLE_BIT: |
11980 | fndecl = builtin_decl_explicit (fncode: BUILT_IN_POPCOUNTG); |
11981 | break; |
11982 | default: |
11983 | gcc_unreachable (); |
11984 | } |
11985 | /* Construct a call to __builtin_{clz,ctz,popcount}g. */ |
11986 | int nargs = barg2 != NULL_TREE ? 2 : 1; |
11987 | vec<tree, va_gc> *args; |
11988 | vec_alloc (v&: args, nelems: nargs); |
11989 | vec<tree, va_gc> *origtypes; |
11990 | vec_alloc (v&: origtypes, nelems: nargs); |
11991 | auto_vec<location_t> arg_loc (nargs); |
11992 | args->quick_push (obj: barg1); |
11993 | arg_loc.quick_push (obj: arg_p->get_location ()); |
11994 | origtypes->quick_push (obj: arg_p->original_type); |
11995 | if (nargs == 2) |
11996 | { |
11997 | args->quick_push (obj: barg2); |
11998 | arg_loc.quick_push (obj: loc); |
11999 | origtypes->quick_push (integer_type_node); |
12000 | } |
12001 | expr.value = c_build_function_call_vec (loc, arg_loc, fndecl, |
12002 | args, origtypes); |
12003 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_paren_loc); |
12004 | if (expr.value == error_mark_node) |
12005 | break; |
12006 | switch (stdc_rid) |
12007 | { |
12008 | case C_BUILTIN_STDC_BIT_CEIL: |
12009 | case C_BUILTIN_STDC_BIT_FLOOR: |
12010 | --prec; |
12011 | /* FALLTHRU */ |
12012 | case C_BUILTIN_STDC_BIT_WIDTH: |
12013 | expr.value = build2_loc (loc, code: MINUS_EXPR, integer_type_node, |
12014 | arg0: build_int_cst (integer_type_node, |
12015 | prec), arg1: expr.value); |
12016 | break; |
12017 | case C_BUILTIN_STDC_FIRST_LEADING_ONE: |
12018 | case C_BUILTIN_STDC_FIRST_LEADING_ZERO: |
12019 | case C_BUILTIN_STDC_FIRST_TRAILING_ONE: |
12020 | case C_BUILTIN_STDC_FIRST_TRAILING_ZERO: |
12021 | expr.value = build2_loc (loc, code: PLUS_EXPR, integer_type_node, |
12022 | arg0: expr.value, integer_one_node); |
12023 | break; |
12024 | case C_BUILTIN_STDC_HAS_SINGLE_BIT: |
12025 | expr.value = build2_loc (loc, code: EQ_EXPR, boolean_type_node, |
12026 | arg0: expr.value, integer_one_node); |
12027 | break; |
12028 | default: |
12029 | break; |
12030 | } |
12031 | |
12032 | if (stdc_rid != C_BUILTIN_STDC_BIT_CEIL |
12033 | && stdc_rid != C_BUILTIN_STDC_BIT_FLOOR) |
12034 | { |
12035 | if (stdc_rid != C_BUILTIN_STDC_HAS_SINGLE_BIT) |
12036 | expr.value = fold_convert_loc (loc, unsigned_type_node, |
12037 | expr.value); |
12038 | break; |
12039 | } |
12040 | /* For __builtin_stdc_bit_ceil (0U) or __builtin_stdc_bit_ceil (1U) |
12041 | or __builtin_stdc_bit_floor (0U) avoid bogus -Wshift-count-* |
12042 | warnings. The LSHIFT_EXPR is in dead code in that case. */ |
12043 | if (integer_zerop (arg) |
12044 | || (stdc_rid == C_BUILTIN_STDC_BIT_CEIL && integer_onep (arg))) |
12045 | expr.value = build_int_cst (type, 0); |
12046 | else |
12047 | expr.value |
12048 | = build2_loc (loc, code: LSHIFT_EXPR, type, |
12049 | arg0: build_int_cst (type, |
12050 | (stdc_rid |
12051 | == C_BUILTIN_STDC_BIT_CEIL |
12052 | ? 2 : 1)), arg1: expr.value); |
12053 | if (stdc_rid == C_BUILTIN_STDC_BIT_CEIL) |
12054 | expr.value = build3_loc (loc, code: COND_EXPR, type, |
12055 | arg0: build2_loc (loc, code: LE_EXPR, |
12056 | boolean_type_node, arg0: arg, |
12057 | arg1: build_int_cst (type, 1)), |
12058 | arg1: build_int_cst (type, 1), |
12059 | arg2: expr.value); |
12060 | else |
12061 | expr.value = build3_loc (loc, code: COND_EXPR, type, |
12062 | arg0: build2_loc (loc, code: EQ_EXPR, |
12063 | boolean_type_node, arg0: arg, |
12064 | arg1: build_int_cst (type, 0)), |
12065 | arg1: build_int_cst (type, 0), |
12066 | arg2: expr.value); |
12067 | break; |
12068 | } |
12069 | case RID_AT_SELECTOR: |
12070 | { |
12071 | gcc_assert (c_dialect_objc ()); |
12072 | c_parser_consume_token (parser); |
12073 | matching_parens parens; |
12074 | if (!parens.require_open (parser)) |
12075 | { |
12076 | expr.set_error (); |
12077 | break; |
12078 | } |
12079 | tree sel = c_parser_objc_selector_arg (parser); |
12080 | location_t close_loc = c_parser_peek_token (parser)->location; |
12081 | parens.skip_until_found_close (parser); |
12082 | expr.value = objc_build_selector_expr (loc, sel); |
12083 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
12084 | } |
12085 | break; |
12086 | case RID_AT_PROTOCOL: |
12087 | { |
12088 | gcc_assert (c_dialect_objc ()); |
12089 | c_parser_consume_token (parser); |
12090 | matching_parens parens; |
12091 | if (!parens.require_open (parser)) |
12092 | { |
12093 | expr.set_error (); |
12094 | break; |
12095 | } |
12096 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12097 | { |
12098 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12099 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
12100 | expr.set_error (); |
12101 | break; |
12102 | } |
12103 | tree id = c_parser_peek_token (parser)->value; |
12104 | c_parser_consume_token (parser); |
12105 | location_t close_loc = c_parser_peek_token (parser)->location; |
12106 | parens.skip_until_found_close (parser); |
12107 | expr.value = objc_build_protocol_expr (id); |
12108 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
12109 | } |
12110 | break; |
12111 | case RID_AT_ENCODE: |
12112 | { |
12113 | /* Extension to support C-structures in the archiver. */ |
12114 | gcc_assert (c_dialect_objc ()); |
12115 | c_parser_consume_token (parser); |
12116 | matching_parens parens; |
12117 | if (!parens.require_open (parser)) |
12118 | { |
12119 | expr.set_error (); |
12120 | break; |
12121 | } |
12122 | t1 = c_parser_type_name (parser); |
12123 | if (t1 == NULL) |
12124 | { |
12125 | expr.set_error (); |
12126 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
12127 | break; |
12128 | } |
12129 | location_t close_loc = c_parser_peek_token (parser)->location; |
12130 | parens.skip_until_found_close (parser); |
12131 | tree type = groktypename (t1, NULL, NULL); |
12132 | expr.value = objc_build_encode_expr (type); |
12133 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
12134 | } |
12135 | break; |
12136 | case RID_GENERIC: |
12137 | expr = c_parser_generic_selection (parser); |
12138 | break; |
12139 | case RID_OMP_ALL_MEMORY: |
12140 | gcc_assert (flag_openmp); |
12141 | c_parser_consume_token (parser); |
12142 | error_at (loc, "%<omp_all_memory%> may only be used in OpenMP " |
12143 | "%<depend%> clause" ); |
12144 | expr.set_error (); |
12145 | break; |
12146 | /* C23 'nullptr' literal. */ |
12147 | case RID_NULLPTR: |
12148 | c_parser_consume_token (parser); |
12149 | expr.value = nullptr_node; |
12150 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
12151 | pedwarn_c11 (loc, opt: OPT_Wpedantic, |
12152 | "ISO C does not support %qs before C23" , "nullptr" ); |
12153 | break; |
12154 | case RID_TRUE: |
12155 | c_parser_consume_token (parser); |
12156 | expr.value = boolean_true_node; |
12157 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
12158 | break; |
12159 | case RID_FALSE: |
12160 | c_parser_consume_token (parser); |
12161 | expr.value = boolean_false_node; |
12162 | set_c_expr_source_range (expr: &expr, src_range: tok_range); |
12163 | break; |
12164 | default: |
12165 | c_parser_error (parser, gmsgid: "expected expression" ); |
12166 | expr.set_error (); |
12167 | break; |
12168 | } |
12169 | break; |
12170 | case CPP_OPEN_SQUARE: |
12171 | if (c_dialect_objc ()) |
12172 | { |
12173 | tree receiver, args; |
12174 | c_parser_consume_token (parser); |
12175 | receiver = c_parser_objc_receiver (parser); |
12176 | args = c_parser_objc_message_args (parser); |
12177 | location_t close_loc = c_parser_peek_token (parser)->location; |
12178 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
12179 | msgid: "expected %<]%>" ); |
12180 | expr.value = objc_build_message_expr (receiver, args); |
12181 | set_c_expr_source_range (expr: &expr, start: loc, finish: close_loc); |
12182 | break; |
12183 | } |
12184 | /* Else fall through to report error. */ |
12185 | /* FALLTHRU */ |
12186 | default: |
12187 | c_parser_error (parser, gmsgid: "expected expression" ); |
12188 | expr.set_error (); |
12189 | break; |
12190 | } |
12191 | out: |
12192 | return c_parser_postfix_expression_after_primary |
12193 | (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr); |
12194 | } |
12195 | |
12196 | /* Parse a postfix expression after a parenthesized type name: the |
12197 | brace-enclosed initializer of a compound literal, possibly followed |
12198 | by some postfix operators. This is separate because it is not |
12199 | possible to tell until after the type name whether a cast |
12200 | expression has a cast or a compound literal, or whether the operand |
12201 | of sizeof is a parenthesized type name or starts with a compound |
12202 | literal. TYPE_LOC is the location where TYPE_NAME starts--the |
12203 | location of the first token after the parentheses around the type |
12204 | name. */ |
12205 | |
12206 | static struct c_expr |
12207 | c_parser_postfix_expression_after_paren_type (c_parser *parser, |
12208 | struct c_declspecs *scspecs, |
12209 | struct c_type_name *type_name, |
12210 | location_t type_loc) |
12211 | { |
12212 | tree type; |
12213 | struct c_expr init; |
12214 | bool non_const; |
12215 | struct c_expr expr; |
12216 | location_t start_loc; |
12217 | tree type_expr = NULL_TREE; |
12218 | bool type_expr_const = true; |
12219 | bool constexpr_p = scspecs ? scspecs->constexpr_p : false; |
12220 | unsigned int underspec_state = 0; |
12221 | check_compound_literal_type (type_loc, type_name); |
12222 | rich_location richloc (line_table, type_loc); |
12223 | start_loc = c_parser_peek_token (parser)->location; |
12224 | if (constexpr_p) |
12225 | { |
12226 | underspec_state = start_underspecified_init (start_loc, NULL_TREE); |
12227 | /* A constexpr compound literal is subject to the constraints on |
12228 | underspecified declarations, which may not declare tags or |
12229 | members or structures or unions; it is undefined behavior to |
12230 | declare the members of an enumeration. Where the structure, |
12231 | union or enumeration type is declared within the compound |
12232 | literal initializer, this is diagnosed elsewhere as a result |
12233 | of the above call to start_underspecified_init. Diagnose |
12234 | here the case of declaring such a type in the type specifiers |
12235 | of the compound literal. */ |
12236 | switch (type_name->specs->typespec_kind) |
12237 | { |
12238 | case ctsk_tagfirstref: |
12239 | case ctsk_tagfirstref_attrs: |
12240 | error_at (type_loc, "%qT declared in %<constexpr%> compound literal" , |
12241 | type_name->specs->type); |
12242 | break; |
12243 | |
12244 | case ctsk_tagdef: |
12245 | error_at (type_loc, "%qT defined in %<constexpr%> compound literal" , |
12246 | type_name->specs->type); |
12247 | break; |
12248 | |
12249 | default: |
12250 | break; |
12251 | } |
12252 | } |
12253 | start_init (NULL_TREE, NULL, |
12254 | (global_bindings_p () |
12255 | || (scspecs && scspecs->storage_class == csc_static) |
12256 | || constexpr_p), constexpr_p, &richloc); |
12257 | type = groktypename (type_name, &type_expr, &type_expr_const); |
12258 | if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type)) |
12259 | { |
12260 | error_at (type_loc, "compound literal has variable size" ); |
12261 | type = error_mark_node; |
12262 | } |
12263 | else if (TREE_CODE (type) == FUNCTION_TYPE) |
12264 | { |
12265 | error_at (type_loc, "compound literal has function type" ); |
12266 | type = error_mark_node; |
12267 | } |
12268 | if (constexpr_p && type != error_mark_node) |
12269 | { |
12270 | tree type_no_array = strip_array_types (type); |
12271 | /* The type of a constexpr object must not be variably modified |
12272 | (which applies to all compound literals), volatile, atomic or |
12273 | restrict qualified or have a member with such a qualifier. |
12274 | const qualification is implicitly added. */ |
12275 | if (TYPE_QUALS (type_no_array) |
12276 | & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC)) |
12277 | error_at (type_loc, "invalid qualifiers for %<constexpr%> object" ); |
12278 | else if (RECORD_OR_UNION_TYPE_P (type_no_array) |
12279 | && C_TYPE_FIELDS_NON_CONSTEXPR (type_no_array)) |
12280 | error_at (type_loc, "invalid qualifiers for field of " |
12281 | "%<constexpr%> object" ); |
12282 | type = c_build_qualified_type (type, |
12283 | (TYPE_QUALS (type_no_array) |
12284 | | TYPE_QUAL_CONST)); |
12285 | } |
12286 | init = c_parser_braced_init (parser, type, nested_p: false, NULL, NULL_TREE); |
12287 | if (constexpr_p) |
12288 | finish_underspecified_init (NULL_TREE, underspec_state); |
12289 | finish_init (); |
12290 | maybe_warn_string_init (type_loc, type, init); |
12291 | |
12292 | if (type != error_mark_node |
12293 | && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) |
12294 | && current_function_decl) |
12295 | { |
12296 | error ("compound literal qualified by address-space qualifier" ); |
12297 | type = error_mark_node; |
12298 | } |
12299 | |
12300 | if (!pedwarn_c90 (start_loc, opt: OPT_Wpedantic, |
12301 | "ISO C90 forbids compound literals" ) && scspecs) |
12302 | pedwarn_c11 (start_loc, opt: OPT_Wpedantic, |
12303 | "ISO C forbids storage class specifiers in compound literals " |
12304 | "before C23" ); |
12305 | non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) |
12306 | ? CONSTRUCTOR_NON_CONST (init.value) |
12307 | : init.original_code == C_MAYBE_CONST_EXPR); |
12308 | non_const |= !type_expr_const; |
12309 | unsigned int alignas_align = 0; |
12310 | if (type != error_mark_node |
12311 | && type_name->specs->align_log != -1) |
12312 | { |
12313 | alignas_align = 1U << type_name->specs->align_log; |
12314 | if (alignas_align < min_align_of_type (type)) |
12315 | { |
12316 | error_at (type_name->specs->locations[cdw_alignas], |
12317 | "%<_Alignas%> specifiers cannot reduce " |
12318 | "alignment of compound literal" ); |
12319 | alignas_align = 0; |
12320 | } |
12321 | } |
12322 | expr.value = build_compound_literal (start_loc, type, init.value, non_const, |
12323 | alignas_align, scspecs); |
12324 | set_c_expr_source_range (expr: &expr, src_range: init.src_range); |
12325 | expr.m_decimal = 0; |
12326 | expr.original_code = ERROR_MARK; |
12327 | expr.original_type = NULL; |
12328 | if (type != error_mark_node |
12329 | && expr.value != error_mark_node |
12330 | && type_expr) |
12331 | { |
12332 | if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) |
12333 | { |
12334 | gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE); |
12335 | C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr; |
12336 | } |
12337 | else |
12338 | { |
12339 | gcc_assert (!non_const); |
12340 | expr.value = build2 (C_MAYBE_CONST_EXPR, type, |
12341 | type_expr, expr.value); |
12342 | } |
12343 | } |
12344 | return c_parser_postfix_expression_after_primary (parser, loc: start_loc, expr); |
12345 | } |
12346 | |
12347 | /* Callback function for sizeof_pointer_memaccess_warning to compare |
12348 | types. */ |
12349 | |
12350 | static bool |
12351 | sizeof_ptr_memacc_comptypes (tree type1, tree type2) |
12352 | { |
12353 | return comptypes (type1, type2) == 1; |
12354 | } |
12355 | |
12356 | /* Warn for patterns where abs-like function appears to be used incorrectly, |
12357 | gracefully ignore any non-abs-like function. The warning location should |
12358 | be LOC. FNDECL is the declaration of called function, it must be a |
12359 | BUILT_IN_NORMAL function. ARG is the first and only argument of the |
12360 | call. */ |
12361 | |
12362 | static void |
12363 | warn_for_abs (location_t loc, tree fndecl, tree arg) |
12364 | { |
12365 | /* Avoid warning in unreachable subexpressions. */ |
12366 | if (c_inhibit_evaluation_warnings) |
12367 | return; |
12368 | |
12369 | tree atype = TREE_TYPE (arg); |
12370 | |
12371 | /* Casts from pointers (and thus arrays and fndecls) will generate |
12372 | -Wint-conversion warnings. Most other wrong types hopefully lead to type |
12373 | mismatch errors. TODO: Think about what to do with FIXED_POINT_TYPE_P |
12374 | types and possibly other exotic types. */ |
12375 | if (!INTEGRAL_TYPE_P (atype) |
12376 | && !SCALAR_FLOAT_TYPE_P (atype) |
12377 | && TREE_CODE (atype) != COMPLEX_TYPE) |
12378 | return; |
12379 | |
12380 | enum built_in_function fcode = DECL_FUNCTION_CODE (decl: fndecl); |
12381 | |
12382 | switch (fcode) |
12383 | { |
12384 | case BUILT_IN_ABS: |
12385 | case BUILT_IN_LABS: |
12386 | case BUILT_IN_LLABS: |
12387 | case BUILT_IN_IMAXABS: |
12388 | if (!INTEGRAL_TYPE_P (atype)) |
12389 | { |
12390 | if (SCALAR_FLOAT_TYPE_P (atype)) |
12391 | warning_at (loc, OPT_Wabsolute_value, |
12392 | "using integer absolute value function %qD when " |
12393 | "argument is of floating-point type %qT" , |
12394 | fndecl, atype); |
12395 | else if (TREE_CODE (atype) == COMPLEX_TYPE) |
12396 | warning_at (loc, OPT_Wabsolute_value, |
12397 | "using integer absolute value function %qD when " |
12398 | "argument is of complex type %qT" , fndecl, atype); |
12399 | else |
12400 | gcc_unreachable (); |
12401 | return; |
12402 | } |
12403 | if (TYPE_UNSIGNED (atype)) |
12404 | warning_at (loc, OPT_Wabsolute_value, |
12405 | "taking the absolute value of unsigned type %qT " |
12406 | "has no effect" , atype); |
12407 | break; |
12408 | |
12409 | CASE_FLT_FN (BUILT_IN_FABS): |
12410 | CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS): |
12411 | if (!SCALAR_FLOAT_TYPE_P (atype) |
12412 | || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype))) |
12413 | { |
12414 | if (INTEGRAL_TYPE_P (atype)) |
12415 | warning_at (loc, OPT_Wabsolute_value, |
12416 | "using floating-point absolute value function %qD " |
12417 | "when argument is of integer type %qT" , fndecl, atype); |
12418 | else if (DECIMAL_FLOAT_TYPE_P (atype)) |
12419 | warning_at (loc, OPT_Wabsolute_value, |
12420 | "using floating-point absolute value function %qD " |
12421 | "when argument is of decimal floating-point type %qT" , |
12422 | fndecl, atype); |
12423 | else if (TREE_CODE (atype) == COMPLEX_TYPE) |
12424 | warning_at (loc, OPT_Wabsolute_value, |
12425 | "using floating-point absolute value function %qD when " |
12426 | "argument is of complex type %qT" , fndecl, atype); |
12427 | else |
12428 | gcc_unreachable (); |
12429 | return; |
12430 | } |
12431 | break; |
12432 | |
12433 | CASE_FLT_FN (BUILT_IN_CABS): |
12434 | if (TREE_CODE (atype) != COMPLEX_TYPE) |
12435 | { |
12436 | if (INTEGRAL_TYPE_P (atype)) |
12437 | warning_at (loc, OPT_Wabsolute_value, |
12438 | "using complex absolute value function %qD when " |
12439 | "argument is of integer type %qT" , fndecl, atype); |
12440 | else if (SCALAR_FLOAT_TYPE_P (atype)) |
12441 | warning_at (loc, OPT_Wabsolute_value, |
12442 | "using complex absolute value function %qD when " |
12443 | "argument is of floating-point type %qT" , |
12444 | fndecl, atype); |
12445 | else |
12446 | gcc_unreachable (); |
12447 | |
12448 | return; |
12449 | } |
12450 | break; |
12451 | |
12452 | case BUILT_IN_FABSD32: |
12453 | case BUILT_IN_FABSD64: |
12454 | case BUILT_IN_FABSD128: |
12455 | if (!DECIMAL_FLOAT_TYPE_P (atype)) |
12456 | { |
12457 | if (INTEGRAL_TYPE_P (atype)) |
12458 | warning_at (loc, OPT_Wabsolute_value, |
12459 | "using decimal floating-point absolute value " |
12460 | "function %qD when argument is of integer type %qT" , |
12461 | fndecl, atype); |
12462 | else if (SCALAR_FLOAT_TYPE_P (atype)) |
12463 | warning_at (loc, OPT_Wabsolute_value, |
12464 | "using decimal floating-point absolute value " |
12465 | "function %qD when argument is of floating-point " |
12466 | "type %qT" , fndecl, atype); |
12467 | else if (TREE_CODE (atype) == COMPLEX_TYPE) |
12468 | warning_at (loc, OPT_Wabsolute_value, |
12469 | "using decimal floating-point absolute value " |
12470 | "function %qD when argument is of complex type %qT" , |
12471 | fndecl, atype); |
12472 | else |
12473 | gcc_unreachable (); |
12474 | return; |
12475 | } |
12476 | break; |
12477 | |
12478 | default: |
12479 | return; |
12480 | } |
12481 | |
12482 | if (!TYPE_ARG_TYPES (TREE_TYPE (fndecl))) |
12483 | return; |
12484 | |
12485 | tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); |
12486 | if (TREE_CODE (atype) == COMPLEX_TYPE) |
12487 | { |
12488 | gcc_assert (TREE_CODE (ftype) == COMPLEX_TYPE); |
12489 | atype = TREE_TYPE (atype); |
12490 | ftype = TREE_TYPE (ftype); |
12491 | } |
12492 | |
12493 | if (TYPE_PRECISION (ftype) < TYPE_PRECISION (atype)) |
12494 | warning_at (loc, OPT_Wabsolute_value, |
12495 | "absolute value function %qD given an argument of type %qT " |
12496 | "but has parameter of type %qT which may cause truncation " |
12497 | "of value" , fndecl, atype, ftype); |
12498 | } |
12499 | |
12500 | |
12501 | /* Parse a postfix expression after the initial primary or compound |
12502 | literal; that is, parse a series of postfix operators. |
12503 | |
12504 | EXPR_LOC is the location of the primary expression. */ |
12505 | |
12506 | static struct c_expr |
12507 | c_parser_postfix_expression_after_primary (c_parser *parser, |
12508 | location_t expr_loc, |
12509 | struct c_expr expr) |
12510 | { |
12511 | struct c_expr orig_expr; |
12512 | tree ident, idx, len; |
12513 | location_t sizeof_arg_loc[6], comp_loc; |
12514 | tree sizeof_arg[6]; |
12515 | unsigned int literal_zero_mask; |
12516 | unsigned int i; |
12517 | vec<tree, va_gc> *exprlist; |
12518 | vec<tree, va_gc> *origtypes = NULL; |
12519 | vec<location_t> arg_loc = vNULL; |
12520 | location_t start; |
12521 | location_t finish; |
12522 | |
12523 | while (true) |
12524 | { |
12525 | location_t op_loc = c_parser_peek_token (parser)->location; |
12526 | switch (c_parser_peek_token (parser)->type) |
12527 | { |
12528 | case CPP_OPEN_SQUARE: |
12529 | /* Array reference. */ |
12530 | c_parser_consume_token (parser); |
12531 | idx = len = NULL_TREE; |
12532 | if (!c_omp_array_section_p |
12533 | || c_parser_next_token_is_not (parser, type: CPP_COLON)) |
12534 | idx = c_parser_expression (parser).value; |
12535 | |
12536 | if (c_omp_array_section_p |
12537 | && c_parser_next_token_is (parser, type: CPP_COLON)) |
12538 | { |
12539 | c_parser_consume_token (parser); |
12540 | if (c_parser_next_token_is_not (parser, type: CPP_CLOSE_SQUARE)) |
12541 | len = c_parser_expression (parser).value; |
12542 | |
12543 | expr.value = build_omp_array_section (op_loc, expr.value, idx, |
12544 | len); |
12545 | } |
12546 | else |
12547 | expr.value = build_array_ref (op_loc, expr.value, idx); |
12548 | |
12549 | c_parser_skip_until_found (parser, type: CPP_CLOSE_SQUARE, |
12550 | msgid: "expected %<]%>" ); |
12551 | |
12552 | start = expr.get_start (); |
12553 | finish = parser->tokens_buf[0].location; |
12554 | set_c_expr_source_range (expr: &expr, start, finish); |
12555 | expr.original_code = ERROR_MARK; |
12556 | expr.original_type = NULL; |
12557 | expr.m_decimal = 0; |
12558 | break; |
12559 | case CPP_OPEN_PAREN: |
12560 | /* Function call. */ |
12561 | { |
12562 | matching_parens parens; |
12563 | parens.consume_open (parser); |
12564 | for (i = 0; i < 6; i++) |
12565 | { |
12566 | sizeof_arg[i] = NULL_TREE; |
12567 | sizeof_arg_loc[i] = UNKNOWN_LOCATION; |
12568 | } |
12569 | literal_zero_mask = 0; |
12570 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
12571 | exprlist = NULL; |
12572 | else if (TREE_CODE (expr.value) == FUNCTION_DECL |
12573 | && fndecl_built_in_p (node: expr.value, name1: BUILT_IN_CLASSIFY_TYPE) |
12574 | && c_parser_next_tokens_start_typename (parser, |
12575 | la: cla_prefer_id)) |
12576 | { |
12577 | /* __builtin_classify_type (type) */ |
12578 | c_inhibit_evaluation_warnings++; |
12579 | in_alignof++; |
12580 | struct c_type_name *type = c_parser_type_name (parser); |
12581 | c_inhibit_evaluation_warnings--; |
12582 | in_alignof--; |
12583 | struct c_typespec ret; |
12584 | ret.expr = NULL_TREE; |
12585 | ret.spec = error_mark_node; |
12586 | ret.expr_const_operands = false; |
12587 | if (type != NULL) |
12588 | ret.spec = groktypename (type, &ret.expr, |
12589 | &ret.expr_const_operands); |
12590 | parens.skip_until_found_close (parser); |
12591 | expr.value = build_int_cst (integer_type_node, |
12592 | type_to_class (ret.spec)); |
12593 | break; |
12594 | } |
12595 | else |
12596 | exprlist = c_parser_expr_list (parser, true, false, &origtypes, |
12597 | sizeof_arg_loc, sizeof_arg, |
12598 | &arg_loc, &literal_zero_mask); |
12599 | parens.skip_until_found_close (parser); |
12600 | } |
12601 | orig_expr = expr; |
12602 | mark_exp_read (expr.value); |
12603 | if (warn_sizeof_pointer_memaccess) |
12604 | sizeof_pointer_memaccess_warning (sizeof_arg_loc, |
12605 | expr.value, exprlist, |
12606 | sizeof_arg, |
12607 | sizeof_ptr_memacc_comptypes); |
12608 | if (TREE_CODE (expr.value) == FUNCTION_DECL) |
12609 | { |
12610 | if (fndecl_built_in_p (node: expr.value, name1: BUILT_IN_MEMSET) |
12611 | && vec_safe_length (v: exprlist) == 3) |
12612 | { |
12613 | tree arg0 = (*exprlist)[0]; |
12614 | tree arg2 = (*exprlist)[2]; |
12615 | warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask); |
12616 | } |
12617 | if (warn_absolute_value |
12618 | && fndecl_built_in_p (node: expr.value, klass: BUILT_IN_NORMAL) |
12619 | && vec_safe_length (v: exprlist) == 1) |
12620 | warn_for_abs (loc: expr_loc, fndecl: expr.value, arg: (*exprlist)[0]); |
12621 | if (parser->omp_for_parse_state |
12622 | && parser->omp_for_parse_state->in_intervening_code |
12623 | && omp_runtime_api_call (fndecl: expr.value)) |
12624 | { |
12625 | error_at (expr_loc, "calls to the OpenMP runtime API are " |
12626 | "not permitted in intervening code" ); |
12627 | parser->omp_for_parse_state->fail = true; |
12628 | } |
12629 | if (warn_calloc_transposed_args) |
12630 | if (tree attr = lookup_attribute (attr_name: "alloc_size" , |
12631 | TYPE_ATTRIBUTES |
12632 | (TREE_TYPE (expr.value)))) |
12633 | if (TREE_VALUE (attr) && TREE_CHAIN (TREE_VALUE (attr))) |
12634 | warn_for_calloc (sizeof_arg_loc, expr.value, exprlist, |
12635 | sizeof_arg, attr); |
12636 | } |
12637 | |
12638 | start = expr.get_start (); |
12639 | finish = parser->tokens_buf[0].get_finish (); |
12640 | expr.value |
12641 | = c_build_function_call_vec (expr_loc, arg_loc, expr.value, |
12642 | exprlist, origtypes); |
12643 | set_c_expr_source_range (expr: &expr, start, finish); |
12644 | expr.m_decimal = 0; |
12645 | |
12646 | expr.original_code = ERROR_MARK; |
12647 | if (TREE_CODE (expr.value) == INTEGER_CST |
12648 | && TREE_CODE (orig_expr.value) == FUNCTION_DECL |
12649 | && fndecl_built_in_p (node: orig_expr.value, name1: BUILT_IN_CONSTANT_P)) |
12650 | expr.original_code = C_MAYBE_CONST_EXPR; |
12651 | expr.original_type = NULL; |
12652 | if (exprlist) |
12653 | { |
12654 | release_tree_vector (exprlist); |
12655 | release_tree_vector (origtypes); |
12656 | } |
12657 | arg_loc.release (); |
12658 | break; |
12659 | case CPP_DOT: |
12660 | /* Structure element reference. */ |
12661 | c_parser_consume_token (parser); |
12662 | expr = default_function_array_conversion (expr_loc, expr); |
12663 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
12664 | { |
12665 | c_token *comp_tok = c_parser_peek_token (parser); |
12666 | ident = comp_tok->value; |
12667 | comp_loc = comp_tok->location; |
12668 | } |
12669 | else |
12670 | { |
12671 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12672 | expr.set_error (); |
12673 | expr.original_code = ERROR_MARK; |
12674 | expr.original_type = NULL; |
12675 | return expr; |
12676 | } |
12677 | start = expr.get_start (); |
12678 | finish = c_parser_peek_token (parser)->get_finish (); |
12679 | c_parser_consume_token (parser); |
12680 | expr.value = build_component_ref (op_loc, expr.value, ident, |
12681 | comp_loc, UNKNOWN_LOCATION); |
12682 | set_c_expr_source_range (expr: &expr, start, finish); |
12683 | expr.original_code = ERROR_MARK; |
12684 | if (TREE_CODE (expr.value) != COMPONENT_REF) |
12685 | expr.original_type = NULL; |
12686 | else |
12687 | { |
12688 | /* Remember the original type of a bitfield. */ |
12689 | tree field = TREE_OPERAND (expr.value, 1); |
12690 | if (TREE_CODE (field) != FIELD_DECL) |
12691 | expr.original_type = NULL; |
12692 | else |
12693 | expr.original_type = DECL_BIT_FIELD_TYPE (field); |
12694 | } |
12695 | expr.m_decimal = 0; |
12696 | break; |
12697 | case CPP_DEREF: |
12698 | /* Structure element reference. */ |
12699 | c_parser_consume_token (parser); |
12700 | expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false); |
12701 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
12702 | { |
12703 | c_token *comp_tok = c_parser_peek_token (parser); |
12704 | ident = comp_tok->value; |
12705 | comp_loc = comp_tok->location; |
12706 | } |
12707 | else |
12708 | { |
12709 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12710 | expr.set_error (); |
12711 | expr.original_code = ERROR_MARK; |
12712 | expr.original_type = NULL; |
12713 | return expr; |
12714 | } |
12715 | start = expr.get_start (); |
12716 | finish = c_parser_peek_token (parser)->get_finish (); |
12717 | c_parser_consume_token (parser); |
12718 | expr.value = build_component_ref (op_loc, |
12719 | build_indirect_ref (op_loc, |
12720 | expr.value, |
12721 | RO_ARROW), |
12722 | ident, comp_loc, |
12723 | expr.get_location ()); |
12724 | set_c_expr_source_range (expr: &expr, start, finish); |
12725 | expr.original_code = ERROR_MARK; |
12726 | if (TREE_CODE (expr.value) != COMPONENT_REF) |
12727 | expr.original_type = NULL; |
12728 | else |
12729 | { |
12730 | /* Remember the original type of a bitfield. */ |
12731 | tree field = TREE_OPERAND (expr.value, 1); |
12732 | if (TREE_CODE (field) != FIELD_DECL) |
12733 | expr.original_type = NULL; |
12734 | else |
12735 | expr.original_type = DECL_BIT_FIELD_TYPE (field); |
12736 | } |
12737 | expr.m_decimal = 0; |
12738 | break; |
12739 | case CPP_PLUS_PLUS: |
12740 | /* Postincrement. */ |
12741 | start = expr.get_start (); |
12742 | finish = c_parser_peek_token (parser)->get_finish (); |
12743 | c_parser_consume_token (parser); |
12744 | expr = default_function_array_read_conversion (expr_loc, expr); |
12745 | expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR, |
12746 | expr.value, false); |
12747 | set_c_expr_source_range (expr: &expr, start, finish); |
12748 | expr.original_code = ERROR_MARK; |
12749 | expr.original_type = NULL; |
12750 | break; |
12751 | case CPP_MINUS_MINUS: |
12752 | /* Postdecrement. */ |
12753 | start = expr.get_start (); |
12754 | finish = c_parser_peek_token (parser)->get_finish (); |
12755 | c_parser_consume_token (parser); |
12756 | expr = default_function_array_read_conversion (expr_loc, expr); |
12757 | expr.value = build_unary_op (op_loc, POSTDECREMENT_EXPR, |
12758 | expr.value, false); |
12759 | set_c_expr_source_range (expr: &expr, start, finish); |
12760 | expr.original_code = ERROR_MARK; |
12761 | expr.original_type = NULL; |
12762 | break; |
12763 | default: |
12764 | return expr; |
12765 | } |
12766 | } |
12767 | } |
12768 | |
12769 | /* Parse an expression (C90 6.3.17, C99 6.5.17, C11 6.5.17). |
12770 | |
12771 | expression: |
12772 | assignment-expression |
12773 | expression , assignment-expression |
12774 | */ |
12775 | |
12776 | static struct c_expr |
12777 | c_parser_expression (c_parser *parser) |
12778 | { |
12779 | location_t tloc = c_parser_peek_token (parser)->location; |
12780 | struct c_expr expr; |
12781 | expr = c_parser_expr_no_commas (parser, NULL); |
12782 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12783 | expr = convert_lvalue_to_rvalue (tloc, expr, true, false); |
12784 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12785 | { |
12786 | struct c_expr next; |
12787 | tree lhsval; |
12788 | location_t loc = c_parser_peek_token (parser)->location; |
12789 | location_t expr_loc; |
12790 | c_parser_consume_token (parser); |
12791 | expr_loc = c_parser_peek_token (parser)->location; |
12792 | lhsval = expr.value; |
12793 | while (TREE_CODE (lhsval) == COMPOUND_EXPR |
12794 | || TREE_CODE (lhsval) == NOP_EXPR) |
12795 | { |
12796 | if (TREE_CODE (lhsval) == COMPOUND_EXPR) |
12797 | lhsval = TREE_OPERAND (lhsval, 1); |
12798 | else |
12799 | lhsval = TREE_OPERAND (lhsval, 0); |
12800 | } |
12801 | if (DECL_P (lhsval) || handled_component_p (t: lhsval)) |
12802 | mark_exp_read (lhsval); |
12803 | next = c_parser_expr_no_commas (parser, NULL); |
12804 | next = convert_lvalue_to_rvalue (expr_loc, next, true, false); |
12805 | expr.value = build_compound_expr (loc, expr.value, next.value); |
12806 | expr.original_code = COMPOUND_EXPR; |
12807 | expr.original_type = next.original_type; |
12808 | expr.m_decimal = 0; |
12809 | } |
12810 | return expr; |
12811 | } |
12812 | |
12813 | /* Parse an expression and convert functions or arrays to pointers and |
12814 | lvalues to rvalues. */ |
12815 | |
12816 | static struct c_expr |
12817 | c_parser_expression_conv (c_parser *parser) |
12818 | { |
12819 | struct c_expr expr; |
12820 | location_t loc = c_parser_peek_token (parser)->location; |
12821 | expr = c_parser_expression (parser); |
12822 | expr = convert_lvalue_to_rvalue (loc, expr, true, false); |
12823 | return expr; |
12824 | } |
12825 | |
12826 | /* Helper function of c_parser_expr_list. Check if IDXth (0 based) |
12827 | argument is a literal zero alone and if so, set it in literal_zero_mask. */ |
12828 | |
12829 | static inline void |
12830 | c_parser_check_literal_zero (c_parser *parser, unsigned *literal_zero_mask, |
12831 | unsigned int idx) |
12832 | { |
12833 | if (idx >= HOST_BITS_PER_INT) |
12834 | return; |
12835 | |
12836 | c_token *tok = c_parser_peek_token (parser); |
12837 | switch (tok->type) |
12838 | { |
12839 | case CPP_NUMBER: |
12840 | case CPP_CHAR: |
12841 | case CPP_WCHAR: |
12842 | case CPP_CHAR16: |
12843 | case CPP_CHAR32: |
12844 | case CPP_UTF8CHAR: |
12845 | /* If a parameter is literal zero alone, remember it |
12846 | for -Wmemset-transposed-args warning. */ |
12847 | if (integer_zerop (tok->value) |
12848 | && !TREE_OVERFLOW (tok->value) |
12849 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
12850 | || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) |
12851 | *literal_zero_mask |= 1U << idx; |
12852 | default: |
12853 | break; |
12854 | } |
12855 | } |
12856 | |
12857 | /* Parse a non-empty list of expressions. If CONVERT_P, convert |
12858 | functions and arrays to pointers and lvalues to rvalues. If |
12859 | FOLD_P, fold the expressions. If LOCATIONS is non-NULL, save the |
12860 | locations of function arguments into this vector. |
12861 | |
12862 | nonempty-expr-list: |
12863 | assignment-expression |
12864 | nonempty-expr-list , assignment-expression |
12865 | */ |
12866 | |
12867 | static vec<tree, va_gc> * |
12868 | c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, |
12869 | vec<tree, va_gc> **p_orig_types, |
12870 | location_t *sizeof_arg_loc, tree *sizeof_arg, |
12871 | vec<location_t> *locations, |
12872 | unsigned int *literal_zero_mask) |
12873 | { |
12874 | vec<tree, va_gc> *ret; |
12875 | vec<tree, va_gc> *orig_types; |
12876 | struct c_expr expr; |
12877 | unsigned int idx = 0; |
12878 | bool save_c_omp_array_section_p = c_omp_array_section_p; |
12879 | c_omp_array_section_p = false; |
12880 | |
12881 | ret = make_tree_vector (); |
12882 | if (p_orig_types == NULL) |
12883 | orig_types = NULL; |
12884 | else |
12885 | orig_types = make_tree_vector (); |
12886 | |
12887 | if (literal_zero_mask) |
12888 | c_parser_check_literal_zero (parser, literal_zero_mask, idx: 0); |
12889 | expr = c_parser_expr_no_commas (parser, NULL); |
12890 | if (convert_p) |
12891 | expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, true); |
12892 | if (fold_p) |
12893 | expr.value = c_fully_fold (expr.value, false, NULL); |
12894 | ret->quick_push (obj: expr.value); |
12895 | if (orig_types) |
12896 | orig_types->quick_push (obj: expr.original_type); |
12897 | if (locations) |
12898 | locations->safe_push (obj: expr.get_location ()); |
12899 | if (sizeof_arg != NULL |
12900 | && (expr.original_code == SIZEOF_EXPR |
12901 | || expr.original_code == PAREN_SIZEOF_EXPR)) |
12902 | { |
12903 | sizeof_arg[0] = c_last_sizeof_arg; |
12904 | sizeof_arg_loc[0] = c_last_sizeof_loc; |
12905 | } |
12906 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
12907 | { |
12908 | c_parser_consume_token (parser); |
12909 | if (literal_zero_mask) |
12910 | c_parser_check_literal_zero (parser, literal_zero_mask, idx: idx + 1); |
12911 | expr = c_parser_expr_no_commas (parser, NULL); |
12912 | if (convert_p) |
12913 | expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, |
12914 | true); |
12915 | if (fold_p) |
12916 | expr.value = c_fully_fold (expr.value, false, NULL); |
12917 | vec_safe_push (v&: ret, obj: expr.value); |
12918 | if (orig_types) |
12919 | vec_safe_push (v&: orig_types, obj: expr.original_type); |
12920 | if (locations) |
12921 | locations->safe_push (obj: expr.get_location ()); |
12922 | if (++idx < 6 |
12923 | && sizeof_arg != NULL |
12924 | && (expr.original_code == SIZEOF_EXPR |
12925 | || expr.original_code == PAREN_SIZEOF_EXPR)) |
12926 | { |
12927 | sizeof_arg[idx] = c_last_sizeof_arg; |
12928 | sizeof_arg_loc[idx] = c_last_sizeof_loc; |
12929 | } |
12930 | } |
12931 | if (orig_types) |
12932 | *p_orig_types = orig_types; |
12933 | c_omp_array_section_p = save_c_omp_array_section_p; |
12934 | return ret; |
12935 | } |
12936 | |
12937 | /* Parse Objective-C-specific constructs. */ |
12938 | |
12939 | /* Parse an objc-class-definition. |
12940 | |
12941 | objc-class-definition: |
12942 | @interface identifier objc-superclass[opt] objc-protocol-refs[opt] |
12943 | objc-class-instance-variables[opt] objc-methodprotolist @end |
12944 | @implementation identifier objc-superclass[opt] |
12945 | objc-class-instance-variables[opt] |
12946 | @interface identifier ( identifier ) objc-protocol-refs[opt] |
12947 | objc-methodprotolist @end |
12948 | @interface identifier ( ) objc-protocol-refs[opt] |
12949 | objc-methodprotolist @end |
12950 | @implementation identifier ( identifier ) |
12951 | |
12952 | objc-superclass: |
12953 | : identifier |
12954 | |
12955 | "@interface identifier (" must start "@interface identifier ( |
12956 | identifier ) ...": objc-methodprotolist in the first production may |
12957 | not start with a parenthesized identifier as a declarator of a data |
12958 | definition with no declaration specifiers if the objc-superclass, |
12959 | objc-protocol-refs and objc-class-instance-variables are omitted. */ |
12960 | |
12961 | static void |
12962 | c_parser_objc_class_definition (c_parser *parser, tree attributes) |
12963 | { |
12964 | bool iface_p; |
12965 | tree id1; |
12966 | tree superclass; |
12967 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_INTERFACE)) |
12968 | iface_p = true; |
12969 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_IMPLEMENTATION)) |
12970 | iface_p = false; |
12971 | else |
12972 | gcc_unreachable (); |
12973 | |
12974 | c_parser_consume_token (parser); |
12975 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12976 | { |
12977 | c_parser_error (parser, gmsgid: "expected identifier" ); |
12978 | return; |
12979 | } |
12980 | id1 = c_parser_peek_token (parser)->value; |
12981 | location_t loc1 = c_parser_peek_token (parser)->location; |
12982 | c_parser_consume_token (parser); |
12983 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
12984 | { |
12985 | /* We have a category or class extension. */ |
12986 | tree id2; |
12987 | tree proto = NULL_TREE; |
12988 | matching_parens parens; |
12989 | parens.consume_open (parser); |
12990 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
12991 | { |
12992 | if (iface_p && c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
12993 | { |
12994 | /* We have a class extension. */ |
12995 | id2 = NULL_TREE; |
12996 | } |
12997 | else |
12998 | { |
12999 | c_parser_error (parser, gmsgid: "expected identifier or %<)%>" ); |
13000 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
13001 | return; |
13002 | } |
13003 | } |
13004 | else |
13005 | { |
13006 | id2 = c_parser_peek_token (parser)->value; |
13007 | c_parser_consume_token (parser); |
13008 | } |
13009 | parens.skip_until_found_close (parser); |
13010 | if (!iface_p) |
13011 | { |
13012 | objc_start_category_implementation (id1, id2); |
13013 | return; |
13014 | } |
13015 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
13016 | proto = c_parser_objc_protocol_refs (parser); |
13017 | objc_start_category_interface (id1, id2, proto, attributes); |
13018 | c_parser_objc_methodprotolist (parser); |
13019 | c_parser_require_keyword (parser, keyword: RID_AT_END, msgid: "expected %<@end%>" ); |
13020 | objc_finish_interface (); |
13021 | return; |
13022 | } |
13023 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
13024 | { |
13025 | c_parser_consume_token (parser); |
13026 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13027 | { |
13028 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13029 | return; |
13030 | } |
13031 | superclass = c_parser_peek_token (parser)->value; |
13032 | c_parser_consume_token (parser); |
13033 | } |
13034 | else |
13035 | superclass = NULL_TREE; |
13036 | if (iface_p) |
13037 | { |
13038 | tree proto = NULL_TREE; |
13039 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
13040 | proto = c_parser_objc_protocol_refs (parser); |
13041 | objc_start_class_interface (id1, loc1, superclass, proto, attributes); |
13042 | } |
13043 | else |
13044 | objc_start_class_implementation (id1, superclass); |
13045 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
13046 | c_parser_objc_class_instance_variables (parser); |
13047 | if (iface_p) |
13048 | { |
13049 | objc_continue_interface (); |
13050 | c_parser_objc_methodprotolist (parser); |
13051 | c_parser_require_keyword (parser, keyword: RID_AT_END, msgid: "expected %<@end%>" ); |
13052 | objc_finish_interface (); |
13053 | } |
13054 | else |
13055 | { |
13056 | objc_continue_implementation (); |
13057 | return; |
13058 | } |
13059 | } |
13060 | |
13061 | /* Parse objc-class-instance-variables. |
13062 | |
13063 | objc-class-instance-variables: |
13064 | { objc-instance-variable-decl-list[opt] } |
13065 | |
13066 | objc-instance-variable-decl-list: |
13067 | objc-visibility-spec |
13068 | objc-instance-variable-decl ; |
13069 | ; |
13070 | objc-instance-variable-decl-list objc-visibility-spec |
13071 | objc-instance-variable-decl-list objc-instance-variable-decl ; |
13072 | objc-instance-variable-decl-list ; |
13073 | |
13074 | objc-visibility-spec: |
13075 | @private |
13076 | @protected |
13077 | @public |
13078 | |
13079 | objc-instance-variable-decl: |
13080 | struct-declaration |
13081 | */ |
13082 | |
13083 | static void |
13084 | c_parser_objc_class_instance_variables (c_parser *parser) |
13085 | { |
13086 | gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); |
13087 | c_parser_consume_token (parser); |
13088 | while (c_parser_next_token_is_not (parser, type: CPP_EOF)) |
13089 | { |
13090 | tree decls; |
13091 | /* Parse any stray semicolon. */ |
13092 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
13093 | { |
13094 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
13095 | "extra semicolon" ); |
13096 | c_parser_consume_token (parser); |
13097 | continue; |
13098 | } |
13099 | /* Stop if at the end of the instance variables. */ |
13100 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
13101 | { |
13102 | c_parser_consume_token (parser); |
13103 | break; |
13104 | } |
13105 | /* Parse any objc-visibility-spec. */ |
13106 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PRIVATE)) |
13107 | { |
13108 | c_parser_consume_token (parser); |
13109 | objc_set_visibility (OBJC_IVAR_VIS_PRIVATE); |
13110 | continue; |
13111 | } |
13112 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PROTECTED)) |
13113 | { |
13114 | c_parser_consume_token (parser); |
13115 | objc_set_visibility (OBJC_IVAR_VIS_PROTECTED); |
13116 | continue; |
13117 | } |
13118 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PUBLIC)) |
13119 | { |
13120 | c_parser_consume_token (parser); |
13121 | objc_set_visibility (OBJC_IVAR_VIS_PUBLIC); |
13122 | continue; |
13123 | } |
13124 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PACKAGE)) |
13125 | { |
13126 | c_parser_consume_token (parser); |
13127 | objc_set_visibility (OBJC_IVAR_VIS_PACKAGE); |
13128 | continue; |
13129 | } |
13130 | else if (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
13131 | { |
13132 | c_parser_pragma (parser, pragma_external, NULL); |
13133 | continue; |
13134 | } |
13135 | |
13136 | /* Parse some comma-separated declarations. */ |
13137 | decls = c_parser_struct_declaration (parser, NULL); |
13138 | if (decls == NULL) |
13139 | { |
13140 | /* There is a syntax error. We want to skip the offending |
13141 | tokens up to the next ';' (included) or '}' |
13142 | (excluded). */ |
13143 | |
13144 | /* First, skip manually a ')' or ']'. This is because they |
13145 | reduce the nesting level, so c_parser_skip_until_found() |
13146 | wouldn't be able to skip past them. */ |
13147 | c_token *token = c_parser_peek_token (parser); |
13148 | if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE) |
13149 | c_parser_consume_token (parser); |
13150 | |
13151 | /* Then, do the standard skipping. */ |
13152 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
13153 | |
13154 | /* We hopefully recovered. Start normal parsing again. */ |
13155 | parser->error = false; |
13156 | continue; |
13157 | } |
13158 | else |
13159 | { |
13160 | /* Comma-separated instance variables are chained together |
13161 | in reverse order; add them one by one. */ |
13162 | tree ivar = nreverse (decls); |
13163 | for (; ivar; ivar = DECL_CHAIN (ivar)) |
13164 | objc_add_instance_variable (copy_node (ivar)); |
13165 | } |
13166 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13167 | } |
13168 | } |
13169 | |
13170 | /* Parse an objc-class-declaration. |
13171 | |
13172 | objc-class-declaration: |
13173 | @class identifier-list ; |
13174 | */ |
13175 | |
13176 | static void |
13177 | c_parser_objc_class_declaration (c_parser *parser) |
13178 | { |
13179 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS)); |
13180 | c_parser_consume_token (parser); |
13181 | /* Any identifiers, including those declared as type names, are OK |
13182 | here. */ |
13183 | while (true) |
13184 | { |
13185 | tree id; |
13186 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13187 | { |
13188 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13189 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
13190 | parser->error = false; |
13191 | return; |
13192 | } |
13193 | id = c_parser_peek_token (parser)->value; |
13194 | objc_declare_class (id); |
13195 | c_parser_consume_token (parser); |
13196 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13197 | c_parser_consume_token (parser); |
13198 | else |
13199 | break; |
13200 | } |
13201 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13202 | } |
13203 | |
13204 | /* Parse an objc-alias-declaration. |
13205 | |
13206 | objc-alias-declaration: |
13207 | @compatibility_alias identifier identifier ; |
13208 | */ |
13209 | |
13210 | static void |
13211 | c_parser_objc_alias_declaration (c_parser *parser) |
13212 | { |
13213 | tree id1, id2; |
13214 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS)); |
13215 | c_parser_consume_token (parser); |
13216 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13217 | { |
13218 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13219 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
13220 | return; |
13221 | } |
13222 | id1 = c_parser_peek_token (parser)->value; |
13223 | c_parser_consume_token (parser); |
13224 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13225 | { |
13226 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13227 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
13228 | return; |
13229 | } |
13230 | id2 = c_parser_peek_token (parser)->value; |
13231 | c_parser_consume_token (parser); |
13232 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13233 | objc_declare_alias (id1, id2); |
13234 | } |
13235 | |
13236 | /* Parse an objc-protocol-definition. |
13237 | |
13238 | objc-protocol-definition: |
13239 | @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end |
13240 | @protocol identifier-list ; |
13241 | |
13242 | "@protocol identifier ;" should be resolved as "@protocol |
13243 | identifier-list ;": objc-methodprotolist may not start with a |
13244 | semicolon in the first alternative if objc-protocol-refs are |
13245 | omitted. */ |
13246 | |
13247 | static void |
13248 | c_parser_objc_protocol_definition (c_parser *parser, tree attributes) |
13249 | { |
13250 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL)); |
13251 | |
13252 | c_parser_consume_token (parser); |
13253 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13254 | { |
13255 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13256 | return; |
13257 | } |
13258 | if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
13259 | || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON) |
13260 | { |
13261 | /* Any identifiers, including those declared as type names, are |
13262 | OK here. */ |
13263 | while (true) |
13264 | { |
13265 | tree id; |
13266 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13267 | { |
13268 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13269 | break; |
13270 | } |
13271 | id = c_parser_peek_token (parser)->value; |
13272 | objc_declare_protocol (id, attributes); |
13273 | c_parser_consume_token (parser); |
13274 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13275 | c_parser_consume_token (parser); |
13276 | else |
13277 | break; |
13278 | } |
13279 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13280 | } |
13281 | else |
13282 | { |
13283 | tree id = c_parser_peek_token (parser)->value; |
13284 | tree proto = NULL_TREE; |
13285 | c_parser_consume_token (parser); |
13286 | if (c_parser_next_token_is (parser, type: CPP_LESS)) |
13287 | proto = c_parser_objc_protocol_refs (parser); |
13288 | parser->objc_pq_context = true; |
13289 | objc_start_protocol (id, proto, attributes); |
13290 | c_parser_objc_methodprotolist (parser); |
13291 | c_parser_require_keyword (parser, keyword: RID_AT_END, msgid: "expected %<@end%>" ); |
13292 | parser->objc_pq_context = false; |
13293 | objc_finish_interface (); |
13294 | } |
13295 | } |
13296 | |
13297 | /* Parse an objc-method-type. |
13298 | |
13299 | objc-method-type: |
13300 | + |
13301 | - |
13302 | |
13303 | Return true if it is a class method (+) and false if it is |
13304 | an instance method (-). |
13305 | */ |
13306 | static inline bool |
13307 | c_parser_objc_method_type (c_parser *parser) |
13308 | { |
13309 | switch (c_parser_peek_token (parser)->type) |
13310 | { |
13311 | case CPP_PLUS: |
13312 | c_parser_consume_token (parser); |
13313 | return true; |
13314 | case CPP_MINUS: |
13315 | c_parser_consume_token (parser); |
13316 | return false; |
13317 | default: |
13318 | gcc_unreachable (); |
13319 | } |
13320 | } |
13321 | |
13322 | /* Parse an objc-method-definition. |
13323 | |
13324 | objc-method-definition: |
13325 | objc-method-type objc-method-decl ;[opt] compound-statement |
13326 | */ |
13327 | |
13328 | static void |
13329 | c_parser_objc_method_definition (c_parser *parser) |
13330 | { |
13331 | bool is_class_method = c_parser_objc_method_type (parser); |
13332 | tree decl, attributes = NULL_TREE, expr = NULL_TREE; |
13333 | parser->objc_pq_context = true; |
13334 | decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, |
13335 | &expr); |
13336 | if (decl == error_mark_node) |
13337 | return; /* Bail here. */ |
13338 | |
13339 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
13340 | { |
13341 | c_parser_consume_token (parser); |
13342 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
13343 | "extra semicolon in method definition specified" ); |
13344 | } |
13345 | |
13346 | if (!c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
13347 | { |
13348 | c_parser_error (parser, gmsgid: "expected %<{%>" ); |
13349 | return; |
13350 | } |
13351 | |
13352 | parser->objc_pq_context = false; |
13353 | if (objc_start_method_definition (is_class_method, decl, attributes, expr)) |
13354 | { |
13355 | add_stmt (c_parser_compound_statement (parser)); |
13356 | objc_finish_method_definition (current_function_decl); |
13357 | } |
13358 | else |
13359 | { |
13360 | /* This code is executed when we find a method definition |
13361 | outside of an @implementation context (or invalid for other |
13362 | reasons). Parse the method (to keep going) but do not emit |
13363 | any code. |
13364 | */ |
13365 | c_parser_compound_statement (parser); |
13366 | } |
13367 | } |
13368 | |
13369 | /* Parse an objc-methodprotolist. |
13370 | |
13371 | objc-methodprotolist: |
13372 | empty |
13373 | objc-methodprotolist objc-methodproto |
13374 | objc-methodprotolist declaration |
13375 | objc-methodprotolist ; |
13376 | @optional |
13377 | @required |
13378 | |
13379 | The declaration is a data definition, which may be missing |
13380 | declaration specifiers under the same rules and diagnostics as |
13381 | other data definitions outside functions, and the stray semicolon |
13382 | is diagnosed the same way as a stray semicolon outside a |
13383 | function. */ |
13384 | |
13385 | static void |
13386 | c_parser_objc_methodprotolist (c_parser *parser) |
13387 | { |
13388 | while (true) |
13389 | { |
13390 | /* The list is terminated by @end. */ |
13391 | switch (c_parser_peek_token (parser)->type) |
13392 | { |
13393 | case CPP_SEMICOLON: |
13394 | pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, |
13395 | "ISO C does not allow extra %<;%> outside of a function" ); |
13396 | c_parser_consume_token (parser); |
13397 | break; |
13398 | case CPP_PLUS: |
13399 | case CPP_MINUS: |
13400 | c_parser_objc_methodproto (parser); |
13401 | break; |
13402 | case CPP_PRAGMA: |
13403 | c_parser_pragma (parser, pragma_external, NULL); |
13404 | break; |
13405 | case CPP_EOF: |
13406 | return; |
13407 | default: |
13408 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_END)) |
13409 | return; |
13410 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_PROPERTY)) |
13411 | c_parser_objc_at_property_declaration (parser); |
13412 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_OPTIONAL)) |
13413 | { |
13414 | objc_set_method_opt (true); |
13415 | c_parser_consume_token (parser); |
13416 | } |
13417 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_REQUIRED)) |
13418 | { |
13419 | objc_set_method_opt (false); |
13420 | c_parser_consume_token (parser); |
13421 | } |
13422 | else |
13423 | c_parser_declaration_or_fndef (parser, fndef_ok: false, static_assert_ok: false, empty_ok: true, |
13424 | nested: false, start_attr_ok: true); |
13425 | break; |
13426 | } |
13427 | } |
13428 | } |
13429 | |
13430 | /* Parse an objc-methodproto. |
13431 | |
13432 | objc-methodproto: |
13433 | objc-method-type objc-method-decl ; |
13434 | */ |
13435 | |
13436 | static void |
13437 | c_parser_objc_methodproto (c_parser *parser) |
13438 | { |
13439 | bool is_class_method = c_parser_objc_method_type (parser); |
13440 | tree decl, attributes = NULL_TREE; |
13441 | |
13442 | /* Remember protocol qualifiers in prototypes. */ |
13443 | parser->objc_pq_context = true; |
13444 | decl = c_parser_objc_method_decl (parser, is_class_method, &attributes, |
13445 | NULL); |
13446 | /* Forget protocol qualifiers now. */ |
13447 | parser->objc_pq_context = false; |
13448 | |
13449 | /* Do not allow the presence of attributes to hide an erroneous |
13450 | method implementation in the interface section. */ |
13451 | if (!c_parser_next_token_is (parser, type: CPP_SEMICOLON)) |
13452 | { |
13453 | c_parser_error (parser, gmsgid: "expected %<;%>" ); |
13454 | return; |
13455 | } |
13456 | |
13457 | if (decl != error_mark_node) |
13458 | objc_add_method_declaration (is_class_method, decl, attributes); |
13459 | |
13460 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
13461 | } |
13462 | |
13463 | /* If we are at a position that method attributes may be present, check that |
13464 | there are not any parsed already (a syntax error) and then collect any |
13465 | specified at the current location. Finally, if new attributes were present, |
13466 | check that the next token is legal ( ';' for decls and '{' for defs). */ |
13467 | |
13468 | static bool |
13469 | c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes) |
13470 | { |
13471 | bool bad = false; |
13472 | if (*attributes) |
13473 | { |
13474 | c_parser_error (parser, |
13475 | gmsgid: "method attributes must be specified at the end only" ); |
13476 | *attributes = NULL_TREE; |
13477 | bad = true; |
13478 | } |
13479 | |
13480 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
13481 | *attributes = c_parser_gnu_attributes (parser); |
13482 | |
13483 | /* If there were no attributes here, just report any earlier error. */ |
13484 | if (*attributes == NULL_TREE || bad) |
13485 | return bad; |
13486 | |
13487 | /* If the attributes are followed by a ; or {, then just report any earlier |
13488 | error. */ |
13489 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
13490 | || c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
13491 | return bad; |
13492 | |
13493 | /* We've got attributes, but not at the end. */ |
13494 | c_parser_error (parser, |
13495 | gmsgid: "expected %<;%> or %<{%> after method attribute definition" ); |
13496 | return true; |
13497 | } |
13498 | |
13499 | /* Parse an objc-method-decl. |
13500 | |
13501 | objc-method-decl: |
13502 | ( objc-type-name ) objc-selector |
13503 | objc-selector |
13504 | ( objc-type-name ) objc-keyword-selector objc-optparmlist |
13505 | objc-keyword-selector objc-optparmlist |
13506 | gnu-attributes |
13507 | |
13508 | objc-keyword-selector: |
13509 | objc-keyword-decl |
13510 | objc-keyword-selector objc-keyword-decl |
13511 | |
13512 | objc-keyword-decl: |
13513 | objc-selector : ( objc-type-name ) identifier |
13514 | objc-selector : identifier |
13515 | : ( objc-type-name ) identifier |
13516 | : identifier |
13517 | |
13518 | objc-optparmlist: |
13519 | objc-optparms objc-optellipsis |
13520 | |
13521 | objc-optparms: |
13522 | empty |
13523 | objc-opt-parms , parameter-declaration |
13524 | |
13525 | objc-optellipsis: |
13526 | empty |
13527 | , ... |
13528 | */ |
13529 | |
13530 | static tree |
13531 | c_parser_objc_method_decl (c_parser *parser, bool is_class_method, |
13532 | tree *attributes, tree *expr) |
13533 | { |
13534 | tree type = NULL_TREE; |
13535 | tree sel; |
13536 | tree parms = NULL_TREE; |
13537 | bool ellipsis = false; |
13538 | bool attr_err = false; |
13539 | |
13540 | *attributes = NULL_TREE; |
13541 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
13542 | { |
13543 | matching_parens parens; |
13544 | parens.consume_open (parser); |
13545 | type = c_parser_objc_type_name (parser); |
13546 | parens.skip_until_found_close (parser); |
13547 | } |
13548 | sel = c_parser_objc_selector (parser); |
13549 | /* If there is no selector, or a colon follows, we have an |
13550 | objc-keyword-selector. If there is a selector, and a colon does |
13551 | not follow, that selector ends the objc-method-decl. */ |
13552 | if (!sel || c_parser_next_token_is (parser, type: CPP_COLON)) |
13553 | { |
13554 | tree tsel = sel; |
13555 | tree list = NULL_TREE; |
13556 | while (true) |
13557 | { |
13558 | tree atype = NULL_TREE, id, keyworddecl; |
13559 | tree param_attr = NULL_TREE; |
13560 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
13561 | break; |
13562 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
13563 | { |
13564 | c_parser_consume_token (parser); |
13565 | atype = c_parser_objc_type_name (parser); |
13566 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
13567 | msgid: "expected %<)%>" ); |
13568 | } |
13569 | /* New ObjC allows attributes on method parameters. */ |
13570 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
13571 | param_attr = c_parser_gnu_attributes (parser); |
13572 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13573 | { |
13574 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13575 | return error_mark_node; |
13576 | } |
13577 | id = c_parser_peek_token (parser)->value; |
13578 | c_parser_consume_token (parser); |
13579 | keyworddecl = objc_build_keyword_decl (tsel, atype, id, param_attr); |
13580 | list = chainon (list, keyworddecl); |
13581 | tsel = c_parser_objc_selector (parser); |
13582 | if (!tsel && c_parser_next_token_is_not (parser, type: CPP_COLON)) |
13583 | break; |
13584 | } |
13585 | |
13586 | attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; |
13587 | |
13588 | /* Parse the optional parameter list. Optional Objective-C |
13589 | method parameters follow the C syntax, and may include '...' |
13590 | to denote a variable number of arguments. */ |
13591 | parms = make_node (TREE_LIST); |
13592 | while (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13593 | { |
13594 | struct c_parm *parm; |
13595 | c_parser_consume_token (parser); |
13596 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
13597 | { |
13598 | ellipsis = true; |
13599 | c_parser_consume_token (parser); |
13600 | attr_err |= c_parser_objc_maybe_method_attributes |
13601 | (parser, attributes) ; |
13602 | break; |
13603 | } |
13604 | parm = c_parser_parameter_declaration (parser, NULL_TREE, have_gnu_attrs: false); |
13605 | if (parm == NULL) |
13606 | break; |
13607 | parms = chainon (parms, |
13608 | build_tree_list (NULL_TREE, grokparm (parm, expr))); |
13609 | } |
13610 | sel = list; |
13611 | } |
13612 | else |
13613 | attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ; |
13614 | |
13615 | if (sel == NULL) |
13616 | { |
13617 | c_parser_error (parser, gmsgid: "objective-c method declaration is expected" ); |
13618 | return error_mark_node; |
13619 | } |
13620 | |
13621 | if (attr_err) |
13622 | return error_mark_node; |
13623 | |
13624 | return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis); |
13625 | } |
13626 | |
13627 | /* Parse an objc-type-name. |
13628 | |
13629 | objc-type-name: |
13630 | objc-type-qualifiers[opt] type-name |
13631 | objc-type-qualifiers[opt] |
13632 | |
13633 | objc-type-qualifiers: |
13634 | objc-type-qualifier |
13635 | objc-type-qualifiers objc-type-qualifier |
13636 | |
13637 | objc-type-qualifier: one of |
13638 | in out inout bycopy byref oneway |
13639 | */ |
13640 | |
13641 | static tree |
13642 | c_parser_objc_type_name (c_parser *parser) |
13643 | { |
13644 | tree quals = NULL_TREE; |
13645 | struct c_type_name *type_name = NULL; |
13646 | tree type = NULL_TREE; |
13647 | while (true) |
13648 | { |
13649 | c_token *token = c_parser_peek_token (parser); |
13650 | if (token->type == CPP_KEYWORD |
13651 | && (token->keyword == RID_IN |
13652 | || token->keyword == RID_OUT |
13653 | || token->keyword == RID_INOUT |
13654 | || token->keyword == RID_BYCOPY |
13655 | || token->keyword == RID_BYREF |
13656 | || token->keyword == RID_ONEWAY)) |
13657 | { |
13658 | quals = chainon (build_tree_list (NULL_TREE, token->value), quals); |
13659 | c_parser_consume_token (parser); |
13660 | } |
13661 | else |
13662 | break; |
13663 | } |
13664 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_type)) |
13665 | type_name = c_parser_type_name (parser); |
13666 | if (type_name) |
13667 | type = groktypename (type_name, NULL, NULL); |
13668 | |
13669 | /* If the type is unknown, and error has already been produced and |
13670 | we need to recover from the error. In that case, use NULL_TREE |
13671 | for the type, as if no type had been specified; this will use the |
13672 | default type ('id') which is good for error recovery. */ |
13673 | if (type == error_mark_node) |
13674 | type = NULL_TREE; |
13675 | |
13676 | return build_tree_list (quals, type); |
13677 | } |
13678 | |
13679 | /* Parse objc-protocol-refs. |
13680 | |
13681 | objc-protocol-refs: |
13682 | < identifier-list > |
13683 | */ |
13684 | |
13685 | static tree |
13686 | c_parser_objc_protocol_refs (c_parser *parser) |
13687 | { |
13688 | tree list = NULL_TREE; |
13689 | gcc_assert (c_parser_next_token_is (parser, CPP_LESS)); |
13690 | c_parser_consume_token (parser); |
13691 | /* Any identifiers, including those declared as type names, are OK |
13692 | here. */ |
13693 | while (true) |
13694 | { |
13695 | tree id; |
13696 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
13697 | { |
13698 | c_parser_error (parser, gmsgid: "expected identifier" ); |
13699 | break; |
13700 | } |
13701 | id = c_parser_peek_token (parser)->value; |
13702 | list = chainon (list, build_tree_list (NULL_TREE, id)); |
13703 | c_parser_consume_token (parser); |
13704 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
13705 | c_parser_consume_token (parser); |
13706 | else |
13707 | break; |
13708 | } |
13709 | c_parser_require (parser, type: CPP_GREATER, msgid: "expected %<>%>" ); |
13710 | return list; |
13711 | } |
13712 | |
13713 | /* Parse an objc-try-catch-finally-statement. |
13714 | |
13715 | objc-try-catch-finally-statement: |
13716 | @try compound-statement objc-catch-list[opt] |
13717 | @try compound-statement objc-catch-list[opt] @finally compound-statement |
13718 | |
13719 | objc-catch-list: |
13720 | @catch ( objc-catch-parameter-declaration ) compound-statement |
13721 | objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement |
13722 | |
13723 | objc-catch-parameter-declaration: |
13724 | parameter-declaration |
13725 | '...' |
13726 | |
13727 | where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS. |
13728 | |
13729 | PS: This function is identical to cp_parser_objc_try_catch_finally_statement |
13730 | for C++. Keep them in sync. */ |
13731 | |
13732 | static void |
13733 | c_parser_objc_try_catch_finally_statement (c_parser *parser) |
13734 | { |
13735 | location_t location; |
13736 | tree stmt; |
13737 | |
13738 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY)); |
13739 | c_parser_consume_token (parser); |
13740 | location = c_parser_peek_token (parser)->location; |
13741 | objc_maybe_warn_exceptions (location); |
13742 | stmt = c_parser_compound_statement (parser); |
13743 | objc_begin_try_stmt (location, stmt); |
13744 | |
13745 | while (c_parser_next_token_is_keyword (parser, keyword: RID_AT_CATCH)) |
13746 | { |
13747 | struct c_parm *parm; |
13748 | tree parameter_declaration = error_mark_node; |
13749 | bool seen_open_paren = false; |
13750 | |
13751 | c_parser_consume_token (parser); |
13752 | matching_parens parens; |
13753 | if (!parens.require_open (parser)) |
13754 | seen_open_paren = true; |
13755 | if (c_parser_next_token_is (parser, type: CPP_ELLIPSIS)) |
13756 | { |
13757 | /* We have "@catch (...)" (where the '...' are literally |
13758 | what is in the code). Skip the '...'. |
13759 | parameter_declaration is set to NULL_TREE, and |
13760 | objc_being_catch_clauses() knows that that means |
13761 | '...'. */ |
13762 | c_parser_consume_token (parser); |
13763 | parameter_declaration = NULL_TREE; |
13764 | } |
13765 | else |
13766 | { |
13767 | /* We have "@catch (NSException *exception)" or something |
13768 | like that. Parse the parameter declaration. */ |
13769 | parm = c_parser_parameter_declaration (parser, NULL_TREE, have_gnu_attrs: false); |
13770 | if (parm == NULL) |
13771 | parameter_declaration = error_mark_node; |
13772 | else |
13773 | parameter_declaration = grokparm (parm, NULL); |
13774 | } |
13775 | if (seen_open_paren) |
13776 | parens.require_close (parser); |
13777 | else |
13778 | { |
13779 | /* If there was no open parenthesis, we are recovering from |
13780 | an error, and we are trying to figure out what mistake |
13781 | the user has made. */ |
13782 | |
13783 | /* If there is an immediate closing parenthesis, the user |
13784 | probably forgot the opening one (ie, they typed "@catch |
13785 | NSException *e)". Parse the closing parenthesis and keep |
13786 | going. */ |
13787 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
13788 | c_parser_consume_token (parser); |
13789 | |
13790 | /* If these is no immediate closing parenthesis, the user |
13791 | probably doesn't know that parenthesis are required at |
13792 | all (ie, they typed "@catch NSException *e"). So, just |
13793 | forget about the closing parenthesis and keep going. */ |
13794 | } |
13795 | objc_begin_catch_clause (parameter_declaration); |
13796 | if (c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
13797 | c_parser_compound_statement_nostart (parser); |
13798 | objc_finish_catch_clause (); |
13799 | } |
13800 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AT_FINALLY)) |
13801 | { |
13802 | c_parser_consume_token (parser); |
13803 | location = c_parser_peek_token (parser)->location; |
13804 | stmt = c_parser_compound_statement (parser); |
13805 | objc_build_finally_clause (location, stmt); |
13806 | } |
13807 | objc_finish_try_stmt (); |
13808 | } |
13809 | |
13810 | /* Parse an objc-synchronized-statement. |
13811 | |
13812 | objc-synchronized-statement: |
13813 | @synchronized ( expression ) compound-statement |
13814 | */ |
13815 | |
13816 | static void |
13817 | c_parser_objc_synchronized_statement (c_parser *parser) |
13818 | { |
13819 | location_t loc; |
13820 | tree expr, stmt; |
13821 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED)); |
13822 | c_parser_consume_token (parser); |
13823 | loc = c_parser_peek_token (parser)->location; |
13824 | objc_maybe_warn_exceptions (loc); |
13825 | matching_parens parens; |
13826 | if (parens.require_open (parser)) |
13827 | { |
13828 | struct c_expr ce = c_parser_expression (parser); |
13829 | ce = convert_lvalue_to_rvalue (loc, ce, false, false); |
13830 | expr = ce.value; |
13831 | expr = c_fully_fold (expr, false, NULL); |
13832 | parens.skip_until_found_close (parser); |
13833 | } |
13834 | else |
13835 | expr = error_mark_node; |
13836 | stmt = c_parser_compound_statement (parser); |
13837 | objc_build_synchronized (loc, expr, stmt); |
13838 | } |
13839 | |
13840 | /* Parse an objc-selector; return NULL_TREE without an error if the |
13841 | next token is not an objc-selector. |
13842 | |
13843 | objc-selector: |
13844 | identifier |
13845 | one of |
13846 | enum struct union if else while do for switch case default |
13847 | break continue return goto asm sizeof typeof typeof_unqual __alignof |
13848 | unsigned long const short volatile signed restrict _Complex |
13849 | in out inout bycopy byref oneway int char float double void _Bool |
13850 | _Atomic |
13851 | |
13852 | ??? Why this selection of keywords but not, for example, storage |
13853 | class specifiers? */ |
13854 | |
13855 | static tree |
13856 | c_parser_objc_selector (c_parser *parser) |
13857 | { |
13858 | c_token *token = c_parser_peek_token (parser); |
13859 | tree value = token->value; |
13860 | if (token->type == CPP_NAME) |
13861 | { |
13862 | c_parser_consume_token (parser); |
13863 | return value; |
13864 | } |
13865 | if (token->type != CPP_KEYWORD) |
13866 | return NULL_TREE; |
13867 | switch (token->keyword) |
13868 | { |
13869 | case RID_ENUM: |
13870 | case RID_STRUCT: |
13871 | case RID_UNION: |
13872 | case RID_IF: |
13873 | case RID_ELSE: |
13874 | case RID_WHILE: |
13875 | case RID_DO: |
13876 | case RID_FOR: |
13877 | case RID_SWITCH: |
13878 | case RID_CASE: |
13879 | case RID_DEFAULT: |
13880 | case RID_BREAK: |
13881 | case RID_CONTINUE: |
13882 | case RID_RETURN: |
13883 | case RID_GOTO: |
13884 | case RID_ASM: |
13885 | case RID_SIZEOF: |
13886 | case RID_TYPEOF: |
13887 | case RID_TYPEOF_UNQUAL: |
13888 | case RID_ALIGNOF: |
13889 | case RID_UNSIGNED: |
13890 | case RID_LONG: |
13891 | case RID_CONST: |
13892 | case RID_SHORT: |
13893 | case RID_VOLATILE: |
13894 | case RID_SIGNED: |
13895 | case RID_RESTRICT: |
13896 | case RID_COMPLEX: |
13897 | case RID_IN: |
13898 | case RID_OUT: |
13899 | case RID_INOUT: |
13900 | case RID_BYCOPY: |
13901 | case RID_BYREF: |
13902 | case RID_ONEWAY: |
13903 | case RID_INT: |
13904 | case RID_CHAR: |
13905 | case RID_FLOAT: |
13906 | case RID_DOUBLE: |
13907 | CASE_RID_FLOATN_NX: |
13908 | case RID_VOID: |
13909 | case RID_BOOL: |
13910 | case RID_ATOMIC: |
13911 | case RID_AUTO_TYPE: |
13912 | case RID_INT_N_0: |
13913 | case RID_INT_N_1: |
13914 | case RID_INT_N_2: |
13915 | case RID_INT_N_3: |
13916 | c_parser_consume_token (parser); |
13917 | return value; |
13918 | default: |
13919 | return NULL_TREE; |
13920 | } |
13921 | } |
13922 | |
13923 | /* Parse an objc-selector-arg. |
13924 | |
13925 | objc-selector-arg: |
13926 | objc-selector |
13927 | objc-keywordname-list |
13928 | |
13929 | objc-keywordname-list: |
13930 | objc-keywordname |
13931 | objc-keywordname-list objc-keywordname |
13932 | |
13933 | objc-keywordname: |
13934 | objc-selector : |
13935 | : |
13936 | */ |
13937 | |
13938 | static tree |
13939 | c_parser_objc_selector_arg (c_parser *parser) |
13940 | { |
13941 | tree sel = c_parser_objc_selector (parser); |
13942 | tree list = NULL_TREE; |
13943 | if (sel |
13944 | && c_parser_next_token_is_not (parser, type: CPP_COLON) |
13945 | && c_parser_next_token_is_not (parser, type: CPP_SCOPE)) |
13946 | return sel; |
13947 | while (true) |
13948 | { |
13949 | if (c_parser_next_token_is (parser, type: CPP_SCOPE)) |
13950 | { |
13951 | c_parser_consume_token (parser); |
13952 | list = chainon (list, build_tree_list (sel, NULL_TREE)); |
13953 | list = chainon (list, build_tree_list (NULL_TREE, NULL_TREE)); |
13954 | } |
13955 | else |
13956 | { |
13957 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
13958 | return list; |
13959 | list = chainon (list, build_tree_list (sel, NULL_TREE)); |
13960 | } |
13961 | sel = c_parser_objc_selector (parser); |
13962 | if (!sel |
13963 | && c_parser_next_token_is_not (parser, type: CPP_COLON) |
13964 | && c_parser_next_token_is_not (parser, type: CPP_SCOPE)) |
13965 | break; |
13966 | } |
13967 | return list; |
13968 | } |
13969 | |
13970 | /* Parse an objc-receiver. |
13971 | |
13972 | objc-receiver: |
13973 | expression |
13974 | class-name |
13975 | type-name |
13976 | */ |
13977 | |
13978 | static tree |
13979 | c_parser_objc_receiver (c_parser *parser) |
13980 | { |
13981 | location_t loc = c_parser_peek_token (parser)->location; |
13982 | |
13983 | if (c_parser_peek_token (parser)->type == CPP_NAME |
13984 | && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME |
13985 | || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)) |
13986 | { |
13987 | tree id = c_parser_peek_token (parser)->value; |
13988 | c_parser_consume_token (parser); |
13989 | return objc_get_class_reference (id); |
13990 | } |
13991 | struct c_expr ce = c_parser_expression (parser); |
13992 | ce = convert_lvalue_to_rvalue (loc, ce, false, false); |
13993 | return c_fully_fold (ce.value, false, NULL); |
13994 | } |
13995 | |
13996 | /* Parse objc-message-args. |
13997 | |
13998 | objc-message-args: |
13999 | objc-selector |
14000 | objc-keywordarg-list |
14001 | |
14002 | objc-keywordarg-list: |
14003 | objc-keywordarg |
14004 | objc-keywordarg-list objc-keywordarg |
14005 | |
14006 | objc-keywordarg: |
14007 | objc-selector : objc-keywordexpr |
14008 | : objc-keywordexpr |
14009 | */ |
14010 | |
14011 | static tree |
14012 | c_parser_objc_message_args (c_parser *parser) |
14013 | { |
14014 | tree sel = c_parser_objc_selector (parser); |
14015 | tree list = NULL_TREE; |
14016 | if (sel && c_parser_next_token_is_not (parser, type: CPP_COLON)) |
14017 | return sel; |
14018 | while (true) |
14019 | { |
14020 | tree keywordexpr; |
14021 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
14022 | return error_mark_node; |
14023 | keywordexpr = c_parser_objc_keywordexpr (parser); |
14024 | list = chainon (list, build_tree_list (sel, keywordexpr)); |
14025 | sel = c_parser_objc_selector (parser); |
14026 | if (!sel && c_parser_next_token_is_not (parser, type: CPP_COLON)) |
14027 | break; |
14028 | } |
14029 | return list; |
14030 | } |
14031 | |
14032 | /* Parse an objc-keywordexpr. |
14033 | |
14034 | objc-keywordexpr: |
14035 | nonempty-expr-list |
14036 | */ |
14037 | |
14038 | static tree |
14039 | c_parser_objc_keywordexpr (c_parser *parser) |
14040 | { |
14041 | tree ret; |
14042 | vec<tree, va_gc> *expr_list = c_parser_expr_list (parser, convert_p: true, fold_p: true, |
14043 | NULL, NULL, NULL, NULL); |
14044 | if (vec_safe_length (v: expr_list) == 1) |
14045 | { |
14046 | /* Just return the expression, remove a level of |
14047 | indirection. */ |
14048 | ret = (*expr_list)[0]; |
14049 | } |
14050 | else |
14051 | { |
14052 | /* We have a comma expression, we will collapse later. */ |
14053 | ret = build_tree_list_vec (expr_list); |
14054 | } |
14055 | release_tree_vector (expr_list); |
14056 | return ret; |
14057 | } |
14058 | |
14059 | /* A check, needed in several places, that ObjC interface, implementation or |
14060 | method definitions are not prefixed by incorrect items. */ |
14061 | static bool |
14062 | c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, |
14063 | struct c_declspecs *specs) |
14064 | { |
14065 | if (!specs->declspecs_seen_p || specs->non_sc_seen_p |
14066 | || specs->typespec_kind != ctsk_none) |
14067 | { |
14068 | c_parser_error (parser, |
14069 | gmsgid: "no type or storage class may be specified here," ); |
14070 | c_parser_skip_to_end_of_block_or_statement (parser); |
14071 | return true; |
14072 | } |
14073 | return false; |
14074 | } |
14075 | |
14076 | /* Parse an Objective-C @property declaration. The syntax is: |
14077 | |
14078 | objc-property-declaration: |
14079 | '@property' objc-property-attributes[opt] struct-declaration ; |
14080 | |
14081 | objc-property-attributes: |
14082 | '(' objc-property-attribute-list ')' |
14083 | |
14084 | objc-property-attribute-list: |
14085 | objc-property-attribute |
14086 | objc-property-attribute-list, objc-property-attribute |
14087 | |
14088 | objc-property-attribute |
14089 | 'getter' = identifier |
14090 | 'setter' = identifier |
14091 | 'readonly' |
14092 | 'readwrite' |
14093 | 'assign' |
14094 | 'retain' |
14095 | 'copy' |
14096 | 'nonatomic' |
14097 | |
14098 | For example: |
14099 | @property NSString *name; |
14100 | @property (readonly) id object; |
14101 | @property (retain, nonatomic, getter=getTheName) id name; |
14102 | @property int a, b, c; |
14103 | |
14104 | PS: This function is identical to cp_parser_objc_at_propery_declaration |
14105 | for C++. Keep them in sync. */ |
14106 | static void |
14107 | c_parser_objc_at_property_declaration (c_parser *parser) |
14108 | { |
14109 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY)); |
14110 | location_t loc = c_parser_peek_token (parser)->location; |
14111 | c_parser_consume_token (parser); /* Eat '@property'. */ |
14112 | |
14113 | /* Parse the optional attribute list. |
14114 | |
14115 | A list of parsed, but not verified, attributes. */ |
14116 | vec<property_attribute_info *> prop_attr_list = vNULL; |
14117 | |
14118 | bool syntax_error = false; |
14119 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
14120 | { |
14121 | matching_parens parens; |
14122 | |
14123 | location_t attr_start = c_parser_peek_token (parser)->location; |
14124 | /* Eat the '(' */ |
14125 | parens.consume_open (parser); |
14126 | |
14127 | /* Property attribute keywords are valid now. */ |
14128 | parser->objc_property_attr_context = true; |
14129 | |
14130 | /* Allow @property (), with a warning. */ |
14131 | location_t attr_end = c_parser_peek_token (parser)->location; |
14132 | |
14133 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
14134 | { |
14135 | location_t attr_comb = make_location (caret: attr_end, start: attr_start, finish: attr_end); |
14136 | warning_at (attr_comb, OPT_Wattributes, |
14137 | "empty property attribute list" ); |
14138 | } |
14139 | else |
14140 | while (true) |
14141 | { |
14142 | c_token *token = c_parser_peek_token (parser); |
14143 | attr_start = token->location; |
14144 | attr_end = get_finish (loc: token->location); |
14145 | location_t attr_comb = make_location (caret: attr_start, start: attr_start, |
14146 | finish: attr_end); |
14147 | |
14148 | if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA) |
14149 | { |
14150 | warning_at (attr_comb, OPT_Wattributes, |
14151 | "missing property attribute" ); |
14152 | if (token->type == CPP_CLOSE_PAREN) |
14153 | break; |
14154 | c_parser_consume_token (parser); |
14155 | continue; |
14156 | } |
14157 | |
14158 | tree attr_name = NULL_TREE; |
14159 | enum rid keyword = RID_MAX; /* Not a valid property attribute. */ |
14160 | bool add_at = false; |
14161 | if (token->type == CPP_KEYWORD) |
14162 | { |
14163 | keyword = token->keyword; |
14164 | if (OBJC_IS_AT_KEYWORD (keyword)) |
14165 | { |
14166 | /* For '@' keywords the token value has the keyword, |
14167 | prepend the '@' for diagnostics. */ |
14168 | attr_name = token->value; |
14169 | add_at = true; |
14170 | } |
14171 | else |
14172 | attr_name = ridpointers[(int)keyword]; |
14173 | } |
14174 | else if (token->type == CPP_NAME) |
14175 | attr_name = token->value; |
14176 | c_parser_consume_token (parser); |
14177 | |
14178 | enum objc_property_attribute_kind prop_kind |
14179 | = objc_prop_attr_kind_for_rid (keyword); |
14180 | property_attribute_info *prop |
14181 | = new property_attribute_info (attr_name, attr_comb, prop_kind); |
14182 | prop_attr_list.safe_push (obj: prop); |
14183 | |
14184 | tree meth_name; |
14185 | switch (prop->prop_kind) |
14186 | { |
14187 | default: break; |
14188 | case OBJC_PROPERTY_ATTR_UNKNOWN: |
14189 | if (attr_name) |
14190 | error_at (attr_comb, "unknown property attribute %<%s%s%>" , |
14191 | add_at ? "@" : "" , IDENTIFIER_POINTER (attr_name)); |
14192 | else |
14193 | error_at (attr_comb, "unknown property attribute" ); |
14194 | prop->parse_error = syntax_error = true; |
14195 | break; |
14196 | |
14197 | case OBJC_PROPERTY_ATTR_GETTER: |
14198 | case OBJC_PROPERTY_ATTR_SETTER: |
14199 | if (c_parser_next_token_is_not (parser, type: CPP_EQ)) |
14200 | { |
14201 | attr_comb = make_location (caret: attr_end, start: attr_start, finish: attr_end); |
14202 | error_at (attr_comb, "expected %<=%> after Objective-C %qE" , |
14203 | attr_name); |
14204 | prop->parse_error = syntax_error = true; |
14205 | break; |
14206 | } |
14207 | token = c_parser_peek_token (parser); |
14208 | attr_end = token->location; |
14209 | c_parser_consume_token (parser); /* eat the = */ |
14210 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
14211 | { |
14212 | attr_comb = make_location (caret: attr_end, start: attr_start, finish: attr_end); |
14213 | error_at (attr_comb, "expected %qE selector name" , |
14214 | attr_name); |
14215 | prop->parse_error = syntax_error = true; |
14216 | break; |
14217 | } |
14218 | /* Get the end of the method name, and consume the name. */ |
14219 | token = c_parser_peek_token (parser); |
14220 | attr_end = get_finish (loc: token->location); |
14221 | meth_name = token->value; |
14222 | c_parser_consume_token (parser); |
14223 | if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER) |
14224 | { |
14225 | if (c_parser_next_token_is_not (parser, type: CPP_COLON)) |
14226 | { |
14227 | attr_comb = make_location (caret: attr_end, start: attr_start, |
14228 | finish: attr_end); |
14229 | error_at (attr_comb, "setter method names must" |
14230 | " terminate with %<:%>" ); |
14231 | prop->parse_error = syntax_error = true; |
14232 | } |
14233 | else |
14234 | { |
14235 | attr_end = get_finish (loc: c_parser_peek_token |
14236 | (parser)->location); |
14237 | c_parser_consume_token (parser); |
14238 | } |
14239 | attr_comb = make_location (caret: attr_start, start: attr_start, |
14240 | finish: attr_end); |
14241 | } |
14242 | else |
14243 | attr_comb = make_location (caret: attr_start, start: attr_start, |
14244 | finish: attr_end); |
14245 | prop->ident = meth_name; |
14246 | /* Updated location including all that was successfully |
14247 | parsed. */ |
14248 | prop->prop_loc = attr_comb; |
14249 | break; |
14250 | } |
14251 | |
14252 | /* If we see a comma here, then keep going - even if we already |
14253 | saw a syntax error. For simple mistakes e.g. (asign, getter=x) |
14254 | this makes a more useful output and avoid spurious warnings about |
14255 | missing attributes that are, in fact, specified after the one with |
14256 | the syntax error. */ |
14257 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
14258 | c_parser_consume_token (parser); |
14259 | else |
14260 | break; |
14261 | } |
14262 | parser->objc_property_attr_context = false; |
14263 | |
14264 | if (syntax_error && c_parser_next_token_is_not (parser, type: CPP_CLOSE_PAREN)) |
14265 | /* We don't really want to chew the whole of the file looking for a |
14266 | matching closing parenthesis, so we will try to read the decl and |
14267 | let the error handling for that close out the statement. */ |
14268 | ; |
14269 | else |
14270 | syntax_error = false, parens.skip_until_found_close (parser); |
14271 | } |
14272 | |
14273 | /* 'properties' is the list of properties that we read. Usually a |
14274 | single one, but maybe more (eg, in "@property int a, b, c;" there |
14275 | are three). */ |
14276 | tree properties = c_parser_struct_declaration (parser, NULL); |
14277 | |
14278 | if (properties == error_mark_node) |
14279 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
14280 | else |
14281 | { |
14282 | if (properties == NULL_TREE) |
14283 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14284 | else |
14285 | { |
14286 | /* Comma-separated properties are chained together in reverse order; |
14287 | add them one by one. */ |
14288 | properties = nreverse (properties); |
14289 | for (; properties; properties = TREE_CHAIN (properties)) |
14290 | objc_add_property_declaration (loc, copy_node (properties), |
14291 | prop_attr_list); |
14292 | } |
14293 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
14294 | } |
14295 | |
14296 | while (!prop_attr_list.is_empty()) |
14297 | delete prop_attr_list.pop (); |
14298 | prop_attr_list.release (); |
14299 | parser->error = false; |
14300 | } |
14301 | |
14302 | /* Parse an Objective-C @synthesize declaration. The syntax is: |
14303 | |
14304 | objc-synthesize-declaration: |
14305 | @synthesize objc-synthesize-identifier-list ; |
14306 | |
14307 | objc-synthesize-identifier-list: |
14308 | objc-synthesize-identifier |
14309 | objc-synthesize-identifier-list, objc-synthesize-identifier |
14310 | |
14311 | objc-synthesize-identifier |
14312 | identifier |
14313 | identifier = identifier |
14314 | |
14315 | For example: |
14316 | @synthesize MyProperty; |
14317 | @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty; |
14318 | |
14319 | PS: This function is identical to cp_parser_objc_at_synthesize_declaration |
14320 | for C++. Keep them in sync. |
14321 | */ |
14322 | static void |
14323 | c_parser_objc_at_synthesize_declaration (c_parser *parser) |
14324 | { |
14325 | tree list = NULL_TREE; |
14326 | location_t loc; |
14327 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE)); |
14328 | loc = c_parser_peek_token (parser)->location; |
14329 | |
14330 | c_parser_consume_token (parser); |
14331 | while (true) |
14332 | { |
14333 | tree property, ivar; |
14334 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
14335 | { |
14336 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14337 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
14338 | /* Once we find the semicolon, we can resume normal parsing. |
14339 | We have to reset parser->error manually because |
14340 | c_parser_skip_until_found() won't reset it for us if the |
14341 | next token is precisely a semicolon. */ |
14342 | parser->error = false; |
14343 | return; |
14344 | } |
14345 | property = c_parser_peek_token (parser)->value; |
14346 | c_parser_consume_token (parser); |
14347 | if (c_parser_next_token_is (parser, type: CPP_EQ)) |
14348 | { |
14349 | c_parser_consume_token (parser); |
14350 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
14351 | { |
14352 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14353 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
14354 | parser->error = false; |
14355 | return; |
14356 | } |
14357 | ivar = c_parser_peek_token (parser)->value; |
14358 | c_parser_consume_token (parser); |
14359 | } |
14360 | else |
14361 | ivar = NULL_TREE; |
14362 | list = chainon (list, build_tree_list (ivar, property)); |
14363 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
14364 | c_parser_consume_token (parser); |
14365 | else |
14366 | break; |
14367 | } |
14368 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
14369 | objc_add_synthesize_declaration (loc, list); |
14370 | } |
14371 | |
14372 | /* Parse an Objective-C @dynamic declaration. The syntax is: |
14373 | |
14374 | objc-dynamic-declaration: |
14375 | @dynamic identifier-list ; |
14376 | |
14377 | For example: |
14378 | @dynamic MyProperty; |
14379 | @dynamic MyProperty, AnotherProperty; |
14380 | |
14381 | PS: This function is identical to cp_parser_objc_at_dynamic_declaration |
14382 | for C++. Keep them in sync. |
14383 | */ |
14384 | static void |
14385 | c_parser_objc_at_dynamic_declaration (c_parser *parser) |
14386 | { |
14387 | tree list = NULL_TREE; |
14388 | location_t loc; |
14389 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC)); |
14390 | loc = c_parser_peek_token (parser)->location; |
14391 | |
14392 | c_parser_consume_token (parser); |
14393 | while (true) |
14394 | { |
14395 | tree property; |
14396 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
14397 | { |
14398 | c_parser_error (parser, gmsgid: "expected identifier" ); |
14399 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, NULL); |
14400 | parser->error = false; |
14401 | return; |
14402 | } |
14403 | property = c_parser_peek_token (parser)->value; |
14404 | list = chainon (list, build_tree_list (NULL_TREE, property)); |
14405 | c_parser_consume_token (parser); |
14406 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
14407 | c_parser_consume_token (parser); |
14408 | else |
14409 | break; |
14410 | } |
14411 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
14412 | objc_add_dynamic_declaration (loc, list); |
14413 | } |
14414 | |
14415 | |
14416 | /* Parse a pragma GCC ivdep. */ |
14417 | |
14418 | static bool |
14419 | c_parse_pragma_ivdep (c_parser *parser) |
14420 | { |
14421 | c_parser_consume_pragma (parser); |
14422 | c_parser_skip_to_pragma_eol (parser); |
14423 | return true; |
14424 | } |
14425 | |
14426 | /* Parse a pragma GCC novector. */ |
14427 | |
14428 | static bool |
14429 | c_parse_pragma_novector (c_parser *parser) |
14430 | { |
14431 | c_parser_consume_pragma (parser); |
14432 | c_parser_skip_to_pragma_eol (parser); |
14433 | return true; |
14434 | } |
14435 | |
14436 | /* Parse a pragma GCC unroll. */ |
14437 | |
14438 | static unsigned short |
14439 | c_parser_pragma_unroll (c_parser *parser) |
14440 | { |
14441 | unsigned short unroll; |
14442 | c_parser_consume_pragma (parser); |
14443 | location_t location = c_parser_peek_token (parser)->location; |
14444 | tree expr = c_parser_expr_no_commas (parser, NULL).value; |
14445 | mark_exp_read (expr); |
14446 | expr = c_fully_fold (expr, false, NULL); |
14447 | HOST_WIDE_INT lunroll = 0; |
14448 | if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) |
14449 | || TREE_CODE (expr) != INTEGER_CST |
14450 | || (lunroll = tree_to_shwi (expr)) < 0 |
14451 | || lunroll >= USHRT_MAX) |
14452 | { |
14453 | error_at (location, "%<#pragma GCC unroll%> requires an" |
14454 | " assignment-expression that evaluates to a non-negative" |
14455 | " integral constant less than %u" , USHRT_MAX); |
14456 | unroll = 0; |
14457 | } |
14458 | else |
14459 | { |
14460 | unroll = (unsigned short)lunroll; |
14461 | if (unroll == 0) |
14462 | unroll = 1; |
14463 | } |
14464 | |
14465 | c_parser_skip_to_pragma_eol (parser); |
14466 | return unroll; |
14467 | } |
14468 | |
14469 | /* Handle pragmas. Some OpenMP pragmas are associated with, and therefore |
14470 | should be considered, statements. ALLOW_STMT is true if we're within |
14471 | the context of a function and such pragmas are to be allowed. Returns |
14472 | true if we actually parsed such a pragma. */ |
14473 | |
14474 | static bool |
14475 | c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) |
14476 | { |
14477 | unsigned int id; |
14478 | const char *construct = NULL; |
14479 | |
14480 | input_location = c_parser_peek_token (parser)->location; |
14481 | id = c_parser_peek_token (parser)->pragma_kind; |
14482 | gcc_assert (id != PRAGMA_NONE); |
14483 | if (parser->omp_for_parse_state |
14484 | && parser->omp_for_parse_state->in_intervening_code |
14485 | && id >= PRAGMA_OMP__START_ |
14486 | && id <= PRAGMA_OMP__LAST_) |
14487 | { |
14488 | error_at (input_location, |
14489 | "intervening code must not contain OpenMP directives" ); |
14490 | parser->omp_for_parse_state->fail = true; |
14491 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14492 | return false; |
14493 | } |
14494 | |
14495 | switch (id) |
14496 | { |
14497 | case PRAGMA_OACC_DECLARE: |
14498 | c_parser_oacc_declare (parser); |
14499 | return false; |
14500 | |
14501 | case PRAGMA_OACC_ENTER_DATA: |
14502 | if (context != pragma_compound) |
14503 | { |
14504 | construct = "acc enter data" ; |
14505 | in_compound: |
14506 | if (context == pragma_stmt) |
14507 | { |
14508 | error_at (c_parser_peek_token (parser)->location, |
14509 | "%<#pragma %s%> may only be used in compound " |
14510 | "statements" , construct); |
14511 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14512 | return true; |
14513 | } |
14514 | goto bad_stmt; |
14515 | } |
14516 | c_parser_oacc_enter_exit_data (parser, true); |
14517 | return false; |
14518 | |
14519 | case PRAGMA_OACC_EXIT_DATA: |
14520 | if (context != pragma_compound) |
14521 | { |
14522 | construct = "acc exit data" ; |
14523 | goto in_compound; |
14524 | } |
14525 | c_parser_oacc_enter_exit_data (parser, false); |
14526 | return false; |
14527 | |
14528 | case PRAGMA_OACC_ROUTINE: |
14529 | if (context != pragma_external) |
14530 | { |
14531 | error_at (c_parser_peek_token (parser)->location, |
14532 | "%<#pragma acc routine%> must be at file scope" ); |
14533 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14534 | return false; |
14535 | } |
14536 | c_parser_oacc_routine (parser, context); |
14537 | return false; |
14538 | |
14539 | case PRAGMA_OACC_UPDATE: |
14540 | if (context != pragma_compound) |
14541 | { |
14542 | construct = "acc update" ; |
14543 | goto in_compound; |
14544 | } |
14545 | c_parser_oacc_update (parser); |
14546 | return false; |
14547 | |
14548 | case PRAGMA_OMP_BARRIER: |
14549 | if (context != pragma_compound) |
14550 | { |
14551 | construct = "omp barrier" ; |
14552 | goto in_compound; |
14553 | } |
14554 | c_parser_omp_barrier (parser); |
14555 | return false; |
14556 | |
14557 | case PRAGMA_OMP_DEPOBJ: |
14558 | if (context != pragma_compound) |
14559 | { |
14560 | construct = "omp depobj" ; |
14561 | goto in_compound; |
14562 | } |
14563 | c_parser_omp_depobj (parser); |
14564 | return false; |
14565 | |
14566 | case PRAGMA_OMP_FLUSH: |
14567 | if (context != pragma_compound) |
14568 | { |
14569 | construct = "omp flush" ; |
14570 | goto in_compound; |
14571 | } |
14572 | c_parser_omp_flush (parser); |
14573 | return false; |
14574 | |
14575 | case PRAGMA_OMP_TASKWAIT: |
14576 | if (context != pragma_compound) |
14577 | { |
14578 | construct = "omp taskwait" ; |
14579 | goto in_compound; |
14580 | } |
14581 | c_parser_omp_taskwait (parser); |
14582 | return false; |
14583 | |
14584 | case PRAGMA_OMP_TASKYIELD: |
14585 | if (context != pragma_compound) |
14586 | { |
14587 | construct = "omp taskyield" ; |
14588 | goto in_compound; |
14589 | } |
14590 | c_parser_omp_taskyield (parser); |
14591 | return false; |
14592 | |
14593 | case PRAGMA_OMP_CANCEL: |
14594 | if (context != pragma_compound) |
14595 | { |
14596 | construct = "omp cancel" ; |
14597 | goto in_compound; |
14598 | } |
14599 | c_parser_omp_cancel (parser); |
14600 | return false; |
14601 | |
14602 | case PRAGMA_OMP_CANCELLATION_POINT: |
14603 | return c_parser_omp_cancellation_point (parser, context); |
14604 | |
14605 | case PRAGMA_OMP_THREADPRIVATE: |
14606 | c_parser_omp_threadprivate (parser); |
14607 | return false; |
14608 | |
14609 | case PRAGMA_OMP_TARGET: |
14610 | return c_parser_omp_target (parser, context, if_p); |
14611 | |
14612 | case PRAGMA_OMP_BEGIN: |
14613 | c_parser_omp_begin (parser); |
14614 | return false; |
14615 | |
14616 | case PRAGMA_OMP_END: |
14617 | c_parser_omp_end (parser); |
14618 | return false; |
14619 | |
14620 | case PRAGMA_OMP_SCAN: |
14621 | error_at (c_parser_peek_token (parser)->location, |
14622 | "%<#pragma omp scan%> may only be used in " |
14623 | "a loop construct with %<inscan%> %<reduction%> clause" ); |
14624 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14625 | return false; |
14626 | |
14627 | case PRAGMA_OMP_SECTION: |
14628 | error_at (c_parser_peek_token (parser)->location, |
14629 | "%<#pragma omp section%> may only be used in " |
14630 | "%<#pragma omp sections%> construct" ); |
14631 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14632 | return false; |
14633 | |
14634 | case PRAGMA_OMP_DECLARE: |
14635 | return c_parser_omp_declare (parser, context); |
14636 | |
14637 | case PRAGMA_OMP_REQUIRES: |
14638 | if (context != pragma_external) |
14639 | { |
14640 | error_at (c_parser_peek_token (parser)->location, |
14641 | "%<#pragma %s%> may only be used at file scope" , |
14642 | "omp requires" ); |
14643 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14644 | return false; |
14645 | } |
14646 | c_parser_omp_requires (parser); |
14647 | return false; |
14648 | |
14649 | case PRAGMA_OMP_ALLOCATE: |
14650 | c_parser_omp_allocate (parser); |
14651 | return false; |
14652 | |
14653 | case PRAGMA_OMP_ASSUMES: |
14654 | if (context != pragma_external) |
14655 | { |
14656 | error_at (c_parser_peek_token (parser)->location, |
14657 | "%<#pragma %s%> may only be used at file scope" , |
14658 | "omp assumes" ); |
14659 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14660 | return false; |
14661 | } |
14662 | c_parser_omp_assumes (parser); |
14663 | return false; |
14664 | |
14665 | case PRAGMA_OMP_NOTHING: |
14666 | c_parser_omp_nothing (parser); |
14667 | return false; |
14668 | |
14669 | case PRAGMA_OMP_ERROR: |
14670 | return c_parser_omp_error (parser, context); |
14671 | |
14672 | case PRAGMA_OMP_ORDERED: |
14673 | return c_parser_omp_ordered (parser, context, if_p); |
14674 | |
14675 | case PRAGMA_NOVECTOR: |
14676 | case PRAGMA_UNROLL: |
14677 | case PRAGMA_IVDEP: |
14678 | { |
14679 | bool novector = false; |
14680 | unsigned short unroll = 0; |
14681 | bool ivdep = false; |
14682 | |
14683 | switch (id) |
14684 | { |
14685 | case PRAGMA_NOVECTOR: |
14686 | novector = c_parse_pragma_novector (parser); |
14687 | break; |
14688 | case PRAGMA_UNROLL: |
14689 | unroll = c_parser_pragma_unroll (parser); |
14690 | break; |
14691 | case PRAGMA_IVDEP: |
14692 | ivdep = c_parse_pragma_ivdep (parser); |
14693 | break; |
14694 | default: |
14695 | gcc_unreachable (); |
14696 | } |
14697 | |
14698 | c_token *tok = c_parser_peek_token (parser); |
14699 | bool has_more = tok->type == CPP_PRAGMA; |
14700 | while (has_more) |
14701 | { |
14702 | switch (tok->pragma_kind) |
14703 | { |
14704 | case PRAGMA_IVDEP: |
14705 | ivdep = c_parse_pragma_ivdep (parser); |
14706 | break; |
14707 | case PRAGMA_UNROLL: |
14708 | unroll = c_parser_pragma_unroll (parser); |
14709 | break; |
14710 | case PRAGMA_NOVECTOR: |
14711 | novector = c_parse_pragma_novector (parser); |
14712 | break; |
14713 | default: |
14714 | has_more = false; |
14715 | break; |
14716 | } |
14717 | tok = c_parser_peek_token (parser); |
14718 | has_more = has_more && tok->type == CPP_PRAGMA; |
14719 | } |
14720 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_FOR) |
14721 | && !c_parser_next_token_is_keyword (parser, keyword: RID_WHILE) |
14722 | && !c_parser_next_token_is_keyword (parser, keyword: RID_DO)) |
14723 | { |
14724 | c_parser_error (parser, gmsgid: "for, while or do statement expected" ); |
14725 | return false; |
14726 | } |
14727 | if (c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
14728 | c_parser_for_statement (parser, ivdep, unroll, novector, if_p); |
14729 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_WHILE)) |
14730 | c_parser_while_statement (parser, ivdep, unroll, novector, if_p); |
14731 | else |
14732 | c_parser_do_statement (parser, ivdep, unroll, novector); |
14733 | } |
14734 | return true; |
14735 | |
14736 | case PRAGMA_GCC_PCH_PREPROCESS: |
14737 | c_parser_error (parser, gmsgid: "%<#pragma GCC pch_preprocess%> must be first" ); |
14738 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14739 | return false; |
14740 | |
14741 | case PRAGMA_OACC_WAIT: |
14742 | if (context != pragma_compound) |
14743 | { |
14744 | construct = "acc wait" ; |
14745 | goto in_compound; |
14746 | } |
14747 | /* FALL THROUGH. */ |
14748 | |
14749 | default: |
14750 | if (id < PRAGMA_FIRST_EXTERNAL) |
14751 | { |
14752 | if (context != pragma_stmt && context != pragma_compound) |
14753 | { |
14754 | bad_stmt: |
14755 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
14756 | c_parser_skip_until_found (parser, type: CPP_PRAGMA_EOL, NULL); |
14757 | return false; |
14758 | } |
14759 | c_parser_omp_construct (parser, if_p); |
14760 | return true; |
14761 | } |
14762 | break; |
14763 | } |
14764 | |
14765 | c_parser_consume_pragma (parser); |
14766 | c_invoke_pragma_handler (id); |
14767 | |
14768 | /* Skip to EOL, but suppress any error message. Those will have been |
14769 | generated by the handler routine through calling error, as opposed |
14770 | to calling c_parser_error. */ |
14771 | parser->error = true; |
14772 | c_parser_skip_to_pragma_eol (parser); |
14773 | |
14774 | return false; |
14775 | } |
14776 | |
14777 | /* The interface the pragma parsers have to the lexer. */ |
14778 | |
14779 | enum cpp_ttype |
14780 | pragma_lex (tree *value, location_t *loc) |
14781 | { |
14782 | c_token *tok = c_parser_peek_token (parser: the_parser); |
14783 | enum cpp_ttype ret = tok->type; |
14784 | |
14785 | *value = tok->value; |
14786 | if (loc) |
14787 | *loc = tok->location; |
14788 | |
14789 | if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) |
14790 | ret = CPP_EOF; |
14791 | else if (ret == CPP_STRING) |
14792 | *value = c_parser_string_literal (parser: the_parser, translate: false, wide_ok: false).value; |
14793 | else |
14794 | { |
14795 | if (ret == CPP_KEYWORD) |
14796 | ret = CPP_NAME; |
14797 | c_parser_consume_token (parser: the_parser); |
14798 | } |
14799 | |
14800 | return ret; |
14801 | } |
14802 | |
14803 | void |
14804 | pragma_lex_discard_to_eol () |
14805 | { |
14806 | cpp_ttype type; |
14807 | do |
14808 | { |
14809 | type = c_parser_peek_token (parser: the_parser)->type; |
14810 | gcc_assert (type != CPP_EOF); |
14811 | c_parser_consume_token (parser: the_parser); |
14812 | } while (type != CPP_PRAGMA_EOL); |
14813 | } |
14814 | |
14815 | static void |
14816 | c_parser_pragma_pch_preprocess (c_parser *parser) |
14817 | { |
14818 | tree name = NULL; |
14819 | |
14820 | parser->lex_joined_string = true; |
14821 | c_parser_consume_pragma (parser); |
14822 | if (c_parser_next_token_is (parser, type: CPP_STRING)) |
14823 | { |
14824 | name = c_parser_peek_token (parser)->value; |
14825 | c_parser_consume_token (parser); |
14826 | } |
14827 | else |
14828 | c_parser_error (parser, gmsgid: "expected string literal" ); |
14829 | c_parser_skip_to_pragma_eol (parser); |
14830 | parser->lex_joined_string = false; |
14831 | |
14832 | if (name) |
14833 | c_common_pch_pragma (pfile: parse_in, TREE_STRING_POINTER (name)); |
14834 | } |
14835 | |
14836 | /* OpenACC and OpenMP parsing routines. */ |
14837 | |
14838 | /* Returns name of the next clause. |
14839 | If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and |
14840 | the token is not consumed. Otherwise appropriate pragma_omp_clause is |
14841 | returned and the token is consumed. */ |
14842 | |
14843 | static pragma_omp_clause |
14844 | c_parser_omp_clause_name (c_parser *parser) |
14845 | { |
14846 | pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; |
14847 | |
14848 | if (c_parser_next_token_is_keyword (parser, keyword: RID_AUTO)) |
14849 | result = PRAGMA_OACC_CLAUSE_AUTO; |
14850 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
14851 | result = PRAGMA_OMP_CLAUSE_IF; |
14852 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT)) |
14853 | result = PRAGMA_OMP_CLAUSE_DEFAULT; |
14854 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
14855 | result = PRAGMA_OMP_CLAUSE_FOR; |
14856 | else if (c_parser_next_token_is (parser, type: CPP_NAME)) |
14857 | { |
14858 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
14859 | |
14860 | switch (p[0]) |
14861 | { |
14862 | case 'a': |
14863 | if (!strcmp (s1: "affinity" , s2: p)) |
14864 | result = PRAGMA_OMP_CLAUSE_AFFINITY; |
14865 | else if (!strcmp (s1: "aligned" , s2: p)) |
14866 | result = PRAGMA_OMP_CLAUSE_ALIGNED; |
14867 | else if (!strcmp (s1: "allocate" , s2: p)) |
14868 | result = PRAGMA_OMP_CLAUSE_ALLOCATE; |
14869 | else if (!strcmp (s1: "async" , s2: p)) |
14870 | result = PRAGMA_OACC_CLAUSE_ASYNC; |
14871 | else if (!strcmp (s1: "attach" , s2: p)) |
14872 | result = PRAGMA_OACC_CLAUSE_ATTACH; |
14873 | break; |
14874 | case 'b': |
14875 | if (!strcmp (s1: "bind" , s2: p)) |
14876 | result = PRAGMA_OMP_CLAUSE_BIND; |
14877 | break; |
14878 | case 'c': |
14879 | if (!strcmp (s1: "collapse" , s2: p)) |
14880 | result = PRAGMA_OMP_CLAUSE_COLLAPSE; |
14881 | else if (!strcmp (s1: "copy" , s2: p)) |
14882 | result = PRAGMA_OACC_CLAUSE_COPY; |
14883 | else if (!strcmp (s1: "copyin" , s2: p)) |
14884 | result = PRAGMA_OMP_CLAUSE_COPYIN; |
14885 | else if (!strcmp (s1: "copyout" , s2: p)) |
14886 | result = PRAGMA_OACC_CLAUSE_COPYOUT; |
14887 | else if (!strcmp (s1: "copyprivate" , s2: p)) |
14888 | result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; |
14889 | else if (!strcmp (s1: "create" , s2: p)) |
14890 | result = PRAGMA_OACC_CLAUSE_CREATE; |
14891 | break; |
14892 | case 'd': |
14893 | if (!strcmp (s1: "defaultmap" , s2: p)) |
14894 | result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; |
14895 | else if (!strcmp (s1: "delete" , s2: p)) |
14896 | result = PRAGMA_OACC_CLAUSE_DELETE; |
14897 | else if (!strcmp (s1: "depend" , s2: p)) |
14898 | result = PRAGMA_OMP_CLAUSE_DEPEND; |
14899 | else if (!strcmp (s1: "detach" , s2: p)) |
14900 | result = PRAGMA_OACC_CLAUSE_DETACH; |
14901 | else if (!strcmp (s1: "device" , s2: p)) |
14902 | result = PRAGMA_OMP_CLAUSE_DEVICE; |
14903 | else if (!strcmp (s1: "deviceptr" , s2: p)) |
14904 | result = PRAGMA_OACC_CLAUSE_DEVICEPTR; |
14905 | else if (!strcmp (s1: "device_resident" , s2: p)) |
14906 | result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT; |
14907 | else if (!strcmp (s1: "device_type" , s2: p)) |
14908 | result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE; |
14909 | else if (!strcmp (s1: "dist_schedule" , s2: p)) |
14910 | result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; |
14911 | else if (!strcmp (s1: "doacross" , s2: p)) |
14912 | result = PRAGMA_OMP_CLAUSE_DOACROSS; |
14913 | break; |
14914 | case 'e': |
14915 | if (!strcmp (s1: "enter" , s2: p)) |
14916 | result = PRAGMA_OMP_CLAUSE_ENTER; |
14917 | break; |
14918 | case 'f': |
14919 | if (!strcmp (s1: "filter" , s2: p)) |
14920 | result = PRAGMA_OMP_CLAUSE_FILTER; |
14921 | else if (!strcmp (s1: "final" , s2: p)) |
14922 | result = PRAGMA_OMP_CLAUSE_FINAL; |
14923 | else if (!strcmp (s1: "finalize" , s2: p)) |
14924 | result = PRAGMA_OACC_CLAUSE_FINALIZE; |
14925 | else if (!strcmp (s1: "firstprivate" , s2: p)) |
14926 | result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; |
14927 | else if (!strcmp (s1: "from" , s2: p)) |
14928 | result = PRAGMA_OMP_CLAUSE_FROM; |
14929 | break; |
14930 | case 'g': |
14931 | if (!strcmp (s1: "gang" , s2: p)) |
14932 | result = PRAGMA_OACC_CLAUSE_GANG; |
14933 | else if (!strcmp (s1: "grainsize" , s2: p)) |
14934 | result = PRAGMA_OMP_CLAUSE_GRAINSIZE; |
14935 | break; |
14936 | case 'h': |
14937 | if (!strcmp (s1: "has_device_addr" , s2: p)) |
14938 | result = PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR; |
14939 | else if (!strcmp (s1: "hint" , s2: p)) |
14940 | result = PRAGMA_OMP_CLAUSE_HINT; |
14941 | else if (!strcmp (s1: "host" , s2: p)) |
14942 | result = PRAGMA_OACC_CLAUSE_HOST; |
14943 | break; |
14944 | case 'i': |
14945 | if (!strcmp (s1: "if_present" , s2: p)) |
14946 | result = PRAGMA_OACC_CLAUSE_IF_PRESENT; |
14947 | else if (!strcmp (s1: "in_reduction" , s2: p)) |
14948 | result = PRAGMA_OMP_CLAUSE_IN_REDUCTION; |
14949 | else if (!strcmp (s1: "inbranch" , s2: p)) |
14950 | result = PRAGMA_OMP_CLAUSE_INBRANCH; |
14951 | else if (!strcmp (s1: "independent" , s2: p)) |
14952 | result = PRAGMA_OACC_CLAUSE_INDEPENDENT; |
14953 | else if (!strcmp (s1: "indirect" , s2: p)) |
14954 | result = PRAGMA_OMP_CLAUSE_INDIRECT; |
14955 | else if (!strcmp (s1: "is_device_ptr" , s2: p)) |
14956 | result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR; |
14957 | break; |
14958 | case 'l': |
14959 | if (!strcmp (s1: "lastprivate" , s2: p)) |
14960 | result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; |
14961 | else if (!strcmp (s1: "linear" , s2: p)) |
14962 | result = PRAGMA_OMP_CLAUSE_LINEAR; |
14963 | else if (!strcmp (s1: "link" , s2: p)) |
14964 | result = PRAGMA_OMP_CLAUSE_LINK; |
14965 | break; |
14966 | case 'm': |
14967 | if (!strcmp (s1: "map" , s2: p)) |
14968 | result = PRAGMA_OMP_CLAUSE_MAP; |
14969 | else if (!strcmp (s1: "mergeable" , s2: p)) |
14970 | result = PRAGMA_OMP_CLAUSE_MERGEABLE; |
14971 | break; |
14972 | case 'n': |
14973 | if (!strcmp (s1: "no_create" , s2: p)) |
14974 | result = PRAGMA_OACC_CLAUSE_NO_CREATE; |
14975 | else if (!strcmp (s1: "nogroup" , s2: p)) |
14976 | result = PRAGMA_OMP_CLAUSE_NOGROUP; |
14977 | else if (!strcmp (s1: "nohost" , s2: p)) |
14978 | result = PRAGMA_OACC_CLAUSE_NOHOST; |
14979 | else if (!strcmp (s1: "nontemporal" , s2: p)) |
14980 | result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; |
14981 | else if (!strcmp (s1: "notinbranch" , s2: p)) |
14982 | result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; |
14983 | else if (!strcmp (s1: "nowait" , s2: p)) |
14984 | result = PRAGMA_OMP_CLAUSE_NOWAIT; |
14985 | else if (!strcmp (s1: "num_gangs" , s2: p)) |
14986 | result = PRAGMA_OACC_CLAUSE_NUM_GANGS; |
14987 | else if (!strcmp (s1: "num_tasks" , s2: p)) |
14988 | result = PRAGMA_OMP_CLAUSE_NUM_TASKS; |
14989 | else if (!strcmp (s1: "num_teams" , s2: p)) |
14990 | result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; |
14991 | else if (!strcmp (s1: "num_threads" , s2: p)) |
14992 | result = PRAGMA_OMP_CLAUSE_NUM_THREADS; |
14993 | else if (!strcmp (s1: "num_workers" , s2: p)) |
14994 | result = PRAGMA_OACC_CLAUSE_NUM_WORKERS; |
14995 | break; |
14996 | case 'o': |
14997 | if (!strcmp (s1: "ordered" , s2: p)) |
14998 | result = PRAGMA_OMP_CLAUSE_ORDERED; |
14999 | else if (!strcmp (s1: "order" , s2: p)) |
15000 | result = PRAGMA_OMP_CLAUSE_ORDER; |
15001 | break; |
15002 | case 'p': |
15003 | if (!strcmp (s1: "parallel" , s2: p)) |
15004 | result = PRAGMA_OMP_CLAUSE_PARALLEL; |
15005 | else if (!strcmp (s1: "present" , s2: p)) |
15006 | result = PRAGMA_OACC_CLAUSE_PRESENT; |
15007 | /* As of OpenACC 2.5, these are now aliases of the non-present_or |
15008 | clauses. */ |
15009 | else if (!strcmp (s1: "present_or_copy" , s2: p) |
15010 | || !strcmp (s1: "pcopy" , s2: p)) |
15011 | result = PRAGMA_OACC_CLAUSE_COPY; |
15012 | else if (!strcmp (s1: "present_or_copyin" , s2: p) |
15013 | || !strcmp (s1: "pcopyin" , s2: p)) |
15014 | result = PRAGMA_OACC_CLAUSE_COPYIN; |
15015 | else if (!strcmp (s1: "present_or_copyout" , s2: p) |
15016 | || !strcmp (s1: "pcopyout" , s2: p)) |
15017 | result = PRAGMA_OACC_CLAUSE_COPYOUT; |
15018 | else if (!strcmp (s1: "present_or_create" , s2: p) |
15019 | || !strcmp (s1: "pcreate" , s2: p)) |
15020 | result = PRAGMA_OACC_CLAUSE_CREATE; |
15021 | else if (!strcmp (s1: "priority" , s2: p)) |
15022 | result = PRAGMA_OMP_CLAUSE_PRIORITY; |
15023 | else if (!strcmp (s1: "private" , s2: p)) |
15024 | result = PRAGMA_OMP_CLAUSE_PRIVATE; |
15025 | else if (!strcmp (s1: "proc_bind" , s2: p)) |
15026 | result = PRAGMA_OMP_CLAUSE_PROC_BIND; |
15027 | break; |
15028 | case 'r': |
15029 | if (!strcmp (s1: "reduction" , s2: p)) |
15030 | result = PRAGMA_OMP_CLAUSE_REDUCTION; |
15031 | break; |
15032 | case 's': |
15033 | if (!strcmp (s1: "safelen" , s2: p)) |
15034 | result = PRAGMA_OMP_CLAUSE_SAFELEN; |
15035 | else if (!strcmp (s1: "schedule" , s2: p)) |
15036 | result = PRAGMA_OMP_CLAUSE_SCHEDULE; |
15037 | else if (!strcmp (s1: "sections" , s2: p)) |
15038 | result = PRAGMA_OMP_CLAUSE_SECTIONS; |
15039 | else if (!strcmp (s1: "self" , s2: p)) |
15040 | result = PRAGMA_OACC_CLAUSE_SELF; |
15041 | else if (!strcmp (s1: "seq" , s2: p)) |
15042 | result = PRAGMA_OACC_CLAUSE_SEQ; |
15043 | else if (!strcmp (s1: "shared" , s2: p)) |
15044 | result = PRAGMA_OMP_CLAUSE_SHARED; |
15045 | else if (!strcmp (s1: "simd" , s2: p)) |
15046 | result = PRAGMA_OMP_CLAUSE_SIMD; |
15047 | else if (!strcmp (s1: "simdlen" , s2: p)) |
15048 | result = PRAGMA_OMP_CLAUSE_SIMDLEN; |
15049 | break; |
15050 | case 't': |
15051 | if (!strcmp (s1: "task_reduction" , s2: p)) |
15052 | result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION; |
15053 | else if (!strcmp (s1: "taskgroup" , s2: p)) |
15054 | result = PRAGMA_OMP_CLAUSE_TASKGROUP; |
15055 | else if (!strcmp (s1: "thread_limit" , s2: p)) |
15056 | result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT; |
15057 | else if (!strcmp (s1: "threads" , s2: p)) |
15058 | result = PRAGMA_OMP_CLAUSE_THREADS; |
15059 | else if (!strcmp (s1: "tile" , s2: p)) |
15060 | result = PRAGMA_OACC_CLAUSE_TILE; |
15061 | else if (!strcmp (s1: "to" , s2: p)) |
15062 | result = PRAGMA_OMP_CLAUSE_TO; |
15063 | break; |
15064 | case 'u': |
15065 | if (!strcmp (s1: "uniform" , s2: p)) |
15066 | result = PRAGMA_OMP_CLAUSE_UNIFORM; |
15067 | else if (!strcmp (s1: "untied" , s2: p)) |
15068 | result = PRAGMA_OMP_CLAUSE_UNTIED; |
15069 | else if (!strcmp (s1: "use_device" , s2: p)) |
15070 | result = PRAGMA_OACC_CLAUSE_USE_DEVICE; |
15071 | else if (!strcmp (s1: "use_device_addr" , s2: p)) |
15072 | result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR; |
15073 | else if (!strcmp (s1: "use_device_ptr" , s2: p)) |
15074 | result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR; |
15075 | break; |
15076 | case 'v': |
15077 | if (!strcmp (s1: "vector" , s2: p)) |
15078 | result = PRAGMA_OACC_CLAUSE_VECTOR; |
15079 | else if (!strcmp (s1: "vector_length" , s2: p)) |
15080 | result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH; |
15081 | break; |
15082 | case 'w': |
15083 | if (!strcmp (s1: "wait" , s2: p)) |
15084 | result = PRAGMA_OACC_CLAUSE_WAIT; |
15085 | else if (!strcmp (s1: "worker" , s2: p)) |
15086 | result = PRAGMA_OACC_CLAUSE_WORKER; |
15087 | break; |
15088 | } |
15089 | } |
15090 | |
15091 | if (result != PRAGMA_OMP_CLAUSE_NONE) |
15092 | c_parser_consume_token (parser); |
15093 | |
15094 | return result; |
15095 | } |
15096 | |
15097 | /* Validate that a clause of the given type does not already exist. */ |
15098 | |
15099 | static void |
15100 | check_no_duplicate_clause (tree clauses, enum omp_clause_code code, |
15101 | const char *name) |
15102 | { |
15103 | if (tree c = omp_find_clause (clauses, kind: code)) |
15104 | error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses" , name); |
15105 | } |
15106 | |
15107 | /* OpenACC 2.0 |
15108 | Parse wait clause or wait directive parameters. */ |
15109 | |
15110 | static tree |
15111 | c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) |
15112 | { |
15113 | vec<tree, va_gc> *args; |
15114 | tree t, args_tree; |
15115 | |
15116 | matching_parens parens; |
15117 | if (!parens.require_open (parser)) |
15118 | return list; |
15119 | |
15120 | args = c_parser_expr_list (parser, convert_p: false, fold_p: true, NULL, NULL, NULL, NULL); |
15121 | args_tree = build_tree_list_vec (args); |
15122 | |
15123 | for (t = args_tree; t; t = TREE_CHAIN (t)) |
15124 | { |
15125 | tree targ = TREE_VALUE (t); |
15126 | |
15127 | if (targ != error_mark_node) |
15128 | { |
15129 | if (!INTEGRAL_TYPE_P (TREE_TYPE (targ))) |
15130 | { |
15131 | c_parser_error (parser, gmsgid: "expression must be integral" ); |
15132 | targ = error_mark_node; |
15133 | } |
15134 | else |
15135 | { |
15136 | tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); |
15137 | |
15138 | OMP_CLAUSE_DECL (c) = targ; |
15139 | OMP_CLAUSE_CHAIN (c) = list; |
15140 | list = c; |
15141 | } |
15142 | } |
15143 | } |
15144 | |
15145 | release_tree_vector (args); |
15146 | parens.require_close (parser); |
15147 | return list; |
15148 | } |
15149 | |
15150 | /* OpenACC 2.0, OpenMP 2.5: |
15151 | variable-list: |
15152 | identifier |
15153 | variable-list , identifier |
15154 | |
15155 | If KIND is nonzero, create the appropriate node and install the |
15156 | decl in OMP_CLAUSE_DECL and add the node to the head of the list. |
15157 | If KIND is nonzero, CLAUSE_LOC is the location of the clause. |
15158 | |
15159 | If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; |
15160 | return the list created. |
15161 | |
15162 | The optional ALLOW_DEREF argument is true if list items can use the deref |
15163 | (->) operator. */ |
15164 | |
15165 | struct omp_dim |
15166 | { |
15167 | tree low_bound, length; |
15168 | location_t loc; |
15169 | bool no_colon; |
15170 | omp_dim (tree lb, tree len, location_t lo, bool nc) |
15171 | : low_bound (lb), length (len), loc (lo), no_colon (nc) {} |
15172 | }; |
15173 | |
15174 | static tree |
15175 | c_parser_omp_variable_list (c_parser *parser, |
15176 | location_t clause_loc, |
15177 | enum omp_clause_code kind, tree list, |
15178 | bool map_lvalue = false) |
15179 | { |
15180 | auto_vec<omp_dim> dims; |
15181 | bool array_section_p; |
15182 | auto_vec<c_token> tokens; |
15183 | unsigned int tokens_avail = 0; |
15184 | c_token *saved_tokens = NULL; |
15185 | bool first = true; |
15186 | |
15187 | while (1) |
15188 | { |
15189 | tree t = NULL_TREE; |
15190 | |
15191 | if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) |
15192 | { |
15193 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
15194 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
15195 | { |
15196 | struct c_expr expr; |
15197 | if (kind == OMP_CLAUSE_DEPEND |
15198 | && c_parser_next_token_is_keyword (parser, |
15199 | keyword: RID_OMP_ALL_MEMORY) |
15200 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
15201 | || (c_parser_peek_2nd_token (parser)->type |
15202 | == CPP_CLOSE_PAREN))) |
15203 | { |
15204 | expr.value = ridpointers[RID_OMP_ALL_MEMORY]; |
15205 | c_parser_consume_token (parser); |
15206 | } |
15207 | else |
15208 | expr = c_parser_expr_no_commas (parser, NULL); |
15209 | if (expr.value != error_mark_node) |
15210 | { |
15211 | tree u = build_omp_clause (clause_loc, kind); |
15212 | OMP_CLAUSE_DECL (u) = expr.value; |
15213 | OMP_CLAUSE_CHAIN (u) = list; |
15214 | list = u; |
15215 | } |
15216 | |
15217 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
15218 | break; |
15219 | |
15220 | c_parser_consume_token (parser); |
15221 | first = false; |
15222 | continue; |
15223 | } |
15224 | |
15225 | tokens.truncate (size: 0); |
15226 | unsigned int nesting_depth = 0; |
15227 | while (1) |
15228 | { |
15229 | c_token *token = c_parser_peek_token (parser); |
15230 | switch (token->type) |
15231 | { |
15232 | case CPP_EOF: |
15233 | case CPP_PRAGMA_EOL: |
15234 | break; |
15235 | case CPP_OPEN_BRACE: |
15236 | case CPP_OPEN_PAREN: |
15237 | case CPP_OPEN_SQUARE: |
15238 | ++nesting_depth; |
15239 | goto add; |
15240 | case CPP_CLOSE_BRACE: |
15241 | case CPP_CLOSE_PAREN: |
15242 | case CPP_CLOSE_SQUARE: |
15243 | if (nesting_depth-- == 0) |
15244 | break; |
15245 | goto add; |
15246 | case CPP_COMMA: |
15247 | if (nesting_depth == 0) |
15248 | break; |
15249 | goto add; |
15250 | default: |
15251 | add: |
15252 | tokens.safe_push (obj: *token); |
15253 | c_parser_consume_token (parser); |
15254 | continue; |
15255 | } |
15256 | break; |
15257 | } |
15258 | |
15259 | /* Make sure nothing tries to read past the end of the tokens. */ |
15260 | c_token eof_token; |
15261 | memset (s: &eof_token, c: 0, n: sizeof (eof_token)); |
15262 | eof_token.type = CPP_EOF; |
15263 | tokens.safe_push (obj: eof_token); |
15264 | tokens.safe_push (obj: eof_token); |
15265 | |
15266 | saved_tokens = parser->tokens; |
15267 | tokens_avail = parser->tokens_avail; |
15268 | parser->tokens = tokens.address (); |
15269 | parser->tokens_avail = tokens.length (); |
15270 | } |
15271 | else if (map_lvalue |
15272 | && (kind == OMP_CLAUSE_MAP |
15273 | || kind == OMP_CLAUSE_TO |
15274 | || kind == OMP_CLAUSE_FROM)) |
15275 | { |
15276 | location_t loc = c_parser_peek_token (parser)->location; |
15277 | bool save_c_omp_array_section_p = c_omp_array_section_p; |
15278 | c_omp_array_section_p = true; |
15279 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15280 | if (expr.value != error_mark_node) |
15281 | mark_exp_read (expr.value); |
15282 | c_omp_array_section_p = save_c_omp_array_section_p; |
15283 | tree decl = expr.value; |
15284 | |
15285 | /* This code rewrites a parsed expression containing various tree |
15286 | codes used to represent array accesses into a more uniform nest of |
15287 | OMP_ARRAY_SECTION nodes before it is processed by |
15288 | c-typeck.cc:handle_omp_array_sections_1. It might be more |
15289 | efficient to move this logic to that function instead, analysing |
15290 | the parsed expression directly rather than this preprocessed |
15291 | form. (See also equivalent code in cp/parser.cc, |
15292 | cp/semantics.cc). */ |
15293 | dims.truncate (size: 0); |
15294 | if (TREE_CODE (decl) == OMP_ARRAY_SECTION) |
15295 | { |
15296 | while (TREE_CODE (decl) == OMP_ARRAY_SECTION) |
15297 | { |
15298 | tree low_bound = TREE_OPERAND (decl, 1); |
15299 | tree length = TREE_OPERAND (decl, 2); |
15300 | dims.safe_push (obj: omp_dim (low_bound, length, loc, false)); |
15301 | decl = TREE_OPERAND (decl, 0); |
15302 | } |
15303 | |
15304 | while (TREE_CODE (decl) == ARRAY_REF |
15305 | || TREE_CODE (decl) == INDIRECT_REF |
15306 | || TREE_CODE (decl) == COMPOUND_EXPR) |
15307 | { |
15308 | if (TREE_CODE (decl) == COMPOUND_EXPR) |
15309 | { |
15310 | decl = TREE_OPERAND (decl, 1); |
15311 | STRIP_NOPS (decl); |
15312 | } |
15313 | else if (TREE_CODE (decl) == INDIRECT_REF) |
15314 | { |
15315 | dims.safe_push (obj: omp_dim (integer_zero_node, |
15316 | integer_one_node, loc, true)); |
15317 | decl = TREE_OPERAND (decl, 0); |
15318 | } |
15319 | else /* ARRAY_REF. */ |
15320 | { |
15321 | tree index = TREE_OPERAND (decl, 1); |
15322 | dims.safe_push (obj: omp_dim (index, integer_one_node, loc, |
15323 | true)); |
15324 | decl = TREE_OPERAND (decl, 0); |
15325 | } |
15326 | } |
15327 | |
15328 | for (int i = dims.length () - 1; i >= 0; i--) |
15329 | decl = build_omp_array_section (loc, decl, dims[i].low_bound, |
15330 | dims[i].length); |
15331 | } |
15332 | else if (TREE_CODE (decl) == INDIRECT_REF) |
15333 | { |
15334 | /* Turn indirection of a pointer "*foo" into "foo[0:1]". */ |
15335 | decl = TREE_OPERAND (decl, 0); |
15336 | STRIP_NOPS (decl); |
15337 | |
15338 | decl = build_omp_array_section (loc, decl, integer_zero_node, |
15339 | integer_one_node); |
15340 | } |
15341 | else if (TREE_CODE (decl) == ARRAY_REF) |
15342 | { |
15343 | tree idx = TREE_OPERAND (decl, 1); |
15344 | |
15345 | decl = TREE_OPERAND (decl, 0); |
15346 | STRIP_NOPS (decl); |
15347 | |
15348 | decl = build_omp_array_section (loc, decl, idx, integer_one_node); |
15349 | } |
15350 | else if (TREE_CODE (decl) == NON_LVALUE_EXPR |
15351 | || CONVERT_EXPR_P (decl)) |
15352 | decl = TREE_OPERAND (decl, 0); |
15353 | |
15354 | tree u = build_omp_clause (clause_loc, kind); |
15355 | OMP_CLAUSE_DECL (u) = decl; |
15356 | OMP_CLAUSE_CHAIN (u) = list; |
15357 | list = u; |
15358 | |
15359 | goto next_item; |
15360 | } |
15361 | |
15362 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
15363 | && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
15364 | { |
15365 | t = lookup_name (c_parser_peek_token (parser)->value); |
15366 | |
15367 | if (t == NULL_TREE) |
15368 | { |
15369 | undeclared_variable (c_parser_peek_token (parser)->location, |
15370 | c_parser_peek_token (parser)->value); |
15371 | t = error_mark_node; |
15372 | } |
15373 | |
15374 | c_parser_consume_token (parser); |
15375 | } |
15376 | else if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
15377 | && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME |
15378 | || (c_parser_peek_token (parser)->keyword |
15379 | == RID_PRETTY_FUNCTION_NAME) |
15380 | || (c_parser_peek_token (parser)->keyword |
15381 | == RID_C99_FUNCTION_NAME))) |
15382 | t = c_parser_predefined_identifier (parser).value; |
15383 | else |
15384 | { |
15385 | if (first) |
15386 | c_parser_error (parser, gmsgid: "expected identifier" ); |
15387 | break; |
15388 | } |
15389 | |
15390 | if (t == error_mark_node) |
15391 | ; |
15392 | else if (kind != 0) |
15393 | { |
15394 | switch (kind) |
15395 | { |
15396 | case OMP_CLAUSE__CACHE_: |
15397 | /* The OpenACC cache directive explicitly only allows "array |
15398 | elements or subarrays". */ |
15399 | if (c_parser_peek_token (parser)->type != CPP_OPEN_SQUARE) |
15400 | { |
15401 | c_parser_error (parser, gmsgid: "expected %<[%>" ); |
15402 | t = error_mark_node; |
15403 | break; |
15404 | } |
15405 | /* FALLTHROUGH */ |
15406 | case OMP_CLAUSE_MAP: |
15407 | case OMP_CLAUSE_FROM: |
15408 | case OMP_CLAUSE_TO: |
15409 | start_component_ref: |
15410 | while (c_parser_next_token_is (parser, type: CPP_DOT) |
15411 | || c_parser_next_token_is (parser, type: CPP_DEREF)) |
15412 | { |
15413 | location_t op_loc = c_parser_peek_token (parser)->location; |
15414 | location_t arrow_loc = UNKNOWN_LOCATION; |
15415 | if (c_parser_next_token_is (parser, type: CPP_DEREF)) |
15416 | { |
15417 | c_expr t_expr; |
15418 | t_expr.value = t; |
15419 | t_expr.original_code = ERROR_MARK; |
15420 | t_expr.original_type = NULL; |
15421 | set_c_expr_source_range (expr: &t_expr, start: op_loc, finish: op_loc); |
15422 | t_expr.m_decimal = 0; |
15423 | t_expr = convert_lvalue_to_rvalue (op_loc, t_expr, |
15424 | true, false); |
15425 | t = build_indirect_ref (op_loc, t_expr.value, RO_ARROW); |
15426 | arrow_loc = t_expr.get_location (); |
15427 | } |
15428 | c_parser_consume_token (parser); |
15429 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
15430 | { |
15431 | c_parser_error (parser, gmsgid: "expected identifier" ); |
15432 | t = error_mark_node; |
15433 | break; |
15434 | } |
15435 | |
15436 | c_token *comp_tok = c_parser_peek_token (parser); |
15437 | tree ident = comp_tok->value; |
15438 | location_t comp_loc = comp_tok->location; |
15439 | c_parser_consume_token (parser); |
15440 | t = build_component_ref (op_loc, t, ident, comp_loc, |
15441 | arrow_loc); |
15442 | } |
15443 | /* FALLTHROUGH */ |
15444 | case OMP_CLAUSE_AFFINITY: |
15445 | case OMP_CLAUSE_DEPEND: |
15446 | case OMP_CLAUSE_REDUCTION: |
15447 | case OMP_CLAUSE_IN_REDUCTION: |
15448 | case OMP_CLAUSE_TASK_REDUCTION: |
15449 | case OMP_CLAUSE_HAS_DEVICE_ADDR: |
15450 | array_section_p = false; |
15451 | dims.truncate (size: 0); |
15452 | while (c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE)) |
15453 | { |
15454 | location_t loc = UNKNOWN_LOCATION; |
15455 | tree low_bound = NULL_TREE, length = NULL_TREE; |
15456 | bool no_colon = false; |
15457 | |
15458 | c_parser_consume_token (parser); |
15459 | if (!c_parser_next_token_is (parser, type: CPP_COLON)) |
15460 | { |
15461 | location_t expr_loc |
15462 | = c_parser_peek_token (parser)->location; |
15463 | c_expr expr = c_parser_expression (parser); |
15464 | expr = convert_lvalue_to_rvalue (expr_loc, expr, |
15465 | false, true); |
15466 | low_bound = expr.value; |
15467 | loc = expr_loc; |
15468 | } |
15469 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
15470 | { |
15471 | length = integer_one_node; |
15472 | no_colon = true; |
15473 | } |
15474 | else |
15475 | { |
15476 | /* Look for `:'. */ |
15477 | if (!c_parser_require (parser, type: CPP_COLON, |
15478 | msgid: "expected %<:%>" )) |
15479 | { |
15480 | t = error_mark_node; |
15481 | break; |
15482 | } |
15483 | array_section_p = true; |
15484 | if (!c_parser_next_token_is (parser, type: CPP_CLOSE_SQUARE)) |
15485 | { |
15486 | location_t expr_loc |
15487 | = c_parser_peek_token (parser)->location; |
15488 | c_expr expr = c_parser_expression (parser); |
15489 | expr = convert_lvalue_to_rvalue (expr_loc, expr, |
15490 | false, true); |
15491 | length = expr.value; |
15492 | } |
15493 | } |
15494 | /* Look for the closing `]'. */ |
15495 | if (!c_parser_require (parser, type: CPP_CLOSE_SQUARE, |
15496 | msgid: "expected %<]%>" )) |
15497 | { |
15498 | t = error_mark_node; |
15499 | break; |
15500 | } |
15501 | |
15502 | dims.safe_push (obj: omp_dim (low_bound, length, loc, no_colon)); |
15503 | } |
15504 | |
15505 | if (t != error_mark_node) |
15506 | { |
15507 | if ((kind == OMP_CLAUSE_MAP |
15508 | || kind == OMP_CLAUSE_FROM |
15509 | || kind == OMP_CLAUSE_TO) |
15510 | && !array_section_p |
15511 | && (c_parser_next_token_is (parser, type: CPP_DOT) |
15512 | || c_parser_next_token_is (parser, type: CPP_DEREF))) |
15513 | { |
15514 | for (unsigned i = 0; i < dims.length (); i++) |
15515 | { |
15516 | gcc_assert (dims[i].length == integer_one_node); |
15517 | t = build_array_ref (dims[i].loc, |
15518 | t, dims[i].low_bound); |
15519 | } |
15520 | goto start_component_ref; |
15521 | } |
15522 | else |
15523 | for (unsigned i = 0; i < dims.length (); i++) |
15524 | t = build_omp_array_section (clause_loc, t, |
15525 | dims[i].low_bound, |
15526 | dims[i].length); |
15527 | } |
15528 | |
15529 | if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) |
15530 | && t != error_mark_node |
15531 | && parser->tokens_avail != 2) |
15532 | { |
15533 | if (array_section_p) |
15534 | { |
15535 | error_at (c_parser_peek_token (parser)->location, |
15536 | "expected %<)%> or %<,%>" ); |
15537 | t = error_mark_node; |
15538 | } |
15539 | else |
15540 | { |
15541 | parser->tokens = tokens.address (); |
15542 | parser->tokens_avail = tokens.length (); |
15543 | |
15544 | t = c_parser_expr_no_commas (parser, NULL).value; |
15545 | if (t != error_mark_node && parser->tokens_avail != 2) |
15546 | { |
15547 | error_at (c_parser_peek_token (parser)->location, |
15548 | "expected %<)%> or %<,%>" ); |
15549 | t = error_mark_node; |
15550 | } |
15551 | } |
15552 | } |
15553 | break; |
15554 | default: |
15555 | break; |
15556 | } |
15557 | |
15558 | if (t != error_mark_node) |
15559 | { |
15560 | tree u = build_omp_clause (clause_loc, kind); |
15561 | OMP_CLAUSE_DECL (u) = t; |
15562 | OMP_CLAUSE_CHAIN (u) = list; |
15563 | list = u; |
15564 | } |
15565 | } |
15566 | else |
15567 | list = tree_cons (t, NULL_TREE, list); |
15568 | |
15569 | if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) |
15570 | { |
15571 | parser->tokens = saved_tokens; |
15572 | parser->tokens_avail = tokens_avail; |
15573 | } |
15574 | |
15575 | next_item: |
15576 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA)) |
15577 | break; |
15578 | |
15579 | c_parser_consume_token (parser); |
15580 | first = false; |
15581 | } |
15582 | |
15583 | return list; |
15584 | } |
15585 | |
15586 | /* Similarly, but expect leading and trailing parenthesis. This is a very |
15587 | common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF |
15588 | argument is true if list items can use the deref (->) operator. */ |
15589 | |
15590 | static tree |
15591 | c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, |
15592 | tree list, bool map_lvalue = false) |
15593 | { |
15594 | /* The clauses location. */ |
15595 | location_t loc = c_parser_peek_token (parser)->location; |
15596 | |
15597 | if (parser->in_omp_decl_attribute) |
15598 | { |
15599 | if (kind) |
15600 | { |
15601 | tree u = build_omp_clause (loc, kind); |
15602 | OMP_CLAUSE_DECL (u) = parser->in_omp_decl_attribute; |
15603 | OMP_CLAUSE_CHAIN (u) = list; |
15604 | return u; |
15605 | } |
15606 | else |
15607 | return tree_cons (parser->in_omp_decl_attribute, NULL_TREE, list); |
15608 | } |
15609 | |
15610 | matching_parens parens; |
15611 | if (parens.require_open (parser)) |
15612 | { |
15613 | list = c_parser_omp_variable_list (parser, clause_loc: loc, kind, list, map_lvalue); |
15614 | parens.skip_until_found_close (parser); |
15615 | } |
15616 | return list; |
15617 | } |
15618 | |
15619 | /* OpenACC 2.0: |
15620 | copy ( variable-list ) |
15621 | copyin ( variable-list ) |
15622 | copyout ( variable-list ) |
15623 | create ( variable-list ) |
15624 | delete ( variable-list ) |
15625 | present ( variable-list ) |
15626 | |
15627 | OpenACC 2.6: |
15628 | no_create ( variable-list ) |
15629 | attach ( variable-list ) |
15630 | detach ( variable-list ) |
15631 | |
15632 | OpenACC 2.7: |
15633 | copyin (readonly : variable-list ) |
15634 | */ |
15635 | |
15636 | static tree |
15637 | c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, |
15638 | tree list) |
15639 | { |
15640 | enum gomp_map_kind kind; |
15641 | switch (c_kind) |
15642 | { |
15643 | case PRAGMA_OACC_CLAUSE_ATTACH: |
15644 | kind = GOMP_MAP_ATTACH; |
15645 | break; |
15646 | case PRAGMA_OACC_CLAUSE_COPY: |
15647 | kind = GOMP_MAP_TOFROM; |
15648 | break; |
15649 | case PRAGMA_OACC_CLAUSE_COPYIN: |
15650 | kind = GOMP_MAP_TO; |
15651 | break; |
15652 | case PRAGMA_OACC_CLAUSE_COPYOUT: |
15653 | kind = GOMP_MAP_FROM; |
15654 | break; |
15655 | case PRAGMA_OACC_CLAUSE_CREATE: |
15656 | kind = GOMP_MAP_ALLOC; |
15657 | break; |
15658 | case PRAGMA_OACC_CLAUSE_DELETE: |
15659 | kind = GOMP_MAP_RELEASE; |
15660 | break; |
15661 | case PRAGMA_OACC_CLAUSE_DETACH: |
15662 | kind = GOMP_MAP_DETACH; |
15663 | break; |
15664 | case PRAGMA_OACC_CLAUSE_DEVICE: |
15665 | kind = GOMP_MAP_FORCE_TO; |
15666 | break; |
15667 | case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: |
15668 | kind = GOMP_MAP_DEVICE_RESIDENT; |
15669 | break; |
15670 | case PRAGMA_OACC_CLAUSE_LINK: |
15671 | kind = GOMP_MAP_LINK; |
15672 | break; |
15673 | case PRAGMA_OACC_CLAUSE_NO_CREATE: |
15674 | kind = GOMP_MAP_IF_PRESENT; |
15675 | break; |
15676 | case PRAGMA_OACC_CLAUSE_PRESENT: |
15677 | kind = GOMP_MAP_FORCE_PRESENT; |
15678 | break; |
15679 | case PRAGMA_OACC_CLAUSE_SELF: |
15680 | /* "The 'host' clause is a synonym for the 'self' clause." */ |
15681 | case PRAGMA_OACC_CLAUSE_HOST: |
15682 | kind = GOMP_MAP_FORCE_FROM; |
15683 | break; |
15684 | default: |
15685 | gcc_unreachable (); |
15686 | } |
15687 | |
15688 | tree nl = list; |
15689 | bool readonly = false; |
15690 | location_t open_loc = c_parser_peek_token (parser)->location; |
15691 | matching_parens parens; |
15692 | if (parens.require_open (parser)) |
15693 | { |
15694 | /* Turn on readonly modifier parsing for copyin clause. */ |
15695 | if (c_kind == PRAGMA_OACC_CLAUSE_COPYIN) |
15696 | { |
15697 | c_token *token = c_parser_peek_token (parser); |
15698 | if (token->type == CPP_NAME |
15699 | && !strcmp (IDENTIFIER_POINTER (token->value), s2: "readonly" ) |
15700 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
15701 | { |
15702 | c_parser_consume_token (parser); |
15703 | c_parser_consume_token (parser); |
15704 | readonly = true; |
15705 | } |
15706 | } |
15707 | nl = c_parser_omp_variable_list (parser, clause_loc: open_loc, kind: OMP_CLAUSE_MAP, list, |
15708 | map_lvalue: false); |
15709 | parens.skip_until_found_close (parser); |
15710 | } |
15711 | |
15712 | for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
15713 | { |
15714 | OMP_CLAUSE_SET_MAP_KIND (c, kind); |
15715 | if (readonly) |
15716 | OMP_CLAUSE_MAP_READONLY (c) = 1; |
15717 | } |
15718 | |
15719 | return nl; |
15720 | } |
15721 | |
15722 | /* OpenACC 2.0: |
15723 | deviceptr ( variable-list ) */ |
15724 | |
15725 | static tree |
15726 | c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list) |
15727 | { |
15728 | location_t loc = c_parser_peek_token (parser)->location; |
15729 | tree vars, t; |
15730 | |
15731 | /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic |
15732 | c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, |
15733 | variable-list must only allow for pointer variables. */ |
15734 | vars = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ERROR, NULL); |
15735 | for (t = vars; t && t; t = TREE_CHAIN (t)) |
15736 | { |
15737 | tree v = TREE_PURPOSE (t); |
15738 | |
15739 | /* FIXME diagnostics: Ideally we should keep individual |
15740 | locations for all the variables in the var list to make the |
15741 | following errors more precise. Perhaps |
15742 | c_parser_omp_var_list_parens() should construct a list of |
15743 | locations to go along with the var list. */ |
15744 | |
15745 | if (!VAR_P (v) && TREE_CODE (v) != PARM_DECL) |
15746 | error_at (loc, "%qD is not a variable" , v); |
15747 | else if (TREE_TYPE (v) == error_mark_node) |
15748 | ; |
15749 | else if (!POINTER_TYPE_P (TREE_TYPE (v))) |
15750 | error_at (loc, "%qD is not a pointer variable" , v); |
15751 | |
15752 | tree u = build_omp_clause (loc, OMP_CLAUSE_MAP); |
15753 | OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR); |
15754 | OMP_CLAUSE_DECL (u) = v; |
15755 | OMP_CLAUSE_CHAIN (u) = list; |
15756 | list = u; |
15757 | } |
15758 | |
15759 | return list; |
15760 | } |
15761 | |
15762 | /* OpenACC 2.0, OpenMP 3.0: |
15763 | collapse ( constant-expression ) */ |
15764 | |
15765 | static tree |
15766 | c_parser_omp_clause_collapse (c_parser *parser, tree list) |
15767 | { |
15768 | tree c, num = error_mark_node; |
15769 | HOST_WIDE_INT n; |
15770 | location_t loc; |
15771 | |
15772 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_COLLAPSE, name: "collapse" ); |
15773 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_TILE, name: "tile" ); |
15774 | |
15775 | loc = c_parser_peek_token (parser)->location; |
15776 | matching_parens parens; |
15777 | if (parens.require_open (parser)) |
15778 | { |
15779 | num = c_parser_expr_no_commas (parser, NULL).value; |
15780 | parens.skip_until_found_close (parser); |
15781 | } |
15782 | if (num == error_mark_node) |
15783 | return list; |
15784 | mark_exp_read (num); |
15785 | num = c_fully_fold (num, false, NULL); |
15786 | if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) |
15787 | || !tree_fits_shwi_p (num) |
15788 | || (n = tree_to_shwi (num)) <= 0 |
15789 | || (int) n != n) |
15790 | { |
15791 | error_at (loc, |
15792 | "collapse argument needs positive constant integer expression" ); |
15793 | return list; |
15794 | } |
15795 | c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE); |
15796 | OMP_CLAUSE_COLLAPSE_EXPR (c) = num; |
15797 | OMP_CLAUSE_CHAIN (c) = list; |
15798 | return c; |
15799 | } |
15800 | |
15801 | /* OpenMP 2.5: |
15802 | copyin ( variable-list ) */ |
15803 | |
15804 | static tree |
15805 | c_parser_omp_clause_copyin (c_parser *parser, tree list) |
15806 | { |
15807 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_COPYIN, list); |
15808 | } |
15809 | |
15810 | /* OpenMP 2.5: |
15811 | copyprivate ( variable-list ) */ |
15812 | |
15813 | static tree |
15814 | c_parser_omp_clause_copyprivate (c_parser *parser, tree list) |
15815 | { |
15816 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_COPYPRIVATE, list); |
15817 | } |
15818 | |
15819 | /* OpenMP 2.5: |
15820 | default ( none | shared ) |
15821 | |
15822 | OpenMP 5.1: |
15823 | default ( private | firstprivate ) |
15824 | |
15825 | OpenACC: |
15826 | default ( none | present ) */ |
15827 | |
15828 | static tree |
15829 | c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) |
15830 | { |
15831 | enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; |
15832 | location_t loc = c_parser_peek_token (parser)->location; |
15833 | tree c; |
15834 | |
15835 | matching_parens parens; |
15836 | if (!parens.require_open (parser)) |
15837 | return list; |
15838 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
15839 | { |
15840 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
15841 | |
15842 | switch (p[0]) |
15843 | { |
15844 | case 'n': |
15845 | if (strcmp (s1: "none" , s2: p) != 0) |
15846 | goto invalid_kind; |
15847 | kind = OMP_CLAUSE_DEFAULT_NONE; |
15848 | break; |
15849 | |
15850 | case 'p': |
15851 | if (is_oacc) |
15852 | { |
15853 | if (strcmp (s1: "present" , s2: p) != 0) |
15854 | goto invalid_kind; |
15855 | kind = OMP_CLAUSE_DEFAULT_PRESENT; |
15856 | } |
15857 | else |
15858 | { |
15859 | if (strcmp (s1: "private" , s2: p) != 0) |
15860 | goto invalid_kind; |
15861 | kind = OMP_CLAUSE_DEFAULT_PRIVATE; |
15862 | } |
15863 | break; |
15864 | |
15865 | case 'f': |
15866 | if (strcmp (s1: "firstprivate" , s2: p) != 0 || is_oacc) |
15867 | goto invalid_kind; |
15868 | kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; |
15869 | break; |
15870 | |
15871 | case 's': |
15872 | if (strcmp (s1: "shared" , s2: p) != 0 || is_oacc) |
15873 | goto invalid_kind; |
15874 | kind = OMP_CLAUSE_DEFAULT_SHARED; |
15875 | break; |
15876 | |
15877 | default: |
15878 | goto invalid_kind; |
15879 | } |
15880 | |
15881 | c_parser_consume_token (parser); |
15882 | } |
15883 | else |
15884 | { |
15885 | invalid_kind: |
15886 | if (is_oacc) |
15887 | c_parser_error (parser, gmsgid: "expected %<none%> or %<present%>" ); |
15888 | else |
15889 | c_parser_error (parser, gmsgid: "expected %<none%>, %<shared%>, " |
15890 | "%<private%> or %<firstprivate%>" ); |
15891 | } |
15892 | parens.skip_until_found_close (parser); |
15893 | |
15894 | if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED) |
15895 | return list; |
15896 | |
15897 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_DEFAULT, name: "default" ); |
15898 | c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT); |
15899 | OMP_CLAUSE_CHAIN (c) = list; |
15900 | OMP_CLAUSE_DEFAULT_KIND (c) = kind; |
15901 | |
15902 | return c; |
15903 | } |
15904 | |
15905 | /* OpenMP 2.5: |
15906 | firstprivate ( variable-list ) */ |
15907 | |
15908 | static tree |
15909 | c_parser_omp_clause_firstprivate (c_parser *parser, tree list) |
15910 | { |
15911 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_FIRSTPRIVATE, list); |
15912 | } |
15913 | |
15914 | /* OpenMP 3.1: |
15915 | final ( expression ) */ |
15916 | |
15917 | static tree |
15918 | c_parser_omp_clause_final (c_parser *parser, tree list) |
15919 | { |
15920 | location_t loc = c_parser_peek_token (parser)->location; |
15921 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
15922 | { |
15923 | matching_parens parens; |
15924 | tree t, c; |
15925 | if (!parens.require_open (parser)) |
15926 | t = error_mark_node; |
15927 | else |
15928 | { |
15929 | location_t eloc = c_parser_peek_token (parser)->location; |
15930 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15931 | t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; |
15932 | t = c_objc_common_truthvalue_conversion (eloc, t); |
15933 | t = c_fully_fold (t, false, NULL); |
15934 | parens.skip_until_found_close (parser); |
15935 | } |
15936 | |
15937 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_FINAL, name: "final" ); |
15938 | |
15939 | c = build_omp_clause (loc, OMP_CLAUSE_FINAL); |
15940 | OMP_CLAUSE_FINAL_EXPR (c) = t; |
15941 | OMP_CLAUSE_CHAIN (c) = list; |
15942 | list = c; |
15943 | } |
15944 | else |
15945 | c_parser_error (parser, gmsgid: "expected %<(%>" ); |
15946 | |
15947 | return list; |
15948 | } |
15949 | |
15950 | /* OpenMP 5.1: |
15951 | indirect [( expression )] |
15952 | */ |
15953 | |
15954 | static tree |
15955 | c_parser_omp_clause_indirect (c_parser *parser, tree list) |
15956 | { |
15957 | location_t location = c_parser_peek_token (parser)->location; |
15958 | tree t; |
15959 | |
15960 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
15961 | { |
15962 | matching_parens parens; |
15963 | if (!parens.require_open (parser)) |
15964 | return list; |
15965 | |
15966 | location_t loc = c_parser_peek_token (parser)->location; |
15967 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
15968 | expr = convert_lvalue_to_rvalue (loc, expr, true, true); |
15969 | t = c_objc_common_truthvalue_conversion (loc, expr.value); |
15970 | t = c_fully_fold (t, false, NULL); |
15971 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
15972 | || TREE_CODE (t) != INTEGER_CST) |
15973 | { |
15974 | c_parser_error (parser, gmsgid: "expected constant logical expression" ); |
15975 | return list; |
15976 | } |
15977 | parens.skip_until_found_close (parser); |
15978 | } |
15979 | else |
15980 | t = integer_one_node; |
15981 | |
15982 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_INDIRECT, name: "indirect" ); |
15983 | |
15984 | tree c = build_omp_clause (location, OMP_CLAUSE_INDIRECT); |
15985 | OMP_CLAUSE_INDIRECT_EXPR (c) = t; |
15986 | OMP_CLAUSE_CHAIN (c) = list; |
15987 | |
15988 | return c; |
15989 | } |
15990 | |
15991 | /* OpenACC, OpenMP 2.5: |
15992 | if ( expression ) |
15993 | |
15994 | OpenMP 4.5: |
15995 | if ( directive-name-modifier : expression ) |
15996 | |
15997 | directive-name-modifier: |
15998 | parallel | task | taskloop | target data | target | target update |
15999 | | target enter data | target exit data |
16000 | |
16001 | OpenMP 5.0: |
16002 | directive-name-modifier: |
16003 | ... | simd | cancel */ |
16004 | |
16005 | static tree |
16006 | c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp) |
16007 | { |
16008 | location_t location = c_parser_peek_token (parser)->location; |
16009 | enum tree_code if_modifier = ERROR_MARK; |
16010 | |
16011 | matching_parens parens; |
16012 | if (!parens.require_open (parser)) |
16013 | return list; |
16014 | |
16015 | if (is_omp && c_parser_next_token_is (parser, type: CPP_NAME)) |
16016 | { |
16017 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16018 | int n = 2; |
16019 | if (strcmp (s1: p, s2: "cancel" ) == 0) |
16020 | if_modifier = VOID_CST; |
16021 | else if (strcmp (s1: p, s2: "parallel" ) == 0) |
16022 | if_modifier = OMP_PARALLEL; |
16023 | else if (strcmp (s1: p, s2: "simd" ) == 0) |
16024 | if_modifier = OMP_SIMD; |
16025 | else if (strcmp (s1: p, s2: "task" ) == 0) |
16026 | if_modifier = OMP_TASK; |
16027 | else if (strcmp (s1: p, s2: "taskloop" ) == 0) |
16028 | if_modifier = OMP_TASKLOOP; |
16029 | else if (strcmp (s1: p, s2: "target" ) == 0) |
16030 | { |
16031 | if_modifier = OMP_TARGET; |
16032 | if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
16033 | { |
16034 | p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value); |
16035 | if (strcmp (s1: "data" , s2: p) == 0) |
16036 | if_modifier = OMP_TARGET_DATA; |
16037 | else if (strcmp (s1: "update" , s2: p) == 0) |
16038 | if_modifier = OMP_TARGET_UPDATE; |
16039 | else if (strcmp (s1: "enter" , s2: p) == 0) |
16040 | if_modifier = OMP_TARGET_ENTER_DATA; |
16041 | else if (strcmp (s1: "exit" , s2: p) == 0) |
16042 | if_modifier = OMP_TARGET_EXIT_DATA; |
16043 | if (if_modifier != OMP_TARGET) |
16044 | { |
16045 | n = 3; |
16046 | c_parser_consume_token (parser); |
16047 | } |
16048 | else |
16049 | { |
16050 | location_t loc = c_parser_peek_2nd_token (parser)->location; |
16051 | error_at (loc, "expected %<data%>, %<update%>, %<enter%> " |
16052 | "or %<exit%>" ); |
16053 | if_modifier = ERROR_MARK; |
16054 | } |
16055 | if (if_modifier == OMP_TARGET_ENTER_DATA |
16056 | || if_modifier == OMP_TARGET_EXIT_DATA) |
16057 | { |
16058 | if (c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
16059 | { |
16060 | p = IDENTIFIER_POINTER |
16061 | (c_parser_peek_2nd_token (parser)->value); |
16062 | if (strcmp (s1: "data" , s2: p) == 0) |
16063 | n = 4; |
16064 | } |
16065 | if (n == 4) |
16066 | c_parser_consume_token (parser); |
16067 | else |
16068 | { |
16069 | location_t loc |
16070 | = c_parser_peek_2nd_token (parser)->location; |
16071 | error_at (loc, "expected %<data%>" ); |
16072 | if_modifier = ERROR_MARK; |
16073 | } |
16074 | } |
16075 | } |
16076 | } |
16077 | if (if_modifier != ERROR_MARK) |
16078 | { |
16079 | if (c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
16080 | { |
16081 | c_parser_consume_token (parser); |
16082 | c_parser_consume_token (parser); |
16083 | } |
16084 | else |
16085 | { |
16086 | if (n > 2) |
16087 | { |
16088 | location_t loc = c_parser_peek_2nd_token (parser)->location; |
16089 | error_at (loc, "expected %<:%>" ); |
16090 | } |
16091 | if_modifier = ERROR_MARK; |
16092 | } |
16093 | } |
16094 | } |
16095 | |
16096 | location_t loc = c_parser_peek_token (parser)->location; |
16097 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16098 | expr = convert_lvalue_to_rvalue (loc, expr, true, true); |
16099 | tree t = c_objc_common_truthvalue_conversion (loc, expr.value), c; |
16100 | t = c_fully_fold (t, false, NULL); |
16101 | parens.skip_until_found_close (parser); |
16102 | |
16103 | for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) |
16104 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF) |
16105 | { |
16106 | if (if_modifier != ERROR_MARK |
16107 | && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) |
16108 | { |
16109 | const char *p = NULL; |
16110 | switch (if_modifier) |
16111 | { |
16112 | case VOID_CST: p = "cancel" ; break; |
16113 | case OMP_PARALLEL: p = "parallel" ; break; |
16114 | case OMP_SIMD: p = "simd" ; break; |
16115 | case OMP_TASK: p = "task" ; break; |
16116 | case OMP_TASKLOOP: p = "taskloop" ; break; |
16117 | case OMP_TARGET_DATA: p = "target data" ; break; |
16118 | case OMP_TARGET: p = "target" ; break; |
16119 | case OMP_TARGET_UPDATE: p = "target update" ; break; |
16120 | case OMP_TARGET_ENTER_DATA: p = "target enter data" ; break; |
16121 | case OMP_TARGET_EXIT_DATA: p = "target exit data" ; break; |
16122 | default: gcc_unreachable (); |
16123 | } |
16124 | error_at (location, "too many %<if%> clauses with %qs modifier" , |
16125 | p); |
16126 | return list; |
16127 | } |
16128 | else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier) |
16129 | { |
16130 | if (!is_omp) |
16131 | error_at (location, "too many %<if%> clauses" ); |
16132 | else |
16133 | error_at (location, "too many %<if%> clauses without modifier" ); |
16134 | return list; |
16135 | } |
16136 | else if (if_modifier == ERROR_MARK |
16137 | || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK) |
16138 | { |
16139 | error_at (location, "if any %<if%> clause has modifier, then all " |
16140 | "%<if%> clauses have to use modifier" ); |
16141 | return list; |
16142 | } |
16143 | } |
16144 | |
16145 | c = build_omp_clause (location, OMP_CLAUSE_IF); |
16146 | OMP_CLAUSE_IF_MODIFIER (c) = if_modifier; |
16147 | OMP_CLAUSE_IF_EXPR (c) = t; |
16148 | OMP_CLAUSE_CHAIN (c) = list; |
16149 | return c; |
16150 | } |
16151 | |
16152 | /* OpenMP 2.5: |
16153 | lastprivate ( variable-list ) |
16154 | |
16155 | OpenMP 5.0: |
16156 | lastprivate ( [ lastprivate-modifier : ] variable-list ) */ |
16157 | |
16158 | static tree |
16159 | c_parser_omp_clause_lastprivate (c_parser *parser, tree list) |
16160 | { |
16161 | /* The clauses location. */ |
16162 | location_t loc = c_parser_peek_token (parser)->location; |
16163 | |
16164 | if (c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
16165 | { |
16166 | bool conditional = false; |
16167 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
16168 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
16169 | { |
16170 | const char *p |
16171 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16172 | if (strcmp (s1: p, s2: "conditional" ) == 0) |
16173 | { |
16174 | conditional = true; |
16175 | c_parser_consume_token (parser); |
16176 | c_parser_consume_token (parser); |
16177 | } |
16178 | } |
16179 | tree nlist = c_parser_omp_variable_list (parser, clause_loc: loc, |
16180 | kind: OMP_CLAUSE_LASTPRIVATE, list); |
16181 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" ); |
16182 | if (conditional) |
16183 | for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) |
16184 | OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1; |
16185 | return nlist; |
16186 | } |
16187 | return list; |
16188 | } |
16189 | |
16190 | /* OpenMP 3.1: |
16191 | mergeable */ |
16192 | |
16193 | static tree |
16194 | c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
16195 | { |
16196 | tree c; |
16197 | |
16198 | /* FIXME: Should we allow duplicates? */ |
16199 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_MERGEABLE, name: "mergeable" ); |
16200 | |
16201 | c = build_omp_clause (c_parser_peek_token (parser)->location, |
16202 | OMP_CLAUSE_MERGEABLE); |
16203 | OMP_CLAUSE_CHAIN (c) = list; |
16204 | |
16205 | return c; |
16206 | } |
16207 | |
16208 | /* OpenMP 2.5: |
16209 | nowait */ |
16210 | |
16211 | static tree |
16212 | c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
16213 | { |
16214 | tree c; |
16215 | location_t loc = c_parser_peek_token (parser)->location; |
16216 | |
16217 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NOWAIT, name: "nowait" ); |
16218 | |
16219 | c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT); |
16220 | OMP_CLAUSE_CHAIN (c) = list; |
16221 | return c; |
16222 | } |
16223 | |
16224 | /* OpenMP 2.5: |
16225 | num_threads ( expression ) */ |
16226 | |
16227 | static tree |
16228 | c_parser_omp_clause_num_threads (c_parser *parser, tree list) |
16229 | { |
16230 | location_t num_threads_loc = c_parser_peek_token (parser)->location; |
16231 | matching_parens parens; |
16232 | if (parens.require_open (parser)) |
16233 | { |
16234 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16235 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16236 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16237 | tree c, t = expr.value; |
16238 | t = c_fully_fold (t, false, NULL); |
16239 | |
16240 | parens.skip_until_found_close (parser); |
16241 | |
16242 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16243 | { |
16244 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16245 | return list; |
16246 | } |
16247 | |
16248 | /* Attempt to statically determine when the number isn't positive. */ |
16249 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
16250 | build_int_cst (TREE_TYPE (t), 0)); |
16251 | protected_set_expr_location (c, expr_loc); |
16252 | if (c == boolean_true_node) |
16253 | { |
16254 | warning_at (expr_loc, OPT_Wopenmp, |
16255 | "%<num_threads%> value must be positive" ); |
16256 | t = integer_one_node; |
16257 | } |
16258 | |
16259 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NUM_THREADS, name: "num_threads" ); |
16260 | |
16261 | c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS); |
16262 | OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; |
16263 | OMP_CLAUSE_CHAIN (c) = list; |
16264 | list = c; |
16265 | } |
16266 | |
16267 | return list; |
16268 | } |
16269 | |
16270 | /* OpenMP 4.5: |
16271 | num_tasks ( expression ) |
16272 | |
16273 | OpenMP 5.1: |
16274 | num_tasks ( strict : expression ) */ |
16275 | |
16276 | static tree |
16277 | c_parser_omp_clause_num_tasks (c_parser *parser, tree list) |
16278 | { |
16279 | location_t num_tasks_loc = c_parser_peek_token (parser)->location; |
16280 | matching_parens parens; |
16281 | if (parens.require_open (parser)) |
16282 | { |
16283 | bool strict = false; |
16284 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
16285 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON |
16286 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
16287 | s2: "strict" ) == 0) |
16288 | { |
16289 | strict = true; |
16290 | c_parser_consume_token (parser); |
16291 | c_parser_consume_token (parser); |
16292 | } |
16293 | |
16294 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16295 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16296 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16297 | tree c, t = expr.value; |
16298 | t = c_fully_fold (t, false, NULL); |
16299 | |
16300 | parens.skip_until_found_close (parser); |
16301 | |
16302 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16303 | { |
16304 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16305 | return list; |
16306 | } |
16307 | |
16308 | /* Attempt to statically determine when the number isn't positive. */ |
16309 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
16310 | build_int_cst (TREE_TYPE (t), 0)); |
16311 | if (CAN_HAVE_LOCATION_P (c)) |
16312 | SET_EXPR_LOCATION (c, expr_loc); |
16313 | if (c == boolean_true_node) |
16314 | { |
16315 | warning_at (expr_loc, OPT_Wopenmp, |
16316 | "%<num_tasks%> value must be positive" ); |
16317 | t = integer_one_node; |
16318 | } |
16319 | |
16320 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NUM_TASKS, name: "num_tasks" ); |
16321 | |
16322 | c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS); |
16323 | OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; |
16324 | OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; |
16325 | OMP_CLAUSE_CHAIN (c) = list; |
16326 | list = c; |
16327 | } |
16328 | |
16329 | return list; |
16330 | } |
16331 | |
16332 | /* OpenMP 4.5: |
16333 | grainsize ( expression ) |
16334 | |
16335 | OpenMP 5.1: |
16336 | grainsize ( strict : expression ) */ |
16337 | |
16338 | static tree |
16339 | c_parser_omp_clause_grainsize (c_parser *parser, tree list) |
16340 | { |
16341 | location_t grainsize_loc = c_parser_peek_token (parser)->location; |
16342 | matching_parens parens; |
16343 | if (parens.require_open (parser)) |
16344 | { |
16345 | bool strict = false; |
16346 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
16347 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON |
16348 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
16349 | s2: "strict" ) == 0) |
16350 | { |
16351 | strict = true; |
16352 | c_parser_consume_token (parser); |
16353 | c_parser_consume_token (parser); |
16354 | } |
16355 | |
16356 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16357 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16358 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16359 | tree c, t = expr.value; |
16360 | t = c_fully_fold (t, false, NULL); |
16361 | |
16362 | parens.skip_until_found_close (parser); |
16363 | |
16364 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16365 | { |
16366 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16367 | return list; |
16368 | } |
16369 | |
16370 | /* Attempt to statically determine when the number isn't positive. */ |
16371 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
16372 | build_int_cst (TREE_TYPE (t), 0)); |
16373 | if (CAN_HAVE_LOCATION_P (c)) |
16374 | SET_EXPR_LOCATION (c, expr_loc); |
16375 | if (c == boolean_true_node) |
16376 | { |
16377 | warning_at (expr_loc, OPT_Wopenmp, |
16378 | "%<grainsize%> value must be positive" ); |
16379 | t = integer_one_node; |
16380 | } |
16381 | |
16382 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_GRAINSIZE, name: "grainsize" ); |
16383 | |
16384 | c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE); |
16385 | OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; |
16386 | OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; |
16387 | OMP_CLAUSE_CHAIN (c) = list; |
16388 | list = c; |
16389 | } |
16390 | |
16391 | return list; |
16392 | } |
16393 | |
16394 | /* OpenMP 4.5: |
16395 | priority ( expression ) */ |
16396 | |
16397 | static tree |
16398 | c_parser_omp_clause_priority (c_parser *parser, tree list) |
16399 | { |
16400 | location_t priority_loc = c_parser_peek_token (parser)->location; |
16401 | matching_parens parens; |
16402 | if (parens.require_open (parser)) |
16403 | { |
16404 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16405 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16406 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16407 | tree c, t = expr.value; |
16408 | t = c_fully_fold (t, false, NULL); |
16409 | |
16410 | parens.skip_until_found_close (parser); |
16411 | |
16412 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16413 | { |
16414 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16415 | return list; |
16416 | } |
16417 | |
16418 | /* Attempt to statically determine when the number isn't |
16419 | non-negative. */ |
16420 | c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, t, |
16421 | build_int_cst (TREE_TYPE (t), 0)); |
16422 | if (CAN_HAVE_LOCATION_P (c)) |
16423 | SET_EXPR_LOCATION (c, expr_loc); |
16424 | if (c == boolean_true_node) |
16425 | { |
16426 | warning_at (expr_loc, OPT_Wopenmp, |
16427 | "%<priority%> value must be non-negative" ); |
16428 | t = integer_one_node; |
16429 | } |
16430 | |
16431 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_PRIORITY, name: "priority" ); |
16432 | |
16433 | c = build_omp_clause (priority_loc, OMP_CLAUSE_PRIORITY); |
16434 | OMP_CLAUSE_PRIORITY_EXPR (c) = t; |
16435 | OMP_CLAUSE_CHAIN (c) = list; |
16436 | list = c; |
16437 | } |
16438 | |
16439 | return list; |
16440 | } |
16441 | |
16442 | /* OpenMP 4.5: |
16443 | hint ( expression ) */ |
16444 | |
16445 | static tree |
16446 | c_parser_omp_clause_hint (c_parser *parser, tree list) |
16447 | { |
16448 | location_t hint_loc = c_parser_peek_token (parser)->location; |
16449 | matching_parens parens; |
16450 | if (parens.require_open (parser)) |
16451 | { |
16452 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16453 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16454 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16455 | tree c, t = expr.value; |
16456 | t = c_fully_fold (t, false, NULL); |
16457 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
16458 | || TREE_CODE (t) != INTEGER_CST |
16459 | || tree_int_cst_sgn (t) == -1) |
16460 | { |
16461 | c_parser_error (parser, gmsgid: "expected constant integer expression " |
16462 | "with valid sync-hint value" ); |
16463 | return list; |
16464 | } |
16465 | parens.skip_until_found_close (parser); |
16466 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_HINT, name: "hint" ); |
16467 | |
16468 | c = build_omp_clause (hint_loc, OMP_CLAUSE_HINT); |
16469 | OMP_CLAUSE_HINT_EXPR (c) = t; |
16470 | OMP_CLAUSE_CHAIN (c) = list; |
16471 | list = c; |
16472 | } |
16473 | |
16474 | return list; |
16475 | } |
16476 | |
16477 | /* OpenMP 5.1: |
16478 | filter ( integer-expression ) */ |
16479 | |
16480 | static tree |
16481 | c_parser_omp_clause_filter (c_parser *parser, tree list) |
16482 | { |
16483 | location_t hint_loc = c_parser_peek_token (parser)->location; |
16484 | matching_parens parens; |
16485 | if (parens.require_open (parser)) |
16486 | { |
16487 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16488 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
16489 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16490 | tree c, t = expr.value; |
16491 | t = c_fully_fold (t, false, NULL); |
16492 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16493 | { |
16494 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16495 | return list; |
16496 | } |
16497 | parens.skip_until_found_close (parser); |
16498 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_FILTER, name: "filter" ); |
16499 | |
16500 | c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); |
16501 | OMP_CLAUSE_FILTER_EXPR (c) = t; |
16502 | OMP_CLAUSE_CHAIN (c) = list; |
16503 | list = c; |
16504 | } |
16505 | |
16506 | return list; |
16507 | } |
16508 | |
16509 | /* OpenMP 4.5: |
16510 | defaultmap ( tofrom : scalar ) |
16511 | |
16512 | OpenMP 5.0: |
16513 | defaultmap ( implicit-behavior [ : variable-category ] ) */ |
16514 | |
16515 | static tree |
16516 | c_parser_omp_clause_defaultmap (c_parser *parser, tree list) |
16517 | { |
16518 | location_t loc = c_parser_peek_token (parser)->location; |
16519 | tree c; |
16520 | const char *p; |
16521 | enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; |
16522 | enum omp_clause_defaultmap_kind category |
16523 | = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; |
16524 | |
16525 | matching_parens parens; |
16526 | if (!parens.require_open (parser)) |
16527 | return list; |
16528 | if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT)) |
16529 | p = "default" ; |
16530 | else if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
16531 | { |
16532 | invalid_behavior: |
16533 | c_parser_error (parser, gmsgid: "expected %<alloc%>, %<to%>, %<from%>, " |
16534 | "%<tofrom%>, %<firstprivate%>, %<none%> " |
16535 | "or %<default%>" ); |
16536 | goto out_err; |
16537 | } |
16538 | else |
16539 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16540 | |
16541 | switch (p[0]) |
16542 | { |
16543 | case 'a': |
16544 | if (strcmp (s1: "alloc" , s2: p) == 0) |
16545 | behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; |
16546 | else |
16547 | goto invalid_behavior; |
16548 | break; |
16549 | |
16550 | case 'd': |
16551 | if (strcmp (s1: "default" , s2: p) == 0) |
16552 | behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; |
16553 | else |
16554 | goto invalid_behavior; |
16555 | break; |
16556 | |
16557 | case 'f': |
16558 | if (strcmp (s1: "firstprivate" , s2: p) == 0) |
16559 | behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; |
16560 | else if (strcmp (s1: "from" , s2: p) == 0) |
16561 | behavior = OMP_CLAUSE_DEFAULTMAP_FROM; |
16562 | else |
16563 | goto invalid_behavior; |
16564 | break; |
16565 | |
16566 | case 'n': |
16567 | if (strcmp (s1: "none" , s2: p) == 0) |
16568 | behavior = OMP_CLAUSE_DEFAULTMAP_NONE; |
16569 | else |
16570 | goto invalid_behavior; |
16571 | break; |
16572 | |
16573 | case 'p': |
16574 | if (strcmp (s1: "present" , s2: p) == 0) |
16575 | behavior = OMP_CLAUSE_DEFAULTMAP_PRESENT; |
16576 | else |
16577 | goto invalid_behavior; |
16578 | break; |
16579 | |
16580 | case 't': |
16581 | if (strcmp (s1: "tofrom" , s2: p) == 0) |
16582 | behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; |
16583 | else if (strcmp (s1: "to" , s2: p) == 0) |
16584 | behavior = OMP_CLAUSE_DEFAULTMAP_TO; |
16585 | else |
16586 | goto invalid_behavior; |
16587 | break; |
16588 | |
16589 | default: |
16590 | goto invalid_behavior; |
16591 | } |
16592 | c_parser_consume_token (parser); |
16593 | |
16594 | if (!c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
16595 | { |
16596 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
16597 | goto out_err; |
16598 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
16599 | { |
16600 | invalid_category: |
16601 | c_parser_error (parser, gmsgid: "expected %<scalar%>, %<aggregate%>, " |
16602 | "%<pointer%> or %<all%>" ); |
16603 | goto out_err; |
16604 | } |
16605 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
16606 | switch (p[0]) |
16607 | { |
16608 | case 'a': |
16609 | if (strcmp (s1: "aggregate" , s2: p) == 0) |
16610 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; |
16611 | else if (strcmp (s1: "all" , s2: p) == 0) |
16612 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL; |
16613 | else |
16614 | goto invalid_category; |
16615 | break; |
16616 | |
16617 | case 'p': |
16618 | if (strcmp (s1: "pointer" , s2: p) == 0) |
16619 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; |
16620 | else |
16621 | goto invalid_category; |
16622 | break; |
16623 | |
16624 | case 's': |
16625 | if (strcmp (s1: "scalar" , s2: p) == 0) |
16626 | category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; |
16627 | else |
16628 | goto invalid_category; |
16629 | break; |
16630 | |
16631 | default: |
16632 | goto invalid_category; |
16633 | } |
16634 | |
16635 | c_parser_consume_token (parser); |
16636 | } |
16637 | parens.skip_until_found_close (parser); |
16638 | |
16639 | for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) |
16640 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP |
16641 | && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED |
16642 | || category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL |
16643 | || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category |
16644 | || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) |
16645 | == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) |
16646 | || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) |
16647 | == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL))) |
16648 | { |
16649 | enum omp_clause_defaultmap_kind cat = category; |
16650 | location_t loc = OMP_CLAUSE_LOCATION (c); |
16651 | if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED |
16652 | || (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL |
16653 | && (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) |
16654 | != OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) |
16655 | cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); |
16656 | p = NULL; |
16657 | switch (cat) |
16658 | { |
16659 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: |
16660 | p = NULL; |
16661 | break; |
16662 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL: |
16663 | p = "all" ; |
16664 | break; |
16665 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: |
16666 | p = "aggregate" ; |
16667 | break; |
16668 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: |
16669 | p = "pointer" ; |
16670 | break; |
16671 | case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: |
16672 | p = "scalar" ; |
16673 | break; |
16674 | default: |
16675 | gcc_unreachable (); |
16676 | } |
16677 | if (p) |
16678 | error_at (loc, "too many %<defaultmap%> clauses with %qs category" , |
16679 | p); |
16680 | else |
16681 | error_at (loc, "too many %<defaultmap%> clauses with unspecified " |
16682 | "category" ); |
16683 | break; |
16684 | } |
16685 | |
16686 | c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); |
16687 | OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); |
16688 | OMP_CLAUSE_CHAIN (c) = list; |
16689 | return c; |
16690 | |
16691 | out_err: |
16692 | parens.skip_until_found_close (parser); |
16693 | return list; |
16694 | } |
16695 | |
16696 | /* OpenACC 2.0: |
16697 | use_device ( variable-list ) |
16698 | |
16699 | OpenMP 4.5: |
16700 | use_device_ptr ( variable-list ) */ |
16701 | |
16702 | static tree |
16703 | c_parser_omp_clause_use_device_ptr (c_parser *parser, tree list) |
16704 | { |
16705 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_USE_DEVICE_PTR, |
16706 | list); |
16707 | } |
16708 | |
16709 | /* OpenMP 5.0: |
16710 | use_device_addr ( variable-list ) */ |
16711 | |
16712 | static tree |
16713 | c_parser_omp_clause_use_device_addr (c_parser *parser, tree list) |
16714 | { |
16715 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_USE_DEVICE_ADDR, |
16716 | list); |
16717 | } |
16718 | |
16719 | /* OpenMP 5.1: |
16720 | has_device_addr ( variable-list ) */ |
16721 | |
16722 | static tree |
16723 | c_parser_omp_clause_has_device_addr (c_parser *parser, tree list) |
16724 | { |
16725 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_HAS_DEVICE_ADDR, |
16726 | list); |
16727 | } |
16728 | |
16729 | /* OpenMP 4.5: |
16730 | is_device_ptr ( variable-list ) */ |
16731 | |
16732 | static tree |
16733 | c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list) |
16734 | { |
16735 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_IS_DEVICE_PTR, list); |
16736 | } |
16737 | |
16738 | /* OpenACC: |
16739 | num_gangs ( expression ) |
16740 | num_workers ( expression ) |
16741 | vector_length ( expression ) */ |
16742 | |
16743 | static tree |
16744 | c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code, |
16745 | tree list) |
16746 | { |
16747 | location_t loc = c_parser_peek_token (parser)->location; |
16748 | |
16749 | matching_parens parens; |
16750 | if (!parens.require_open (parser)) |
16751 | return list; |
16752 | |
16753 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16754 | c_expr expr = c_parser_expression (parser); |
16755 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
16756 | tree c, t = expr.value; |
16757 | t = c_fully_fold (t, false, NULL); |
16758 | |
16759 | parens.skip_until_found_close (parser); |
16760 | |
16761 | if (t == error_mark_node) |
16762 | return list; |
16763 | else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16764 | { |
16765 | error_at (expr_loc, "%qs expression must be integral" , |
16766 | omp_clause_code_name[code]); |
16767 | return list; |
16768 | } |
16769 | |
16770 | /* Attempt to statically determine when the number isn't positive. */ |
16771 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
16772 | build_int_cst (TREE_TYPE (t), 0)); |
16773 | protected_set_expr_location (c, expr_loc); |
16774 | if (c == boolean_true_node) |
16775 | { |
16776 | warning_at (expr_loc, 0, |
16777 | "%qs value must be positive" , |
16778 | omp_clause_code_name[code]); |
16779 | t = integer_one_node; |
16780 | } |
16781 | |
16782 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
16783 | |
16784 | c = build_omp_clause (loc, code); |
16785 | OMP_CLAUSE_OPERAND (c, 0) = t; |
16786 | OMP_CLAUSE_CHAIN (c) = list; |
16787 | return c; |
16788 | } |
16789 | |
16790 | /* OpenACC: |
16791 | |
16792 | gang [( gang-arg-list )] |
16793 | worker [( [num:] int-expr )] |
16794 | vector [( [length:] int-expr )] |
16795 | |
16796 | where gang-arg is one of: |
16797 | |
16798 | [num:] int-expr |
16799 | static: size-expr |
16800 | |
16801 | and size-expr may be: |
16802 | |
16803 | * |
16804 | int-expr |
16805 | */ |
16806 | |
16807 | static tree |
16808 | c_parser_oacc_shape_clause (c_parser *parser, location_t loc, |
16809 | omp_clause_code kind, |
16810 | const char *str, tree list) |
16811 | { |
16812 | const char *id = "num" ; |
16813 | tree ops[2] = { NULL_TREE, NULL_TREE }, c; |
16814 | |
16815 | if (kind == OMP_CLAUSE_VECTOR) |
16816 | id = "length" ; |
16817 | |
16818 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
16819 | { |
16820 | c_parser_consume_token (parser); |
16821 | |
16822 | do |
16823 | { |
16824 | c_token *next = c_parser_peek_token (parser); |
16825 | int idx = 0; |
16826 | |
16827 | /* Gang static argument. */ |
16828 | if (kind == OMP_CLAUSE_GANG |
16829 | && c_parser_next_token_is_keyword (parser, keyword: RID_STATIC)) |
16830 | { |
16831 | c_parser_consume_token (parser); |
16832 | |
16833 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
16834 | goto cleanup_error; |
16835 | |
16836 | idx = 1; |
16837 | if (ops[idx] != NULL_TREE) |
16838 | { |
16839 | c_parser_error (parser, gmsgid: "too many %<static%> arguments" ); |
16840 | goto cleanup_error; |
16841 | } |
16842 | |
16843 | /* Check for the '*' argument. */ |
16844 | if (c_parser_next_token_is (parser, type: CPP_MULT) |
16845 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
16846 | || c_parser_peek_2nd_token (parser)->type |
16847 | == CPP_CLOSE_PAREN)) |
16848 | { |
16849 | c_parser_consume_token (parser); |
16850 | ops[idx] = integer_minus_one_node; |
16851 | |
16852 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
16853 | { |
16854 | c_parser_consume_token (parser); |
16855 | continue; |
16856 | } |
16857 | else |
16858 | break; |
16859 | } |
16860 | } |
16861 | /* Worker num: argument and vector length: arguments. */ |
16862 | else if (c_parser_next_token_is (parser, type: CPP_NAME) |
16863 | && strcmp (s1: id, IDENTIFIER_POINTER (next->value)) == 0 |
16864 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
16865 | { |
16866 | c_parser_consume_token (parser); /* id */ |
16867 | c_parser_consume_token (parser); /* ':' */ |
16868 | } |
16869 | |
16870 | /* Now collect the actual argument. */ |
16871 | if (ops[idx] != NULL_TREE) |
16872 | { |
16873 | c_parser_error (parser, gmsgid: "unexpected argument" ); |
16874 | goto cleanup_error; |
16875 | } |
16876 | |
16877 | location_t expr_loc = c_parser_peek_token (parser)->location; |
16878 | c_expr cexpr = c_parser_expr_no_commas (parser, NULL); |
16879 | cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); |
16880 | tree expr = cexpr.value; |
16881 | if (expr == error_mark_node) |
16882 | goto cleanup_error; |
16883 | |
16884 | expr = c_fully_fold (expr, false, NULL); |
16885 | |
16886 | /* Attempt to statically determine when the number isn't a |
16887 | positive integer. */ |
16888 | |
16889 | if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))) |
16890 | { |
16891 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16892 | return list; |
16893 | } |
16894 | |
16895 | tree c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, expr, |
16896 | build_int_cst (TREE_TYPE (expr), 0)); |
16897 | if (c == boolean_true_node) |
16898 | { |
16899 | warning_at (loc, 0, |
16900 | "%qs value must be positive" , str); |
16901 | expr = integer_one_node; |
16902 | } |
16903 | |
16904 | ops[idx] = expr; |
16905 | |
16906 | if (kind == OMP_CLAUSE_GANG |
16907 | && c_parser_next_token_is (parser, type: CPP_COMMA)) |
16908 | { |
16909 | c_parser_consume_token (parser); |
16910 | continue; |
16911 | } |
16912 | break; |
16913 | } |
16914 | while (1); |
16915 | |
16916 | if (!c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
16917 | goto cleanup_error; |
16918 | } |
16919 | |
16920 | check_no_duplicate_clause (clauses: list, code: kind, name: str); |
16921 | |
16922 | c = build_omp_clause (loc, kind); |
16923 | |
16924 | if (ops[1]) |
16925 | OMP_CLAUSE_OPERAND (c, 1) = ops[1]; |
16926 | |
16927 | OMP_CLAUSE_OPERAND (c, 0) = ops[0]; |
16928 | OMP_CLAUSE_CHAIN (c) = list; |
16929 | |
16930 | return c; |
16931 | |
16932 | cleanup_error: |
16933 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: 0); |
16934 | return list; |
16935 | } |
16936 | |
16937 | /* OpenACC 2.5: |
16938 | auto |
16939 | finalize |
16940 | independent |
16941 | nohost |
16942 | seq */ |
16943 | |
16944 | static tree |
16945 | c_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code, |
16946 | tree list) |
16947 | { |
16948 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
16949 | |
16950 | tree c = build_omp_clause (loc, code); |
16951 | OMP_CLAUSE_CHAIN (c) = list; |
16952 | |
16953 | return c; |
16954 | } |
16955 | |
16956 | /* OpenACC: |
16957 | async [( int-expr )] */ |
16958 | |
16959 | static tree |
16960 | c_parser_oacc_clause_async (c_parser *parser, tree list) |
16961 | { |
16962 | tree c, t; |
16963 | location_t loc = c_parser_peek_token (parser)->location; |
16964 | |
16965 | t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); |
16966 | |
16967 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
16968 | { |
16969 | c_parser_consume_token (parser); |
16970 | |
16971 | t = c_parser_expr_no_commas (parser, NULL).value; |
16972 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
16973 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
16974 | else if (t == error_mark_node |
16975 | || !c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
16976 | return list; |
16977 | } |
16978 | else |
16979 | t = c_fully_fold (t, false, NULL); |
16980 | |
16981 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_ASYNC, name: "async" ); |
16982 | |
16983 | c = build_omp_clause (loc, OMP_CLAUSE_ASYNC); |
16984 | OMP_CLAUSE_ASYNC_EXPR (c) = t; |
16985 | OMP_CLAUSE_CHAIN (c) = list; |
16986 | list = c; |
16987 | |
16988 | return list; |
16989 | } |
16990 | |
16991 | /* OpenACC 2.0: |
16992 | tile ( size-expr-list ) */ |
16993 | |
16994 | static tree |
16995 | c_parser_oacc_clause_tile (c_parser *parser, tree list) |
16996 | { |
16997 | tree c, expr = error_mark_node; |
16998 | location_t loc; |
16999 | tree tile = NULL_TREE; |
17000 | |
17001 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_TILE, name: "tile" ); |
17002 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_COLLAPSE, name: "collapse" ); |
17003 | |
17004 | loc = c_parser_peek_token (parser)->location; |
17005 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
17006 | return list; |
17007 | |
17008 | do |
17009 | { |
17010 | if (tile && !c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" )) |
17011 | return list; |
17012 | |
17013 | if (c_parser_next_token_is (parser, type: CPP_MULT) |
17014 | && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA |
17015 | || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN)) |
17016 | { |
17017 | c_parser_consume_token (parser); |
17018 | expr = integer_zero_node; |
17019 | } |
17020 | else |
17021 | { |
17022 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17023 | c_expr cexpr = c_parser_expr_no_commas (parser, NULL); |
17024 | cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); |
17025 | expr = cexpr.value; |
17026 | |
17027 | if (expr == error_mark_node) |
17028 | { |
17029 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
17030 | msgid: "expected %<)%>" ); |
17031 | return list; |
17032 | } |
17033 | |
17034 | expr = c_fully_fold (expr, false, NULL); |
17035 | |
17036 | if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) |
17037 | || !tree_fits_shwi_p (expr) |
17038 | || tree_to_shwi (expr) <= 0) |
17039 | { |
17040 | error_at (expr_loc, "%<tile%> argument needs positive" |
17041 | " integral constant" ); |
17042 | expr = integer_zero_node; |
17043 | } |
17044 | } |
17045 | |
17046 | tile = tree_cons (NULL_TREE, expr, tile); |
17047 | } |
17048 | while (c_parser_next_token_is_not (parser, type: CPP_CLOSE_PAREN)); |
17049 | |
17050 | /* Consume the trailing ')'. */ |
17051 | c_parser_consume_token (parser); |
17052 | |
17053 | c = build_omp_clause (loc, OMP_CLAUSE_TILE); |
17054 | tile = nreverse (tile); |
17055 | OMP_CLAUSE_TILE_LIST (c) = tile; |
17056 | OMP_CLAUSE_CHAIN (c) = list; |
17057 | return c; |
17058 | } |
17059 | |
17060 | /* OpenACC: |
17061 | wait [( int-expr-list )] */ |
17062 | |
17063 | static tree |
17064 | c_parser_oacc_clause_wait (c_parser *parser, tree list) |
17065 | { |
17066 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17067 | |
17068 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
17069 | list = c_parser_oacc_wait_list (parser, clause_loc, list); |
17070 | else |
17071 | { |
17072 | tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); |
17073 | |
17074 | OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); |
17075 | OMP_CLAUSE_CHAIN (c) = list; |
17076 | list = c; |
17077 | } |
17078 | |
17079 | return list; |
17080 | } |
17081 | |
17082 | /* OpenACC 2.7: |
17083 | self [( expression )] */ |
17084 | |
17085 | static tree |
17086 | c_parser_oacc_compute_clause_self (c_parser *parser, tree list) |
17087 | { |
17088 | tree t; |
17089 | location_t location = c_parser_peek_token (parser)->location; |
17090 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
17091 | { |
17092 | matching_parens parens; |
17093 | parens.consume_open (parser); |
17094 | |
17095 | location_t loc = c_parser_peek_token (parser)->location; |
17096 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17097 | expr = convert_lvalue_to_rvalue (loc, expr, true, true); |
17098 | t = c_objc_common_truthvalue_conversion (loc, expr.value); |
17099 | t = c_fully_fold (t, false, NULL); |
17100 | parens.skip_until_found_close (parser); |
17101 | } |
17102 | else |
17103 | t = truthvalue_true_node; |
17104 | |
17105 | for (tree c = list; c; c = OMP_CLAUSE_CHAIN (c)) |
17106 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SELF) |
17107 | { |
17108 | error_at (location, "too many %<self%> clauses" ); |
17109 | return list; |
17110 | } |
17111 | |
17112 | tree c = build_omp_clause (location, OMP_CLAUSE_SELF); |
17113 | OMP_CLAUSE_SELF_EXPR (c) = t; |
17114 | OMP_CLAUSE_CHAIN (c) = list; |
17115 | return c; |
17116 | } |
17117 | |
17118 | /* OpenMP 5.0: |
17119 | order ( concurrent ) |
17120 | |
17121 | OpenMP 5.1: |
17122 | order ( order-modifier : concurrent ) |
17123 | |
17124 | order-modifier: |
17125 | reproducible |
17126 | unconstrained */ |
17127 | |
17128 | static tree |
17129 | c_parser_omp_clause_order (c_parser *parser, tree list) |
17130 | { |
17131 | location_t loc = c_parser_peek_token (parser)->location; |
17132 | tree c; |
17133 | const char *p; |
17134 | bool unconstrained = false; |
17135 | bool reproducible = false; |
17136 | |
17137 | matching_parens parens; |
17138 | if (!parens.require_open (parser)) |
17139 | return list; |
17140 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
17141 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
17142 | { |
17143 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17144 | if (strcmp (s1: p, s2: "unconstrained" ) == 0) |
17145 | unconstrained = true; |
17146 | else if (strcmp (s1: p, s2: "reproducible" ) == 0) |
17147 | reproducible = true; |
17148 | else |
17149 | { |
17150 | c_parser_error (parser, gmsgid: "expected %<reproducible%> or " |
17151 | "%<unconstrained%>" ); |
17152 | goto out_err; |
17153 | } |
17154 | c_parser_consume_token (parser); |
17155 | c_parser_consume_token (parser); |
17156 | } |
17157 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
17158 | { |
17159 | c_parser_error (parser, gmsgid: "expected %<concurrent%>" ); |
17160 | goto out_err; |
17161 | } |
17162 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17163 | if (strcmp (s1: p, s2: "concurrent" ) != 0) |
17164 | { |
17165 | c_parser_error (parser, gmsgid: "expected %<concurrent%>" ); |
17166 | goto out_err; |
17167 | } |
17168 | c_parser_consume_token (parser); |
17169 | parens.skip_until_found_close (parser); |
17170 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_ORDER, name: "order" ); |
17171 | c = build_omp_clause (loc, OMP_CLAUSE_ORDER); |
17172 | OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; |
17173 | OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; |
17174 | OMP_CLAUSE_CHAIN (c) = list; |
17175 | return c; |
17176 | |
17177 | out_err: |
17178 | parens.skip_until_found_close (parser); |
17179 | return list; |
17180 | } |
17181 | |
17182 | |
17183 | /* OpenMP 5.0: |
17184 | bind ( teams | parallel | thread ) */ |
17185 | |
17186 | static tree |
17187 | c_parser_omp_clause_bind (c_parser *parser, tree list) |
17188 | { |
17189 | location_t loc = c_parser_peek_token (parser)->location; |
17190 | tree c; |
17191 | const char *p; |
17192 | enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD; |
17193 | |
17194 | matching_parens parens; |
17195 | if (!parens.require_open (parser)) |
17196 | return list; |
17197 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
17198 | { |
17199 | invalid: |
17200 | c_parser_error (parser, |
17201 | gmsgid: "expected %<teams%>, %<parallel%> or %<thread%>" ); |
17202 | parens.skip_until_found_close (parser); |
17203 | return list; |
17204 | } |
17205 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17206 | if (strcmp (s1: p, s2: "teams" ) == 0) |
17207 | kind = OMP_CLAUSE_BIND_TEAMS; |
17208 | else if (strcmp (s1: p, s2: "parallel" ) == 0) |
17209 | kind = OMP_CLAUSE_BIND_PARALLEL; |
17210 | else if (strcmp (s1: p, s2: "thread" ) != 0) |
17211 | goto invalid; |
17212 | c_parser_consume_token (parser); |
17213 | parens.skip_until_found_close (parser); |
17214 | /* check_no_duplicate_clause (list, OMP_CLAUSE_BIND, "bind"); */ |
17215 | c = build_omp_clause (loc, OMP_CLAUSE_BIND); |
17216 | OMP_CLAUSE_BIND_KIND (c) = kind; |
17217 | OMP_CLAUSE_CHAIN (c) = list; |
17218 | return c; |
17219 | } |
17220 | |
17221 | |
17222 | /* OpenMP 2.5: |
17223 | ordered |
17224 | |
17225 | OpenMP 4.5: |
17226 | ordered ( constant-expression ) */ |
17227 | |
17228 | static tree |
17229 | c_parser_omp_clause_ordered (c_parser *parser, tree list) |
17230 | { |
17231 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_ORDERED, name: "ordered" ); |
17232 | |
17233 | tree c, num = NULL_TREE; |
17234 | HOST_WIDE_INT n; |
17235 | location_t loc = c_parser_peek_token (parser)->location; |
17236 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
17237 | { |
17238 | matching_parens parens; |
17239 | parens.consume_open (parser); |
17240 | num = c_parser_expr_no_commas (parser, NULL).value; |
17241 | parens.skip_until_found_close (parser); |
17242 | } |
17243 | if (num == error_mark_node) |
17244 | return list; |
17245 | if (num) |
17246 | { |
17247 | mark_exp_read (num); |
17248 | num = c_fully_fold (num, false, NULL); |
17249 | if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) |
17250 | || !tree_fits_shwi_p (num) |
17251 | || (n = tree_to_shwi (num)) <= 0 |
17252 | || (int) n != n) |
17253 | { |
17254 | error_at (loc, "ordered argument needs positive " |
17255 | "constant integer expression" ); |
17256 | return list; |
17257 | } |
17258 | } |
17259 | c = build_omp_clause (loc, OMP_CLAUSE_ORDERED); |
17260 | OMP_CLAUSE_ORDERED_EXPR (c) = num; |
17261 | OMP_CLAUSE_CHAIN (c) = list; |
17262 | return c; |
17263 | } |
17264 | |
17265 | /* OpenMP 2.5: |
17266 | private ( variable-list ) */ |
17267 | |
17268 | static tree |
17269 | c_parser_omp_clause_private (c_parser *parser, tree list) |
17270 | { |
17271 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_PRIVATE, list); |
17272 | } |
17273 | |
17274 | /* OpenMP 2.5: |
17275 | reduction ( reduction-operator : variable-list ) |
17276 | |
17277 | reduction-operator: |
17278 | One of: + * - & ^ | && || |
17279 | |
17280 | OpenMP 3.1: |
17281 | |
17282 | reduction-operator: |
17283 | One of: + * - & ^ | && || max min |
17284 | |
17285 | OpenMP 4.0: |
17286 | |
17287 | reduction-operator: |
17288 | One of: + * - & ^ | && || |
17289 | identifier |
17290 | |
17291 | OpenMP 5.0: |
17292 | reduction ( reduction-modifier, reduction-operator : variable-list ) |
17293 | in_reduction ( reduction-operator : variable-list ) |
17294 | task_reduction ( reduction-operator : variable-list ) */ |
17295 | |
17296 | static tree |
17297 | c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, |
17298 | bool is_omp, tree list) |
17299 | { |
17300 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17301 | matching_parens parens; |
17302 | if (parens.require_open (parser)) |
17303 | { |
17304 | bool task = false; |
17305 | bool inscan = false; |
17306 | enum tree_code code = ERROR_MARK; |
17307 | tree reduc_id = NULL_TREE; |
17308 | |
17309 | if (kind == OMP_CLAUSE_REDUCTION && is_omp) |
17310 | { |
17311 | if (c_parser_next_token_is_keyword (parser, keyword: RID_DEFAULT) |
17312 | && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) |
17313 | { |
17314 | c_parser_consume_token (parser); |
17315 | c_parser_consume_token (parser); |
17316 | } |
17317 | else if (c_parser_next_token_is (parser, type: CPP_NAME) |
17318 | && c_parser_peek_2nd_token (parser)->type == CPP_COMMA) |
17319 | { |
17320 | const char *p |
17321 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17322 | if (strcmp (s1: p, s2: "task" ) == 0) |
17323 | task = true; |
17324 | else if (strcmp (s1: p, s2: "inscan" ) == 0) |
17325 | inscan = true; |
17326 | if (task || inscan) |
17327 | { |
17328 | c_parser_consume_token (parser); |
17329 | c_parser_consume_token (parser); |
17330 | } |
17331 | } |
17332 | } |
17333 | |
17334 | switch (c_parser_peek_token (parser)->type) |
17335 | { |
17336 | case CPP_PLUS: |
17337 | code = PLUS_EXPR; |
17338 | break; |
17339 | case CPP_MULT: |
17340 | code = MULT_EXPR; |
17341 | break; |
17342 | case CPP_MINUS: |
17343 | code = MINUS_EXPR; |
17344 | break; |
17345 | case CPP_AND: |
17346 | code = BIT_AND_EXPR; |
17347 | break; |
17348 | case CPP_XOR: |
17349 | code = BIT_XOR_EXPR; |
17350 | break; |
17351 | case CPP_OR: |
17352 | code = BIT_IOR_EXPR; |
17353 | break; |
17354 | case CPP_AND_AND: |
17355 | code = TRUTH_ANDIF_EXPR; |
17356 | break; |
17357 | case CPP_OR_OR: |
17358 | code = TRUTH_ORIF_EXPR; |
17359 | break; |
17360 | case CPP_NAME: |
17361 | { |
17362 | const char *p |
17363 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17364 | if (strcmp (s1: p, s2: "min" ) == 0) |
17365 | { |
17366 | code = MIN_EXPR; |
17367 | break; |
17368 | } |
17369 | if (strcmp (s1: p, s2: "max" ) == 0) |
17370 | { |
17371 | code = MAX_EXPR; |
17372 | break; |
17373 | } |
17374 | reduc_id = c_parser_peek_token (parser)->value; |
17375 | break; |
17376 | } |
17377 | default: |
17378 | c_parser_error (parser, |
17379 | gmsgid: "expected %<+%>, %<*%>, %<-%>, %<&%>, " |
17380 | "%<^%>, %<|%>, %<&&%>, %<||%> or identifier" ); |
17381 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: 0); |
17382 | return list; |
17383 | } |
17384 | c_parser_consume_token (parser); |
17385 | reduc_id = c_omp_reduction_id (code, reduc_id); |
17386 | if (c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
17387 | { |
17388 | tree nl, c; |
17389 | |
17390 | nl = c_parser_omp_variable_list (parser, clause_loc, kind, list); |
17391 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
17392 | { |
17393 | tree d = OMP_CLAUSE_DECL (c), type; |
17394 | if (TREE_CODE (d) != OMP_ARRAY_SECTION) |
17395 | type = TREE_TYPE (d); |
17396 | else |
17397 | { |
17398 | int cnt = 0; |
17399 | tree t; |
17400 | for (t = d; |
17401 | TREE_CODE (t) == OMP_ARRAY_SECTION; |
17402 | t = TREE_OPERAND (t, 0)) |
17403 | cnt++; |
17404 | type = TREE_TYPE (t); |
17405 | while (cnt > 0) |
17406 | { |
17407 | if (TREE_CODE (type) != POINTER_TYPE |
17408 | && TREE_CODE (type) != ARRAY_TYPE) |
17409 | break; |
17410 | type = TREE_TYPE (type); |
17411 | cnt--; |
17412 | } |
17413 | } |
17414 | while (TREE_CODE (type) == ARRAY_TYPE) |
17415 | type = TREE_TYPE (type); |
17416 | OMP_CLAUSE_REDUCTION_CODE (c) = code; |
17417 | if (task) |
17418 | OMP_CLAUSE_REDUCTION_TASK (c) = 1; |
17419 | else if (inscan) |
17420 | OMP_CLAUSE_REDUCTION_INSCAN (c) = 1; |
17421 | if (code == ERROR_MARK |
17422 | || !(INTEGRAL_TYPE_P (type) |
17423 | || SCALAR_FLOAT_TYPE_P (type) |
17424 | || TREE_CODE (type) == COMPLEX_TYPE)) |
17425 | OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) |
17426 | = c_omp_reduction_lookup (reduc_id, |
17427 | TYPE_MAIN_VARIANT (type)); |
17428 | } |
17429 | |
17430 | list = nl; |
17431 | } |
17432 | parens.skip_until_found_close (parser); |
17433 | } |
17434 | return list; |
17435 | } |
17436 | |
17437 | /* OpenMP 2.5: |
17438 | schedule ( schedule-kind ) |
17439 | schedule ( schedule-kind , expression ) |
17440 | |
17441 | schedule-kind: |
17442 | static | dynamic | guided | runtime | auto |
17443 | |
17444 | OpenMP 4.5: |
17445 | schedule ( schedule-modifier : schedule-kind ) |
17446 | schedule ( schedule-modifier [ , schedule-modifier ] : schedule-kind , expression ) |
17447 | |
17448 | schedule-modifier: |
17449 | simd |
17450 | monotonic |
17451 | nonmonotonic */ |
17452 | |
17453 | static tree |
17454 | c_parser_omp_clause_schedule (c_parser *parser, tree list) |
17455 | { |
17456 | tree c, t; |
17457 | location_t loc = c_parser_peek_token (parser)->location; |
17458 | int modifiers = 0, nmodifiers = 0; |
17459 | |
17460 | matching_parens parens; |
17461 | if (!parens.require_open (parser)) |
17462 | return list; |
17463 | |
17464 | c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE); |
17465 | |
17466 | location_t comma = UNKNOWN_LOCATION; |
17467 | while (c_parser_next_token_is (parser, type: CPP_NAME)) |
17468 | { |
17469 | tree kind = c_parser_peek_token (parser)->value; |
17470 | const char *p = IDENTIFIER_POINTER (kind); |
17471 | if (strcmp (s1: "simd" , s2: p) == 0) |
17472 | OMP_CLAUSE_SCHEDULE_SIMD (c) = 1; |
17473 | else if (strcmp (s1: "monotonic" , s2: p) == 0) |
17474 | modifiers |= OMP_CLAUSE_SCHEDULE_MONOTONIC; |
17475 | else if (strcmp (s1: "nonmonotonic" , s2: p) == 0) |
17476 | modifiers |= OMP_CLAUSE_SCHEDULE_NONMONOTONIC; |
17477 | else |
17478 | break; |
17479 | comma = UNKNOWN_LOCATION; |
17480 | c_parser_consume_token (parser); |
17481 | if (nmodifiers++ == 0 |
17482 | && c_parser_next_token_is (parser, type: CPP_COMMA)) |
17483 | { |
17484 | comma = c_parser_peek_token (parser)->location; |
17485 | c_parser_consume_token (parser); |
17486 | } |
17487 | else |
17488 | { |
17489 | c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" ); |
17490 | break; |
17491 | } |
17492 | } |
17493 | if (comma != UNKNOWN_LOCATION) |
17494 | error_at (comma, "expected %<:%>" ); |
17495 | |
17496 | if ((modifiers & (OMP_CLAUSE_SCHEDULE_MONOTONIC |
17497 | | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) |
17498 | == (OMP_CLAUSE_SCHEDULE_MONOTONIC |
17499 | | OMP_CLAUSE_SCHEDULE_NONMONOTONIC)) |
17500 | { |
17501 | error_at (loc, "both %<monotonic%> and %<nonmonotonic%> modifiers " |
17502 | "specified" ); |
17503 | modifiers = 0; |
17504 | } |
17505 | |
17506 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
17507 | { |
17508 | tree kind = c_parser_peek_token (parser)->value; |
17509 | const char *p = IDENTIFIER_POINTER (kind); |
17510 | |
17511 | switch (p[0]) |
17512 | { |
17513 | case 'd': |
17514 | if (strcmp (s1: "dynamic" , s2: p) != 0) |
17515 | goto invalid_kind; |
17516 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC; |
17517 | break; |
17518 | |
17519 | case 'g': |
17520 | if (strcmp (s1: "guided" , s2: p) != 0) |
17521 | goto invalid_kind; |
17522 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED; |
17523 | break; |
17524 | |
17525 | case 'r': |
17526 | if (strcmp (s1: "runtime" , s2: p) != 0) |
17527 | goto invalid_kind; |
17528 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME; |
17529 | break; |
17530 | |
17531 | default: |
17532 | goto invalid_kind; |
17533 | } |
17534 | } |
17535 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_STATIC)) |
17536 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC; |
17537 | else if (c_parser_next_token_is_keyword (parser, keyword: RID_AUTO)) |
17538 | OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO; |
17539 | else |
17540 | goto invalid_kind; |
17541 | |
17542 | c_parser_consume_token (parser); |
17543 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
17544 | { |
17545 | location_t here; |
17546 | c_parser_consume_token (parser); |
17547 | |
17548 | here = c_parser_peek_token (parser)->location; |
17549 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17550 | expr = convert_lvalue_to_rvalue (here, expr, false, true); |
17551 | t = expr.value; |
17552 | t = c_fully_fold (t, false, NULL); |
17553 | |
17554 | if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME) |
17555 | error_at (here, "schedule %<runtime%> does not take " |
17556 | "a %<chunk_size%> parameter" ); |
17557 | else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO) |
17558 | error_at (here, |
17559 | "schedule %<auto%> does not take " |
17560 | "a %<chunk_size%> parameter" ); |
17561 | else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE |
17562 | || TREE_CODE (TREE_TYPE (t)) == BITINT_TYPE) |
17563 | { |
17564 | /* Attempt to statically determine when the number isn't |
17565 | positive. */ |
17566 | tree s = fold_build2_loc (loc, LE_EXPR, boolean_type_node, t, |
17567 | build_int_cst (TREE_TYPE (t), 0)); |
17568 | protected_set_expr_location (s, loc); |
17569 | if (s == boolean_true_node) |
17570 | { |
17571 | warning_at (loc, OPT_Wopenmp, |
17572 | "chunk size value must be positive" ); |
17573 | t = integer_one_node; |
17574 | } |
17575 | OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; |
17576 | } |
17577 | else |
17578 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
17579 | |
17580 | parens.skip_until_found_close (parser); |
17581 | } |
17582 | else |
17583 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
17584 | msgid: "expected %<,%> or %<)%>" ); |
17585 | |
17586 | OMP_CLAUSE_SCHEDULE_KIND (c) |
17587 | = (enum omp_clause_schedule_kind) |
17588 | (OMP_CLAUSE_SCHEDULE_KIND (c) | modifiers); |
17589 | |
17590 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_SCHEDULE, name: "schedule" ); |
17591 | OMP_CLAUSE_CHAIN (c) = list; |
17592 | return c; |
17593 | |
17594 | invalid_kind: |
17595 | c_parser_error (parser, gmsgid: "invalid schedule kind" ); |
17596 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, msgid: 0); |
17597 | return list; |
17598 | } |
17599 | |
17600 | /* OpenMP 2.5: |
17601 | shared ( variable-list ) */ |
17602 | |
17603 | static tree |
17604 | c_parser_omp_clause_shared (c_parser *parser, tree list) |
17605 | { |
17606 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_SHARED, list); |
17607 | } |
17608 | |
17609 | /* OpenMP 3.0: |
17610 | untied */ |
17611 | |
17612 | static tree |
17613 | c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
17614 | { |
17615 | tree c; |
17616 | |
17617 | /* FIXME: Should we allow duplicates? */ |
17618 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_UNTIED, name: "untied" ); |
17619 | |
17620 | c = build_omp_clause (c_parser_peek_token (parser)->location, |
17621 | OMP_CLAUSE_UNTIED); |
17622 | OMP_CLAUSE_CHAIN (c) = list; |
17623 | |
17624 | return c; |
17625 | } |
17626 | |
17627 | /* OpenMP 4.0: |
17628 | inbranch |
17629 | notinbranch */ |
17630 | |
17631 | static tree |
17632 | c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED, |
17633 | enum omp_clause_code code, tree list) |
17634 | { |
17635 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
17636 | |
17637 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); |
17638 | OMP_CLAUSE_CHAIN (c) = list; |
17639 | |
17640 | return c; |
17641 | } |
17642 | |
17643 | /* OpenMP 4.0: |
17644 | parallel |
17645 | for |
17646 | sections |
17647 | taskgroup */ |
17648 | |
17649 | static tree |
17650 | c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED, |
17651 | enum omp_clause_code code, tree list) |
17652 | { |
17653 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); |
17654 | OMP_CLAUSE_CHAIN (c) = list; |
17655 | |
17656 | return c; |
17657 | } |
17658 | |
17659 | /* OpenMP 4.5: |
17660 | nogroup */ |
17661 | |
17662 | static tree |
17663 | c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list) |
17664 | { |
17665 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NOGROUP, name: "nogroup" ); |
17666 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, |
17667 | OMP_CLAUSE_NOGROUP); |
17668 | OMP_CLAUSE_CHAIN (c) = list; |
17669 | return c; |
17670 | } |
17671 | |
17672 | /* OpenMP 4.5: |
17673 | simd |
17674 | threads */ |
17675 | |
17676 | static tree |
17677 | c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED, |
17678 | enum omp_clause_code code, tree list) |
17679 | { |
17680 | check_no_duplicate_clause (clauses: list, code, name: omp_clause_code_name[code]); |
17681 | tree c = build_omp_clause (c_parser_peek_token (parser)->location, code); |
17682 | OMP_CLAUSE_CHAIN (c) = list; |
17683 | return c; |
17684 | } |
17685 | |
17686 | /* OpenMP 4.0: |
17687 | num_teams ( expression ) |
17688 | |
17689 | OpenMP 5.1: |
17690 | num_teams ( expression : expression ) */ |
17691 | |
17692 | static tree |
17693 | c_parser_omp_clause_num_teams (c_parser *parser, tree list) |
17694 | { |
17695 | location_t num_teams_loc = c_parser_peek_token (parser)->location; |
17696 | matching_parens parens; |
17697 | if (parens.require_open (parser)) |
17698 | { |
17699 | location_t upper_loc = c_parser_peek_token (parser)->location; |
17700 | location_t lower_loc = UNKNOWN_LOCATION; |
17701 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17702 | expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); |
17703 | tree c, upper = expr.value, lower = NULL_TREE; |
17704 | upper = c_fully_fold (upper, false, NULL); |
17705 | |
17706 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
17707 | { |
17708 | c_parser_consume_token (parser); |
17709 | lower_loc = upper_loc; |
17710 | lower = upper; |
17711 | upper_loc = c_parser_peek_token (parser)->location; |
17712 | expr = c_parser_expr_no_commas (parser, NULL); |
17713 | expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true); |
17714 | upper = expr.value; |
17715 | upper = c_fully_fold (upper, false, NULL); |
17716 | } |
17717 | |
17718 | parens.skip_until_found_close (parser); |
17719 | |
17720 | if (!INTEGRAL_TYPE_P (TREE_TYPE (upper)) |
17721 | || (lower && !INTEGRAL_TYPE_P (TREE_TYPE (lower)))) |
17722 | { |
17723 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
17724 | return list; |
17725 | } |
17726 | |
17727 | /* Attempt to statically determine when the number isn't positive. */ |
17728 | c = fold_build2_loc (upper_loc, LE_EXPR, boolean_type_node, upper, |
17729 | build_int_cst (TREE_TYPE (upper), 0)); |
17730 | protected_set_expr_location (c, upper_loc); |
17731 | if (c == boolean_true_node) |
17732 | { |
17733 | warning_at (upper_loc, OPT_Wopenmp, |
17734 | "%<num_teams%> value must be positive" ); |
17735 | upper = integer_one_node; |
17736 | } |
17737 | if (lower) |
17738 | { |
17739 | c = fold_build2_loc (lower_loc, LE_EXPR, boolean_type_node, lower, |
17740 | build_int_cst (TREE_TYPE (lower), 0)); |
17741 | protected_set_expr_location (c, lower_loc); |
17742 | if (c == boolean_true_node) |
17743 | { |
17744 | warning_at (lower_loc, OPT_Wopenmp, |
17745 | "%<num_teams%> value must be positive" ); |
17746 | lower = NULL_TREE; |
17747 | } |
17748 | else if (TREE_CODE (lower) == INTEGER_CST |
17749 | && TREE_CODE (upper) == INTEGER_CST |
17750 | && tree_int_cst_lt (t1: upper, t2: lower)) |
17751 | { |
17752 | warning_at (lower_loc, OPT_Wopenmp, |
17753 | "%<num_teams%> lower bound %qE bigger than upper " |
17754 | "bound %qE" , lower, upper); |
17755 | lower = NULL_TREE; |
17756 | } |
17757 | } |
17758 | |
17759 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_NUM_TEAMS, name: "num_teams" ); |
17760 | |
17761 | c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); |
17762 | OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (c) = upper; |
17763 | OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) = lower; |
17764 | OMP_CLAUSE_CHAIN (c) = list; |
17765 | list = c; |
17766 | } |
17767 | |
17768 | return list; |
17769 | } |
17770 | |
17771 | /* OpenMP 4.0: |
17772 | thread_limit ( expression ) */ |
17773 | |
17774 | static tree |
17775 | c_parser_omp_clause_thread_limit (c_parser *parser, tree list) |
17776 | { |
17777 | location_t num_thread_limit_loc = c_parser_peek_token (parser)->location; |
17778 | matching_parens parens; |
17779 | if (parens.require_open (parser)) |
17780 | { |
17781 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17782 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17783 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17784 | tree c, t = expr.value; |
17785 | t = c_fully_fold (t, false, NULL); |
17786 | |
17787 | parens.skip_until_found_close (parser); |
17788 | |
17789 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
17790 | { |
17791 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
17792 | return list; |
17793 | } |
17794 | |
17795 | /* Attempt to statically determine when the number isn't positive. */ |
17796 | c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, |
17797 | build_int_cst (TREE_TYPE (t), 0)); |
17798 | protected_set_expr_location (c, expr_loc); |
17799 | if (c == boolean_true_node) |
17800 | { |
17801 | warning_at (expr_loc, OPT_Wopenmp, |
17802 | "%<thread_limit%> value must be positive" ); |
17803 | t = integer_one_node; |
17804 | } |
17805 | |
17806 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_THREAD_LIMIT, |
17807 | name: "thread_limit" ); |
17808 | |
17809 | c = build_omp_clause (num_thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT); |
17810 | OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; |
17811 | OMP_CLAUSE_CHAIN (c) = list; |
17812 | list = c; |
17813 | } |
17814 | |
17815 | return list; |
17816 | } |
17817 | |
17818 | /* OpenMP 4.0: |
17819 | aligned ( variable-list ) |
17820 | aligned ( variable-list : constant-expression ) */ |
17821 | |
17822 | static tree |
17823 | c_parser_omp_clause_aligned (c_parser *parser, tree list) |
17824 | { |
17825 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17826 | tree nl, c; |
17827 | |
17828 | matching_parens parens; |
17829 | if (!parens.require_open (parser)) |
17830 | return list; |
17831 | |
17832 | nl = c_parser_omp_variable_list (parser, clause_loc, |
17833 | kind: OMP_CLAUSE_ALIGNED, list); |
17834 | |
17835 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
17836 | { |
17837 | c_parser_consume_token (parser); |
17838 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17839 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17840 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17841 | tree alignment = expr.value; |
17842 | alignment = c_fully_fold (alignment, false, NULL); |
17843 | if (TREE_CODE (alignment) != INTEGER_CST |
17844 | || !INTEGRAL_TYPE_P (TREE_TYPE (alignment)) |
17845 | || tree_int_cst_sgn (alignment) != 1) |
17846 | { |
17847 | error_at (clause_loc, "%<aligned%> clause alignment expression must " |
17848 | "be positive constant integer expression" ); |
17849 | alignment = NULL_TREE; |
17850 | } |
17851 | |
17852 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
17853 | OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment; |
17854 | } |
17855 | |
17856 | parens.skip_until_found_close (parser); |
17857 | return nl; |
17858 | } |
17859 | |
17860 | /* OpenMP 5.0: |
17861 | allocate ( variable-list ) |
17862 | allocate ( expression : variable-list ) |
17863 | |
17864 | OpenMP 5.1: |
17865 | allocate ( allocator-modifier : variable-list ) |
17866 | allocate ( allocator-modifier , allocator-modifier : variable-list ) |
17867 | |
17868 | allocator-modifier: |
17869 | allocator ( expression ) |
17870 | align ( expression ) */ |
17871 | |
17872 | static tree |
17873 | c_parser_omp_clause_allocate (c_parser *parser, tree list) |
17874 | { |
17875 | location_t clause_loc = c_parser_peek_token (parser)->location; |
17876 | tree nl, c; |
17877 | tree allocator = NULL_TREE; |
17878 | tree align = NULL_TREE; |
17879 | |
17880 | matching_parens parens; |
17881 | if (!parens.require_open (parser)) |
17882 | return list; |
17883 | |
17884 | if ((c_parser_next_token_is_not (parser, type: CPP_NAME) |
17885 | && c_parser_next_token_is_not (parser, type: CPP_KEYWORD)) |
17886 | || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA |
17887 | && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)) |
17888 | { |
17889 | bool has_modifiers = false; |
17890 | tree orig_type = NULL_TREE; |
17891 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
17892 | && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
17893 | { |
17894 | unsigned int n = 3; |
17895 | const char *p |
17896 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
17897 | if ((strcmp (s1: p, s2: "allocator" ) == 0 || strcmp (s1: p, s2: "align" ) == 0) |
17898 | && c_parser_check_balanced_raw_token_sequence (parser, n: &n) |
17899 | && (c_parser_peek_nth_token_raw (parser, n)->type |
17900 | == CPP_CLOSE_PAREN)) |
17901 | { |
17902 | if (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
17903 | == CPP_COLON) |
17904 | has_modifiers = true; |
17905 | else if (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
17906 | == CPP_COMMA |
17907 | && (c_parser_peek_nth_token_raw (parser, n: n + 2)->type |
17908 | == CPP_NAME) |
17909 | && (c_parser_peek_nth_token_raw (parser, n: n + 3)->type |
17910 | == CPP_OPEN_PAREN)) |
17911 | { |
17912 | c_token *tok = c_parser_peek_nth_token_raw (parser, n: n + 2); |
17913 | const char *q = IDENTIFIER_POINTER (tok->value); |
17914 | n += 4; |
17915 | if ((strcmp (s1: q, s2: "allocator" ) == 0 |
17916 | || strcmp (s1: q, s2: "align" ) == 0) |
17917 | && c_parser_check_balanced_raw_token_sequence (parser, |
17918 | n: &n) |
17919 | && (c_parser_peek_nth_token_raw (parser, n)->type |
17920 | == CPP_CLOSE_PAREN) |
17921 | && (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
17922 | == CPP_COLON)) |
17923 | has_modifiers = true; |
17924 | } |
17925 | } |
17926 | if (has_modifiers) |
17927 | { |
17928 | c_parser_consume_token (parser); |
17929 | matching_parens parens2;; |
17930 | parens2.require_open (parser); |
17931 | location_t expr_loc = c_parser_peek_token (parser)->location; |
17932 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
17933 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
17934 | if (expr.value == error_mark_node) |
17935 | ; |
17936 | else if (strcmp (s1: p, s2: "allocator" ) == 0) |
17937 | { |
17938 | allocator = expr.value; |
17939 | allocator = c_fully_fold (allocator, false, NULL); |
17940 | orig_type = expr.original_type |
17941 | ? expr.original_type : TREE_TYPE (allocator); |
17942 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
17943 | } |
17944 | else |
17945 | { |
17946 | align = expr.value; |
17947 | align = c_fully_fold (align, false, NULL); |
17948 | } |
17949 | parens2.skip_until_found_close (parser); |
17950 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
17951 | { |
17952 | c_parser_consume_token (parser); |
17953 | c_token *tok = c_parser_peek_token (parser); |
17954 | const char *q = "" ; |
17955 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
17956 | q = IDENTIFIER_POINTER (tok->value); |
17957 | if (strcmp (s1: q, s2: "allocator" ) != 0 && strcmp (s1: q, s2: "align" ) != 0) |
17958 | { |
17959 | c_parser_error (parser, gmsgid: "expected %<allocator%> or " |
17960 | "%<align%>" ); |
17961 | parens.skip_until_found_close (parser); |
17962 | return list; |
17963 | } |
17964 | else if (strcmp (s1: p, s2: q) == 0) |
17965 | { |
17966 | error_at (tok->location, "duplicate %qs modifier" , p); |
17967 | parens.skip_until_found_close (parser); |
17968 | return list; |
17969 | } |
17970 | c_parser_consume_token (parser); |
17971 | if (!parens2.require_open (parser)) |
17972 | { |
17973 | parens.skip_until_found_close (parser); |
17974 | return list; |
17975 | } |
17976 | expr_loc = c_parser_peek_token (parser)->location; |
17977 | expr = c_parser_expr_no_commas (parser, NULL); |
17978 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, |
17979 | true); |
17980 | if (strcmp (s1: q, s2: "allocator" ) == 0) |
17981 | { |
17982 | allocator = expr.value; |
17983 | allocator = c_fully_fold (allocator, false, NULL); |
17984 | orig_type = expr.original_type |
17985 | ? expr.original_type : TREE_TYPE (allocator); |
17986 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
17987 | } |
17988 | else |
17989 | { |
17990 | align = expr.value; |
17991 | align = c_fully_fold (align, false, NULL); |
17992 | } |
17993 | parens2.skip_until_found_close (parser); |
17994 | } |
17995 | } |
17996 | } |
17997 | if (!has_modifiers) |
17998 | { |
17999 | location_t expr_loc = c_parser_peek_token (parser)->location; |
18000 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18001 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18002 | allocator = expr.value; |
18003 | allocator = c_fully_fold (allocator, false, NULL); |
18004 | orig_type = expr.original_type |
18005 | ? expr.original_type : TREE_TYPE (allocator); |
18006 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
18007 | } |
18008 | if (allocator |
18009 | && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) |
18010 | || TREE_CODE (orig_type) != ENUMERAL_TYPE |
18011 | || (TYPE_NAME (orig_type) |
18012 | != get_identifier ("omp_allocator_handle_t" )))) |
18013 | { |
18014 | error_at (clause_loc, "%<allocate%> clause allocator expression " |
18015 | "has type %qT rather than " |
18016 | "%<omp_allocator_handle_t%>" , |
18017 | TREE_TYPE (allocator)); |
18018 | allocator = NULL_TREE; |
18019 | } |
18020 | if (align |
18021 | && (!INTEGRAL_TYPE_P (TREE_TYPE (align)) |
18022 | || !tree_fits_uhwi_p (align) |
18023 | || !integer_pow2p (align))) |
18024 | { |
18025 | error_at (clause_loc, "%<allocate%> clause %<align%> modifier " |
18026 | "argument needs to be positive constant " |
18027 | "power of two integer expression" ); |
18028 | align = NULL_TREE; |
18029 | } |
18030 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18031 | { |
18032 | parens.skip_until_found_close (parser); |
18033 | return list; |
18034 | } |
18035 | } |
18036 | |
18037 | nl = c_parser_omp_variable_list (parser, clause_loc, |
18038 | kind: OMP_CLAUSE_ALLOCATE, list); |
18039 | |
18040 | if (allocator || align) |
18041 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18042 | { |
18043 | OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; |
18044 | OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; |
18045 | } |
18046 | |
18047 | parens.skip_until_found_close (parser); |
18048 | return nl; |
18049 | } |
18050 | |
18051 | /* OpenMP 4.0: |
18052 | linear ( variable-list ) |
18053 | linear ( variable-list : expression ) |
18054 | |
18055 | OpenMP 4.5: |
18056 | linear ( modifier ( variable-list ) ) |
18057 | linear ( modifier ( variable-list ) : expression ) |
18058 | |
18059 | modifier: |
18060 | val |
18061 | |
18062 | OpenMP 5.2: |
18063 | linear ( variable-list : modifiers-list ) |
18064 | |
18065 | modifiers: |
18066 | val |
18067 | step ( expression ) */ |
18068 | |
18069 | static tree |
18070 | c_parser_omp_clause_linear (c_parser *parser, tree list) |
18071 | { |
18072 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18073 | tree nl, c, step; |
18074 | enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT; |
18075 | bool old_linear_modifier = false; |
18076 | |
18077 | matching_parens parens; |
18078 | if (!parens.require_open (parser)) |
18079 | return list; |
18080 | |
18081 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
18082 | { |
18083 | c_token *tok = c_parser_peek_token (parser); |
18084 | const char *p = IDENTIFIER_POINTER (tok->value); |
18085 | if (strcmp (s1: "val" , s2: p) == 0) |
18086 | kind = OMP_CLAUSE_LINEAR_VAL; |
18087 | if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN) |
18088 | kind = OMP_CLAUSE_LINEAR_DEFAULT; |
18089 | if (kind != OMP_CLAUSE_LINEAR_DEFAULT) |
18090 | { |
18091 | old_linear_modifier = true; |
18092 | c_parser_consume_token (parser); |
18093 | c_parser_consume_token (parser); |
18094 | } |
18095 | } |
18096 | |
18097 | nl = c_parser_omp_variable_list (parser, clause_loc, |
18098 | kind: OMP_CLAUSE_LINEAR, list); |
18099 | |
18100 | if (kind != OMP_CLAUSE_LINEAR_DEFAULT) |
18101 | parens.skip_until_found_close (parser); |
18102 | |
18103 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
18104 | { |
18105 | c_parser_consume_token (parser); |
18106 | location_t expr_loc = c_parser_peek_token (parser)->location; |
18107 | bool has_modifiers = false; |
18108 | if (kind == OMP_CLAUSE_LINEAR_DEFAULT |
18109 | && c_parser_next_token_is (parser, type: CPP_NAME)) |
18110 | { |
18111 | c_token *tok = c_parser_peek_token (parser); |
18112 | const char *p = IDENTIFIER_POINTER (tok->value); |
18113 | unsigned int pos = 0; |
18114 | if (strcmp (s1: "val" , s2: p) == 0) |
18115 | pos = 2; |
18116 | else if (strcmp (s1: "step" , s2: p) == 0 |
18117 | && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
18118 | { |
18119 | pos = 3; |
18120 | if (c_parser_check_balanced_raw_token_sequence (parser, n: &pos) |
18121 | && (c_parser_peek_nth_token_raw (parser, n: pos)->type |
18122 | == CPP_CLOSE_PAREN)) |
18123 | ++pos; |
18124 | else |
18125 | pos = 0; |
18126 | } |
18127 | if (pos) |
18128 | { |
18129 | tok = c_parser_peek_nth_token_raw (parser, n: pos); |
18130 | if (tok->type == CPP_COMMA || tok->type == CPP_CLOSE_PAREN) |
18131 | has_modifiers = true; |
18132 | } |
18133 | } |
18134 | if (has_modifiers) |
18135 | { |
18136 | step = NULL_TREE; |
18137 | while (c_parser_next_token_is (parser, type: CPP_NAME)) |
18138 | { |
18139 | c_token *tok = c_parser_peek_token (parser); |
18140 | const char *p = IDENTIFIER_POINTER (tok->value); |
18141 | if (strcmp (s1: "val" , s2: p) == 0) |
18142 | { |
18143 | if (kind != OMP_CLAUSE_LINEAR_DEFAULT) |
18144 | error_at (tok->location, "multiple linear modifiers" ); |
18145 | kind = OMP_CLAUSE_LINEAR_DEFAULT; |
18146 | c_parser_consume_token (parser); |
18147 | } |
18148 | else if (strcmp (s1: "step" , s2: p) == 0) |
18149 | { |
18150 | c_parser_consume_token (parser); |
18151 | matching_parens parens2; |
18152 | if (parens2.require_open (parser)) |
18153 | { |
18154 | if (step) |
18155 | error_at (tok->location, |
18156 | "multiple %<step%> modifiers" ); |
18157 | expr_loc = c_parser_peek_token (parser)->location; |
18158 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18159 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, |
18160 | true); |
18161 | step = c_fully_fold (expr.value, false, NULL); |
18162 | if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) |
18163 | { |
18164 | error_at (clause_loc, "%<linear%> clause step " |
18165 | "expression must be integral" ); |
18166 | step = integer_one_node; |
18167 | } |
18168 | parens2.skip_until_found_close (parser); |
18169 | } |
18170 | else |
18171 | break; |
18172 | } |
18173 | else |
18174 | break; |
18175 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
18176 | { |
18177 | c_parser_consume_token (parser); |
18178 | continue; |
18179 | } |
18180 | break; |
18181 | } |
18182 | if (!step) |
18183 | step = integer_one_node; |
18184 | } |
18185 | else |
18186 | { |
18187 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18188 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18189 | step = c_fully_fold (expr.value, false, NULL); |
18190 | if (!INTEGRAL_TYPE_P (TREE_TYPE (step))) |
18191 | { |
18192 | error_at (clause_loc, "%<linear%> clause step expression must " |
18193 | "be integral" ); |
18194 | step = integer_one_node; |
18195 | } |
18196 | } |
18197 | |
18198 | } |
18199 | else |
18200 | step = integer_one_node; |
18201 | |
18202 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18203 | { |
18204 | OMP_CLAUSE_LINEAR_STEP (c) = step; |
18205 | OMP_CLAUSE_LINEAR_KIND (c) = kind; |
18206 | OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (c) = old_linear_modifier; |
18207 | } |
18208 | |
18209 | parens.skip_until_found_close (parser); |
18210 | return nl; |
18211 | } |
18212 | |
18213 | /* OpenMP 5.0: |
18214 | nontemporal ( variable-list ) */ |
18215 | |
18216 | static tree |
18217 | c_parser_omp_clause_nontemporal (c_parser *parser, tree list) |
18218 | { |
18219 | return c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_NONTEMPORAL, list); |
18220 | } |
18221 | |
18222 | /* OpenMP 4.0: |
18223 | safelen ( constant-expression ) */ |
18224 | |
18225 | static tree |
18226 | c_parser_omp_clause_safelen (c_parser *parser, tree list) |
18227 | { |
18228 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18229 | tree c, t; |
18230 | |
18231 | matching_parens parens; |
18232 | if (!parens.require_open (parser)) |
18233 | return list; |
18234 | |
18235 | location_t expr_loc = c_parser_peek_token (parser)->location; |
18236 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18237 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18238 | t = expr.value; |
18239 | t = c_fully_fold (t, false, NULL); |
18240 | if (TREE_CODE (t) != INTEGER_CST |
18241 | || !INTEGRAL_TYPE_P (TREE_TYPE (t)) |
18242 | || tree_int_cst_sgn (t) != 1) |
18243 | { |
18244 | error_at (clause_loc, "%<safelen%> clause expression must " |
18245 | "be positive constant integer expression" ); |
18246 | t = NULL_TREE; |
18247 | } |
18248 | |
18249 | parens.skip_until_found_close (parser); |
18250 | if (t == NULL_TREE || t == error_mark_node) |
18251 | return list; |
18252 | |
18253 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_SAFELEN, name: "safelen" ); |
18254 | |
18255 | c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN); |
18256 | OMP_CLAUSE_SAFELEN_EXPR (c) = t; |
18257 | OMP_CLAUSE_CHAIN (c) = list; |
18258 | return c; |
18259 | } |
18260 | |
18261 | /* OpenMP 4.0: |
18262 | simdlen ( constant-expression ) */ |
18263 | |
18264 | static tree |
18265 | c_parser_omp_clause_simdlen (c_parser *parser, tree list) |
18266 | { |
18267 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18268 | tree c, t; |
18269 | |
18270 | matching_parens parens; |
18271 | if (!parens.require_open (parser)) |
18272 | return list; |
18273 | |
18274 | location_t expr_loc = c_parser_peek_token (parser)->location; |
18275 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18276 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18277 | t = expr.value; |
18278 | t = c_fully_fold (t, false, NULL); |
18279 | if (TREE_CODE (t) != INTEGER_CST |
18280 | || !INTEGRAL_TYPE_P (TREE_TYPE (t)) |
18281 | || tree_int_cst_sgn (t) != 1) |
18282 | { |
18283 | error_at (clause_loc, "%<simdlen%> clause expression must " |
18284 | "be positive constant integer expression" ); |
18285 | t = NULL_TREE; |
18286 | } |
18287 | |
18288 | parens.skip_until_found_close (parser); |
18289 | if (t == NULL_TREE || t == error_mark_node) |
18290 | return list; |
18291 | |
18292 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_SIMDLEN, name: "simdlen" ); |
18293 | |
18294 | c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN); |
18295 | OMP_CLAUSE_SIMDLEN_EXPR (c) = t; |
18296 | OMP_CLAUSE_CHAIN (c) = list; |
18297 | return c; |
18298 | } |
18299 | |
18300 | /* OpenMP 4.5: |
18301 | vec: |
18302 | identifier [+/- integer] |
18303 | vec , identifier [+/- integer] |
18304 | */ |
18305 | |
18306 | static tree |
18307 | c_parser_omp_clause_doacross_sink (c_parser *parser, location_t clause_loc, |
18308 | tree list, bool depend_p) |
18309 | { |
18310 | tree vec = NULL; |
18311 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
18312 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
18313 | { |
18314 | c_parser_error (parser, gmsgid: "expected identifier" ); |
18315 | return list; |
18316 | } |
18317 | |
18318 | if (!depend_p) |
18319 | { |
18320 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18321 | if (strcmp (s1: p, s2: "omp_cur_iteration" ) == 0 |
18322 | && c_parser_peek_2nd_token (parser)->type == CPP_MINUS |
18323 | && c_parser_peek_nth_token (parser, n: 3)->type == CPP_NUMBER |
18324 | && c_parser_peek_nth_token (parser, n: 4)->type == CPP_CLOSE_PAREN) |
18325 | { |
18326 | tree val = c_parser_peek_nth_token (parser, n: 3)->value; |
18327 | if (integer_onep (val)) |
18328 | { |
18329 | c_parser_consume_token (parser); |
18330 | c_parser_consume_token (parser); |
18331 | c_parser_consume_token (parser); |
18332 | tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
18333 | OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; |
18334 | OMP_CLAUSE_CHAIN (u) = list; |
18335 | return u; |
18336 | } |
18337 | } |
18338 | } |
18339 | |
18340 | |
18341 | |
18342 | while (c_parser_next_token_is (parser, type: CPP_NAME) |
18343 | && c_parser_peek_token (parser)->id_kind == C_ID_ID) |
18344 | { |
18345 | tree t = lookup_name (c_parser_peek_token (parser)->value); |
18346 | tree addend = NULL; |
18347 | |
18348 | if (t == NULL_TREE) |
18349 | { |
18350 | undeclared_variable (c_parser_peek_token (parser)->location, |
18351 | c_parser_peek_token (parser)->value); |
18352 | t = error_mark_node; |
18353 | } |
18354 | |
18355 | c_parser_consume_token (parser); |
18356 | |
18357 | bool neg = false; |
18358 | if (c_parser_next_token_is (parser, type: CPP_MINUS)) |
18359 | neg = true; |
18360 | else if (!c_parser_next_token_is (parser, type: CPP_PLUS)) |
18361 | { |
18362 | addend = integer_zero_node; |
18363 | neg = false; |
18364 | goto add_to_vector; |
18365 | } |
18366 | c_parser_consume_token (parser); |
18367 | |
18368 | if (c_parser_next_token_is_not (parser, type: CPP_NUMBER)) |
18369 | { |
18370 | c_parser_error (parser, gmsgid: "expected integer" ); |
18371 | return list; |
18372 | } |
18373 | |
18374 | addend = c_parser_peek_token (parser)->value; |
18375 | if (TREE_CODE (addend) != INTEGER_CST) |
18376 | { |
18377 | c_parser_error (parser, gmsgid: "expected integer" ); |
18378 | return list; |
18379 | } |
18380 | c_parser_consume_token (parser); |
18381 | |
18382 | add_to_vector: |
18383 | if (t != error_mark_node) |
18384 | { |
18385 | vec = tree_cons (addend, t, vec); |
18386 | if (neg) |
18387 | OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1; |
18388 | } |
18389 | |
18390 | if (c_parser_next_token_is_not (parser, type: CPP_COMMA) |
18391 | || c_parser_peek_2nd_token (parser)->type != CPP_NAME |
18392 | || c_parser_peek_2nd_token (parser)->id_kind != C_ID_ID) |
18393 | break; |
18394 | |
18395 | c_parser_consume_token (parser); |
18396 | } |
18397 | |
18398 | if (vec == NULL_TREE) |
18399 | return list; |
18400 | |
18401 | tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
18402 | OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; |
18403 | OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p; |
18404 | OMP_CLAUSE_DECL (u) = nreverse (vec); |
18405 | OMP_CLAUSE_CHAIN (u) = list; |
18406 | return u; |
18407 | } |
18408 | |
18409 | /* OpenMP 5.0: |
18410 | iterators ( iterators-definition ) |
18411 | |
18412 | iterators-definition: |
18413 | iterator-specifier |
18414 | iterator-specifier , iterators-definition |
18415 | |
18416 | iterator-specifier: |
18417 | identifier = range-specification |
18418 | iterator-type identifier = range-specification |
18419 | |
18420 | range-specification: |
18421 | begin : end |
18422 | begin : end : step */ |
18423 | |
18424 | static tree |
18425 | c_parser_omp_iterators (c_parser *parser) |
18426 | { |
18427 | tree ret = NULL_TREE, *last = &ret; |
18428 | c_parser_consume_token (parser); |
18429 | |
18430 | push_scope (); |
18431 | |
18432 | matching_parens parens; |
18433 | if (!parens.require_open (parser)) |
18434 | return error_mark_node; |
18435 | |
18436 | do |
18437 | { |
18438 | tree iter_type = NULL_TREE, type_expr = NULL_TREE; |
18439 | if (c_parser_next_tokens_start_typename (parser, la: cla_prefer_id)) |
18440 | { |
18441 | struct c_type_name *type = c_parser_type_name (parser); |
18442 | if (type != NULL) |
18443 | iter_type = groktypename (type, &type_expr, NULL); |
18444 | } |
18445 | if (iter_type == NULL_TREE) |
18446 | iter_type = integer_type_node; |
18447 | |
18448 | location_t loc = c_parser_peek_token (parser)->location; |
18449 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
18450 | { |
18451 | c_parser_error (parser, gmsgid: "expected identifier" ); |
18452 | break; |
18453 | } |
18454 | |
18455 | tree id = c_parser_peek_token (parser)->value; |
18456 | c_parser_consume_token (parser); |
18457 | |
18458 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
18459 | break; |
18460 | |
18461 | location_t eloc = c_parser_peek_token (parser)->location; |
18462 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
18463 | expr = convert_lvalue_to_rvalue (eloc, expr, true, false); |
18464 | tree begin = expr.value; |
18465 | |
18466 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18467 | break; |
18468 | |
18469 | eloc = c_parser_peek_token (parser)->location; |
18470 | expr = c_parser_expr_no_commas (parser, NULL); |
18471 | expr = convert_lvalue_to_rvalue (eloc, expr, true, false); |
18472 | tree end = expr.value; |
18473 | |
18474 | tree step = integer_one_node; |
18475 | if (c_parser_next_token_is (parser, type: CPP_COLON)) |
18476 | { |
18477 | c_parser_consume_token (parser); |
18478 | eloc = c_parser_peek_token (parser)->location; |
18479 | expr = c_parser_expr_no_commas (parser, NULL); |
18480 | expr = convert_lvalue_to_rvalue (eloc, expr, true, false); |
18481 | step = expr.value; |
18482 | } |
18483 | |
18484 | tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); |
18485 | DECL_ARTIFICIAL (iter_var) = 1; |
18486 | DECL_CONTEXT (iter_var) = current_function_decl; |
18487 | pushdecl (iter_var); |
18488 | |
18489 | *last = make_tree_vec (6); |
18490 | TREE_VEC_ELT (*last, 0) = iter_var; |
18491 | TREE_VEC_ELT (*last, 1) = begin; |
18492 | TREE_VEC_ELT (*last, 2) = end; |
18493 | TREE_VEC_ELT (*last, 3) = step; |
18494 | last = &TREE_CHAIN (*last); |
18495 | |
18496 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
18497 | { |
18498 | c_parser_consume_token (parser); |
18499 | continue; |
18500 | } |
18501 | break; |
18502 | } |
18503 | while (1); |
18504 | |
18505 | parens.skip_until_found_close (parser); |
18506 | return ret ? ret : error_mark_node; |
18507 | } |
18508 | |
18509 | /* OpenMP 5.0: |
18510 | affinity ( [aff-modifier :] variable-list ) |
18511 | aff-modifier: |
18512 | iterator ( iterators-definition ) */ |
18513 | |
18514 | static tree |
18515 | c_parser_omp_clause_affinity (c_parser *parser, tree list) |
18516 | { |
18517 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18518 | tree nl, iterators = NULL_TREE; |
18519 | |
18520 | matching_parens parens; |
18521 | if (!parens.require_open (parser)) |
18522 | return list; |
18523 | |
18524 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
18525 | { |
18526 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18527 | bool parse_iter = ((strcmp (s1: "iterator" , s2: p) == 0) |
18528 | && (c_parser_peek_2nd_token (parser)->type |
18529 | == CPP_OPEN_PAREN)); |
18530 | if (parse_iter) |
18531 | { |
18532 | unsigned n = 3; |
18533 | parse_iter = (c_parser_check_balanced_raw_token_sequence (parser, n: &n) |
18534 | && (c_parser_peek_nth_token_raw (parser, n)->type |
18535 | == CPP_CLOSE_PAREN) |
18536 | && (c_parser_peek_nth_token_raw (parser, n: n + 1)->type |
18537 | == CPP_COLON)); |
18538 | } |
18539 | if (parse_iter) |
18540 | { |
18541 | iterators = c_parser_omp_iterators (parser); |
18542 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18543 | { |
18544 | if (iterators) |
18545 | pop_scope (); |
18546 | parens.skip_until_found_close (parser); |
18547 | return list; |
18548 | } |
18549 | } |
18550 | } |
18551 | nl = c_parser_omp_variable_list (parser, clause_loc, kind: OMP_CLAUSE_AFFINITY, |
18552 | list); |
18553 | if (iterators) |
18554 | { |
18555 | tree block = pop_scope (); |
18556 | if (iterators != error_mark_node) |
18557 | { |
18558 | TREE_VEC_ELT (iterators, 5) = block; |
18559 | for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18560 | OMP_CLAUSE_DECL (c) = build_tree_list (iterators, |
18561 | OMP_CLAUSE_DECL (c)); |
18562 | } |
18563 | } |
18564 | |
18565 | parens.skip_until_found_close (parser); |
18566 | return nl; |
18567 | } |
18568 | |
18569 | |
18570 | /* OpenMP 4.0: |
18571 | depend ( depend-kind: variable-list ) |
18572 | |
18573 | depend-kind: |
18574 | in | out | inout |
18575 | |
18576 | OpenMP 4.5: |
18577 | depend ( source ) |
18578 | |
18579 | depend ( sink : vec ) |
18580 | |
18581 | OpenMP 5.0: |
18582 | depend ( depend-modifier , depend-kind: variable-list ) |
18583 | |
18584 | depend-kind: |
18585 | in | out | inout | mutexinoutset | depobj | inoutset |
18586 | |
18587 | depend-modifier: |
18588 | iterator ( iterators-definition ) */ |
18589 | |
18590 | static tree |
18591 | c_parser_omp_clause_depend (c_parser *parser, tree list) |
18592 | { |
18593 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18594 | enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; |
18595 | enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST; |
18596 | tree nl, c, iterators = NULL_TREE; |
18597 | |
18598 | matching_parens parens; |
18599 | if (!parens.require_open (parser)) |
18600 | return list; |
18601 | |
18602 | do |
18603 | { |
18604 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
18605 | goto invalid_kind; |
18606 | |
18607 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18608 | if (strcmp (s1: "iterator" , s2: p) == 0 && iterators == NULL_TREE) |
18609 | { |
18610 | iterators = c_parser_omp_iterators (parser); |
18611 | c_parser_require (parser, type: CPP_COMMA, msgid: "expected %<,%>" ); |
18612 | continue; |
18613 | } |
18614 | if (strcmp (s1: "in" , s2: p) == 0) |
18615 | kind = OMP_CLAUSE_DEPEND_IN; |
18616 | else if (strcmp (s1: "inout" , s2: p) == 0) |
18617 | kind = OMP_CLAUSE_DEPEND_INOUT; |
18618 | else if (strcmp (s1: "inoutset" , s2: p) == 0) |
18619 | kind = OMP_CLAUSE_DEPEND_INOUTSET; |
18620 | else if (strcmp (s1: "mutexinoutset" , s2: p) == 0) |
18621 | kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; |
18622 | else if (strcmp (s1: "out" , s2: p) == 0) |
18623 | kind = OMP_CLAUSE_DEPEND_OUT; |
18624 | else if (strcmp (s1: "depobj" , s2: p) == 0) |
18625 | kind = OMP_CLAUSE_DEPEND_DEPOBJ; |
18626 | else if (strcmp (s1: "sink" , s2: p) == 0) |
18627 | dkind = OMP_CLAUSE_DOACROSS_SINK; |
18628 | else if (strcmp (s1: "source" , s2: p) == 0) |
18629 | dkind = OMP_CLAUSE_DOACROSS_SOURCE; |
18630 | else |
18631 | goto invalid_kind; |
18632 | break; |
18633 | } |
18634 | while (1); |
18635 | |
18636 | c_parser_consume_token (parser); |
18637 | |
18638 | if (iterators |
18639 | && (dkind == OMP_CLAUSE_DOACROSS_SOURCE |
18640 | || dkind == OMP_CLAUSE_DOACROSS_SINK)) |
18641 | { |
18642 | pop_scope (); |
18643 | error_at (clause_loc, "%<iterator%> modifier incompatible with %qs" , |
18644 | dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink" ); |
18645 | iterators = NULL_TREE; |
18646 | } |
18647 | |
18648 | if (dkind == OMP_CLAUSE_DOACROSS_SOURCE) |
18649 | { |
18650 | c = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
18651 | OMP_CLAUSE_DOACROSS_KIND (c) = dkind; |
18652 | OMP_CLAUSE_DOACROSS_DEPEND (c) = 1; |
18653 | OMP_CLAUSE_DECL (c) = NULL_TREE; |
18654 | OMP_CLAUSE_CHAIN (c) = list; |
18655 | parens.skip_until_found_close (parser); |
18656 | return c; |
18657 | } |
18658 | |
18659 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18660 | goto resync_fail; |
18661 | |
18662 | if (dkind == OMP_CLAUSE_DOACROSS_SINK) |
18663 | nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, depend_p: true); |
18664 | else |
18665 | { |
18666 | nl = c_parser_omp_variable_list (parser, clause_loc, |
18667 | kind: OMP_CLAUSE_DEPEND, list); |
18668 | |
18669 | if (iterators) |
18670 | { |
18671 | tree block = pop_scope (); |
18672 | if (iterators == error_mark_node) |
18673 | iterators = NULL_TREE; |
18674 | else |
18675 | TREE_VEC_ELT (iterators, 5) = block; |
18676 | } |
18677 | |
18678 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18679 | { |
18680 | OMP_CLAUSE_DEPEND_KIND (c) = kind; |
18681 | if (iterators) |
18682 | OMP_CLAUSE_DECL (c) |
18683 | = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); |
18684 | } |
18685 | } |
18686 | |
18687 | parens.skip_until_found_close (parser); |
18688 | return nl; |
18689 | |
18690 | invalid_kind: |
18691 | c_parser_error (parser, gmsgid: "invalid depend kind" ); |
18692 | resync_fail: |
18693 | parens.skip_until_found_close (parser); |
18694 | if (iterators) |
18695 | pop_scope (); |
18696 | return list; |
18697 | } |
18698 | |
18699 | /* OpenMP 5.2: |
18700 | doacross ( source : ) |
18701 | doacross ( source : omp_cur_iteration ) |
18702 | |
18703 | doacross ( sink : vec ) |
18704 | doacross ( sink : omp_cur_iteration - logical_iteration ) */ |
18705 | |
18706 | static tree |
18707 | c_parser_omp_clause_doacross (c_parser *parser, tree list) |
18708 | { |
18709 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18710 | enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST; |
18711 | tree nl; |
18712 | const char *p; |
18713 | |
18714 | matching_parens parens; |
18715 | if (!parens.require_open (parser)) |
18716 | return list; |
18717 | |
18718 | if (c_parser_next_token_is_not (parser, type: CPP_NAME)) |
18719 | goto invalid_kind; |
18720 | |
18721 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18722 | if (strcmp (s1: "sink" , s2: p) == 0) |
18723 | kind = OMP_CLAUSE_DOACROSS_SINK; |
18724 | else if (strcmp (s1: "source" , s2: p) == 0) |
18725 | kind = OMP_CLAUSE_DOACROSS_SOURCE; |
18726 | else |
18727 | goto invalid_kind; |
18728 | |
18729 | c_parser_consume_token (parser); |
18730 | |
18731 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
18732 | goto resync_fail; |
18733 | |
18734 | if (kind == OMP_CLAUSE_DOACROSS_SOURCE) |
18735 | { |
18736 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
18737 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
18738 | s2: "omp_cur_iteration" ) == 0) |
18739 | c_parser_consume_token (parser); |
18740 | nl = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); |
18741 | OMP_CLAUSE_DOACROSS_KIND (nl) = OMP_CLAUSE_DOACROSS_SOURCE; |
18742 | OMP_CLAUSE_DECL (nl) = NULL_TREE; |
18743 | OMP_CLAUSE_CHAIN (nl) = list; |
18744 | } |
18745 | else |
18746 | nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, depend_p: false); |
18747 | |
18748 | parens.skip_until_found_close (parser); |
18749 | return nl; |
18750 | |
18751 | invalid_kind: |
18752 | c_parser_error (parser, gmsgid: "invalid doacross kind" ); |
18753 | resync_fail: |
18754 | parens.skip_until_found_close (parser); |
18755 | return list; |
18756 | } |
18757 | |
18758 | /* OpenMP 4.0: |
18759 | map ( map-kind: variable-list ) |
18760 | map ( variable-list ) |
18761 | |
18762 | map-kind: |
18763 | alloc | to | from | tofrom |
18764 | |
18765 | OpenMP 4.5: |
18766 | map-kind: |
18767 | alloc | to | from | tofrom | release | delete |
18768 | |
18769 | map ( always [,] map-kind: variable-list ) |
18770 | |
18771 | OpenMP 5.0: |
18772 | map ( [map-type-modifier[,] ...] map-kind: variable-list ) |
18773 | |
18774 | map-type-modifier: |
18775 | always | close */ |
18776 | |
18777 | static tree |
18778 | c_parser_omp_clause_map (c_parser *parser, tree list) |
18779 | { |
18780 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18781 | enum gomp_map_kind kind = GOMP_MAP_TOFROM; |
18782 | tree nl, c; |
18783 | |
18784 | matching_parens parens; |
18785 | if (!parens.require_open (parser)) |
18786 | return list; |
18787 | |
18788 | int pos = 1; |
18789 | int map_kind_pos = 0; |
18790 | while (c_parser_peek_nth_token_raw (parser, n: pos)->type == CPP_NAME) |
18791 | { |
18792 | if (c_parser_peek_nth_token_raw (parser, n: pos + 1)->type == CPP_COLON) |
18793 | { |
18794 | map_kind_pos = pos; |
18795 | break; |
18796 | } |
18797 | |
18798 | if (c_parser_peek_nth_token_raw (parser, n: pos + 1)->type == CPP_COMMA) |
18799 | pos++; |
18800 | pos++; |
18801 | } |
18802 | |
18803 | int always_modifier = 0; |
18804 | int close_modifier = 0; |
18805 | int present_modifier = 0; |
18806 | for (int pos = 1; pos < map_kind_pos; ++pos) |
18807 | { |
18808 | c_token *tok = c_parser_peek_token (parser); |
18809 | |
18810 | if (tok->type == CPP_COMMA) |
18811 | { |
18812 | c_parser_consume_token (parser); |
18813 | continue; |
18814 | } |
18815 | |
18816 | const char *p = IDENTIFIER_POINTER (tok->value); |
18817 | if (strcmp (s1: "always" , s2: p) == 0) |
18818 | { |
18819 | if (always_modifier) |
18820 | { |
18821 | c_parser_error (parser, gmsgid: "too many %<always%> modifiers" ); |
18822 | parens.skip_until_found_close (parser); |
18823 | return list; |
18824 | } |
18825 | always_modifier++; |
18826 | } |
18827 | else if (strcmp (s1: "close" , s2: p) == 0) |
18828 | { |
18829 | if (close_modifier) |
18830 | { |
18831 | c_parser_error (parser, gmsgid: "too many %<close%> modifiers" ); |
18832 | parens.skip_until_found_close (parser); |
18833 | return list; |
18834 | } |
18835 | close_modifier++; |
18836 | } |
18837 | else if (strcmp (s1: "present" , s2: p) == 0) |
18838 | { |
18839 | if (present_modifier) |
18840 | { |
18841 | c_parser_error (parser, gmsgid: "too many %<present%> modifiers" ); |
18842 | parens.skip_until_found_close (parser); |
18843 | return list; |
18844 | } |
18845 | present_modifier++; |
18846 | } |
18847 | else |
18848 | { |
18849 | c_parser_error (parser, gmsgid: "%<map%> clause with map-type modifier other " |
18850 | "than %<always%>, %<close%> or %<present%>" ); |
18851 | parens.skip_until_found_close (parser); |
18852 | return list; |
18853 | } |
18854 | |
18855 | c_parser_consume_token (parser); |
18856 | } |
18857 | |
18858 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
18859 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
18860 | { |
18861 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
18862 | int always_present_modifier = always_modifier && present_modifier; |
18863 | |
18864 | if (strcmp (s1: "alloc" , s2: p) == 0) |
18865 | kind = present_modifier ? GOMP_MAP_PRESENT_ALLOC : GOMP_MAP_ALLOC; |
18866 | else if (strcmp (s1: "to" , s2: p) == 0) |
18867 | kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TO |
18868 | : present_modifier ? GOMP_MAP_PRESENT_TO |
18869 | : always_modifier ? GOMP_MAP_ALWAYS_TO |
18870 | : GOMP_MAP_TO); |
18871 | else if (strcmp (s1: "from" , s2: p) == 0) |
18872 | kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_FROM |
18873 | : present_modifier ? GOMP_MAP_PRESENT_FROM |
18874 | : always_modifier ? GOMP_MAP_ALWAYS_FROM |
18875 | : GOMP_MAP_FROM); |
18876 | else if (strcmp (s1: "tofrom" , s2: p) == 0) |
18877 | kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TOFROM |
18878 | : present_modifier ? GOMP_MAP_PRESENT_TOFROM |
18879 | : always_modifier ? GOMP_MAP_ALWAYS_TOFROM |
18880 | : GOMP_MAP_TOFROM); |
18881 | else if (strcmp (s1: "release" , s2: p) == 0) |
18882 | kind = GOMP_MAP_RELEASE; |
18883 | else if (strcmp (s1: "delete" , s2: p) == 0) |
18884 | kind = GOMP_MAP_DELETE; |
18885 | else |
18886 | { |
18887 | c_parser_error (parser, gmsgid: "invalid map kind" ); |
18888 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
18889 | msgid: "expected %<)%>" ); |
18890 | return list; |
18891 | } |
18892 | c_parser_consume_token (parser); |
18893 | c_parser_consume_token (parser); |
18894 | } |
18895 | |
18896 | nl = c_parser_omp_variable_list (parser, clause_loc, kind: OMP_CLAUSE_MAP, list, |
18897 | map_lvalue: true); |
18898 | |
18899 | for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
18900 | OMP_CLAUSE_SET_MAP_KIND (c, kind); |
18901 | |
18902 | parens.skip_until_found_close (parser); |
18903 | return nl; |
18904 | } |
18905 | |
18906 | /* OpenMP 4.0: |
18907 | device ( expression ) |
18908 | |
18909 | OpenMP 5.0: |
18910 | device ( [device-modifier :] integer-expression ) |
18911 | |
18912 | device-modifier: |
18913 | ancestor | device_num */ |
18914 | |
18915 | static tree |
18916 | c_parser_omp_clause_device (c_parser *parser, tree list) |
18917 | { |
18918 | location_t clause_loc = c_parser_peek_token (parser)->location; |
18919 | location_t expr_loc; |
18920 | c_expr expr; |
18921 | tree c, t; |
18922 | bool ancestor = false; |
18923 | |
18924 | matching_parens parens; |
18925 | if (!parens.require_open (parser)) |
18926 | return list; |
18927 | |
18928 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
18929 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
18930 | { |
18931 | c_token *tok = c_parser_peek_token (parser); |
18932 | const char *p = IDENTIFIER_POINTER (tok->value); |
18933 | if (strcmp (s1: "ancestor" , s2: p) == 0) |
18934 | { |
18935 | /* A requires directive with the reverse_offload clause must be |
18936 | specified. */ |
18937 | if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) |
18938 | { |
18939 | error_at (tok->location, "%<ancestor%> device modifier not " |
18940 | "preceded by %<requires%> directive " |
18941 | "with %<reverse_offload%> clause" ); |
18942 | parens.skip_until_found_close (parser); |
18943 | return list; |
18944 | } |
18945 | ancestor = true; |
18946 | } |
18947 | else if (strcmp (s1: "device_num" , s2: p) == 0) |
18948 | ; |
18949 | else |
18950 | { |
18951 | error_at (tok->location, "expected %<ancestor%> or %<device_num%>" ); |
18952 | parens.skip_until_found_close (parser); |
18953 | return list; |
18954 | } |
18955 | c_parser_consume_token (parser); |
18956 | c_parser_consume_token (parser); |
18957 | } |
18958 | |
18959 | expr_loc = c_parser_peek_token (parser)->location; |
18960 | expr = c_parser_expr_no_commas (parser, NULL); |
18961 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
18962 | t = expr.value; |
18963 | t = c_fully_fold (t, false, NULL); |
18964 | |
18965 | parens.skip_until_found_close (parser); |
18966 | |
18967 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) |
18968 | { |
18969 | c_parser_error (parser, gmsgid: "expected integer expression" ); |
18970 | return list; |
18971 | } |
18972 | if (ancestor && TREE_CODE (t) == INTEGER_CST && !integer_onep (t)) |
18973 | { |
18974 | error_at (expr_loc, "the %<device%> clause expression must evaluate to " |
18975 | "%<1%>" ); |
18976 | return list; |
18977 | } |
18978 | |
18979 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_DEVICE, name: "device" ); |
18980 | |
18981 | c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE); |
18982 | |
18983 | OMP_CLAUSE_DEVICE_ID (c) = t; |
18984 | OMP_CLAUSE_CHAIN (c) = list; |
18985 | OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; |
18986 | |
18987 | list = c; |
18988 | return list; |
18989 | } |
18990 | |
18991 | /* OpenMP 4.0: |
18992 | dist_schedule ( static ) |
18993 | dist_schedule ( static , expression ) */ |
18994 | |
18995 | static tree |
18996 | c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) |
18997 | { |
18998 | tree c, t = NULL_TREE; |
18999 | location_t loc = c_parser_peek_token (parser)->location; |
19000 | |
19001 | matching_parens parens; |
19002 | if (!parens.require_open (parser)) |
19003 | return list; |
19004 | |
19005 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_STATIC)) |
19006 | { |
19007 | c_parser_error (parser, gmsgid: "invalid dist_schedule kind" ); |
19008 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
19009 | msgid: "expected %<)%>" ); |
19010 | return list; |
19011 | } |
19012 | |
19013 | c_parser_consume_token (parser); |
19014 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
19015 | { |
19016 | c_parser_consume_token (parser); |
19017 | |
19018 | location_t expr_loc = c_parser_peek_token (parser)->location; |
19019 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
19020 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
19021 | t = expr.value; |
19022 | t = c_fully_fold (t, false, NULL); |
19023 | parens.skip_until_found_close (parser); |
19024 | } |
19025 | else |
19026 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
19027 | msgid: "expected %<,%> or %<)%>" ); |
19028 | |
19029 | /* check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE, |
19030 | "dist_schedule"); */ |
19031 | if (omp_find_clause (clauses: list, kind: OMP_CLAUSE_DIST_SCHEDULE)) |
19032 | warning_at (loc, OPT_Wopenmp, "too many %qs clauses" , "dist_schedule" ); |
19033 | if (t == error_mark_node) |
19034 | return list; |
19035 | |
19036 | c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE); |
19037 | OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; |
19038 | OMP_CLAUSE_CHAIN (c) = list; |
19039 | return c; |
19040 | } |
19041 | |
19042 | /* OpenMP 4.0: |
19043 | proc_bind ( proc-bind-kind ) |
19044 | |
19045 | proc-bind-kind: |
19046 | primary | master | close | spread |
19047 | where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ |
19048 | |
19049 | static tree |
19050 | c_parser_omp_clause_proc_bind (c_parser *parser, tree list) |
19051 | { |
19052 | location_t clause_loc = c_parser_peek_token (parser)->location; |
19053 | enum omp_clause_proc_bind_kind kind; |
19054 | tree c; |
19055 | |
19056 | matching_parens parens; |
19057 | if (!parens.require_open (parser)) |
19058 | return list; |
19059 | |
19060 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
19061 | { |
19062 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
19063 | if (strcmp (s1: "primary" , s2: p) == 0) |
19064 | kind = OMP_CLAUSE_PROC_BIND_PRIMARY; |
19065 | else if (strcmp (s1: "master" , s2: p) == 0) |
19066 | kind = OMP_CLAUSE_PROC_BIND_MASTER; |
19067 | else if (strcmp (s1: "close" , s2: p) == 0) |
19068 | kind = OMP_CLAUSE_PROC_BIND_CLOSE; |
19069 | else if (strcmp (s1: "spread" , s2: p) == 0) |
19070 | kind = OMP_CLAUSE_PROC_BIND_SPREAD; |
19071 | else |
19072 | goto invalid_kind; |
19073 | } |
19074 | else |
19075 | goto invalid_kind; |
19076 | |
19077 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_PROC_BIND, name: "proc_bind" ); |
19078 | c_parser_consume_token (parser); |
19079 | parens.skip_until_found_close (parser); |
19080 | c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND); |
19081 | OMP_CLAUSE_PROC_BIND_KIND (c) = kind; |
19082 | OMP_CLAUSE_CHAIN (c) = list; |
19083 | return c; |
19084 | |
19085 | invalid_kind: |
19086 | c_parser_error (parser, gmsgid: "invalid proc_bind kind" ); |
19087 | parens.skip_until_found_close (parser); |
19088 | return list; |
19089 | } |
19090 | |
19091 | /* OpenMP 5.0: |
19092 | device_type ( host | nohost | any ) */ |
19093 | |
19094 | static tree |
19095 | c_parser_omp_clause_device_type (c_parser *parser, tree list) |
19096 | { |
19097 | location_t clause_loc = c_parser_peek_token (parser)->location; |
19098 | enum omp_clause_device_type_kind kind; |
19099 | tree c; |
19100 | |
19101 | matching_parens parens; |
19102 | if (!parens.require_open (parser)) |
19103 | return list; |
19104 | |
19105 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
19106 | { |
19107 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
19108 | if (strcmp (s1: "host" , s2: p) == 0) |
19109 | kind = OMP_CLAUSE_DEVICE_TYPE_HOST; |
19110 | else if (strcmp (s1: "nohost" , s2: p) == 0) |
19111 | kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST; |
19112 | else if (strcmp (s1: "any" , s2: p) == 0) |
19113 | kind = OMP_CLAUSE_DEVICE_TYPE_ANY; |
19114 | else |
19115 | goto invalid_kind; |
19116 | } |
19117 | else |
19118 | goto invalid_kind; |
19119 | |
19120 | check_no_duplicate_clause (clauses: list, code: OMP_CLAUSE_DEVICE_TYPE, |
19121 | name: "device_type" ); |
19122 | c_parser_consume_token (parser); |
19123 | parens.skip_until_found_close (parser); |
19124 | c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE); |
19125 | OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind; |
19126 | OMP_CLAUSE_CHAIN (c) = list; |
19127 | return c; |
19128 | |
19129 | invalid_kind: |
19130 | c_parser_error (parser, gmsgid: "expected %<host%>, %<nohost%> or %<any%>" ); |
19131 | parens.skip_until_found_close (parser); |
19132 | return list; |
19133 | } |
19134 | |
19135 | /* OpenMP 4.0: |
19136 | from ( variable-list ) |
19137 | to ( variable-list ) |
19138 | |
19139 | OpenMP 5.1: |
19140 | from ( [present :] variable-list ) |
19141 | to ( [present :] variable-list ) */ |
19142 | |
19143 | static tree |
19144 | c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, |
19145 | tree list) |
19146 | { |
19147 | location_t loc = c_parser_peek_token (parser)->location; |
19148 | matching_parens parens; |
19149 | if (!parens.require_open (parser)) |
19150 | return list; |
19151 | |
19152 | bool present = false; |
19153 | c_token *token = c_parser_peek_token (parser); |
19154 | |
19155 | if (token->type == CPP_NAME |
19156 | && strcmp (IDENTIFIER_POINTER (token->value), s2: "present" ) == 0 |
19157 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
19158 | { |
19159 | present = true; |
19160 | c_parser_consume_token (parser); |
19161 | c_parser_consume_token (parser); |
19162 | } |
19163 | |
19164 | tree nl = c_parser_omp_variable_list (parser, clause_loc: loc, kind, list); |
19165 | parens.skip_until_found_close (parser); |
19166 | |
19167 | if (present) |
19168 | for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) |
19169 | OMP_CLAUSE_MOTION_PRESENT (c) = 1; |
19170 | |
19171 | return nl; |
19172 | } |
19173 | |
19174 | /* OpenMP 4.0: |
19175 | uniform ( variable-list ) */ |
19176 | |
19177 | static tree |
19178 | c_parser_omp_clause_uniform (c_parser *parser, tree list) |
19179 | { |
19180 | /* The clauses location. */ |
19181 | location_t loc = c_parser_peek_token (parser)->location; |
19182 | |
19183 | matching_parens parens; |
19184 | if (parens.require_open (parser)) |
19185 | { |
19186 | list = c_parser_omp_variable_list (parser, clause_loc: loc, kind: OMP_CLAUSE_UNIFORM, |
19187 | list); |
19188 | parens.skip_until_found_close (parser); |
19189 | } |
19190 | return list; |
19191 | } |
19192 | |
19193 | /* OpenMP 5.0: |
19194 | detach ( event-handle ) */ |
19195 | |
19196 | static tree |
19197 | c_parser_omp_clause_detach (c_parser *parser, tree list) |
19198 | { |
19199 | matching_parens parens; |
19200 | location_t clause_loc = c_parser_peek_token (parser)->location; |
19201 | |
19202 | if (!parens.require_open (parser)) |
19203 | return list; |
19204 | |
19205 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
19206 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
19207 | { |
19208 | c_parser_error (parser, gmsgid: "expected identifier" ); |
19209 | parens.skip_until_found_close (parser); |
19210 | return list; |
19211 | } |
19212 | |
19213 | tree t = lookup_name (c_parser_peek_token (parser)->value); |
19214 | if (t == NULL_TREE) |
19215 | { |
19216 | undeclared_variable (c_parser_peek_token (parser)->location, |
19217 | c_parser_peek_token (parser)->value); |
19218 | parens.skip_until_found_close (parser); |
19219 | return list; |
19220 | } |
19221 | c_parser_consume_token (parser); |
19222 | |
19223 | tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); |
19224 | if (!INTEGRAL_TYPE_P (type) |
19225 | || TREE_CODE (type) != ENUMERAL_TYPE |
19226 | || TYPE_NAME (type) != get_identifier ("omp_event_handle_t" )) |
19227 | { |
19228 | error_at (clause_loc, "%<detach%> clause event handle " |
19229 | "has type %qT rather than " |
19230 | "%<omp_event_handle_t%>" , |
19231 | type); |
19232 | parens.skip_until_found_close (parser); |
19233 | return list; |
19234 | } |
19235 | |
19236 | tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DETACH); |
19237 | OMP_CLAUSE_DECL (u) = t; |
19238 | OMP_CLAUSE_CHAIN (u) = list; |
19239 | parens.skip_until_found_close (parser); |
19240 | return u; |
19241 | } |
19242 | |
19243 | /* Parse all OpenACC clauses. The set clauses allowed by the directive |
19244 | is a bitmask in MASK. Return the list of clauses found. */ |
19245 | |
19246 | static tree |
19247 | c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, |
19248 | const char *where, bool finish_p = true, |
19249 | bool target_p = false) |
19250 | { |
19251 | tree clauses = NULL; |
19252 | bool first = true; |
19253 | |
19254 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
19255 | { |
19256 | location_t here; |
19257 | pragma_omp_clause c_kind; |
19258 | const char *c_name; |
19259 | tree prev = clauses; |
19260 | |
19261 | if (!first && c_parser_next_token_is (parser, type: CPP_COMMA)) |
19262 | c_parser_consume_token (parser); |
19263 | |
19264 | here = c_parser_peek_token (parser)->location; |
19265 | c_kind = c_parser_omp_clause_name (parser); |
19266 | |
19267 | switch (c_kind) |
19268 | { |
19269 | case PRAGMA_OACC_CLAUSE_ASYNC: |
19270 | clauses = c_parser_oacc_clause_async (parser, list: clauses); |
19271 | c_name = "async" ; |
19272 | break; |
19273 | case PRAGMA_OACC_CLAUSE_AUTO: |
19274 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_AUTO, |
19275 | list: clauses); |
19276 | c_name = "auto" ; |
19277 | break; |
19278 | case PRAGMA_OACC_CLAUSE_ATTACH: |
19279 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19280 | c_name = "attach" ; |
19281 | break; |
19282 | case PRAGMA_OACC_CLAUSE_COLLAPSE: |
19283 | clauses = c_parser_omp_clause_collapse (parser, list: clauses); |
19284 | c_name = "collapse" ; |
19285 | break; |
19286 | case PRAGMA_OACC_CLAUSE_COPY: |
19287 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19288 | c_name = "copy" ; |
19289 | break; |
19290 | case PRAGMA_OACC_CLAUSE_COPYIN: |
19291 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19292 | c_name = "copyin" ; |
19293 | break; |
19294 | case PRAGMA_OACC_CLAUSE_COPYOUT: |
19295 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19296 | c_name = "copyout" ; |
19297 | break; |
19298 | case PRAGMA_OACC_CLAUSE_CREATE: |
19299 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19300 | c_name = "create" ; |
19301 | break; |
19302 | case PRAGMA_OACC_CLAUSE_DELETE: |
19303 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19304 | c_name = "delete" ; |
19305 | break; |
19306 | case PRAGMA_OMP_CLAUSE_DEFAULT: |
19307 | clauses = c_parser_omp_clause_default (parser, list: clauses, is_oacc: true); |
19308 | c_name = "default" ; |
19309 | break; |
19310 | case PRAGMA_OACC_CLAUSE_DETACH: |
19311 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19312 | c_name = "detach" ; |
19313 | break; |
19314 | case PRAGMA_OACC_CLAUSE_DEVICE: |
19315 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19316 | c_name = "device" ; |
19317 | break; |
19318 | case PRAGMA_OACC_CLAUSE_DEVICEPTR: |
19319 | clauses = c_parser_oacc_data_clause_deviceptr (parser, list: clauses); |
19320 | c_name = "deviceptr" ; |
19321 | break; |
19322 | case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT: |
19323 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19324 | c_name = "device_resident" ; |
19325 | break; |
19326 | case PRAGMA_OACC_CLAUSE_FINALIZE: |
19327 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_FINALIZE, |
19328 | list: clauses); |
19329 | c_name = "finalize" ; |
19330 | break; |
19331 | case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE: |
19332 | clauses = c_parser_omp_clause_firstprivate (parser, list: clauses); |
19333 | c_name = "firstprivate" ; |
19334 | break; |
19335 | case PRAGMA_OACC_CLAUSE_GANG: |
19336 | c_name = "gang" ; |
19337 | clauses = c_parser_oacc_shape_clause (parser, loc: here, kind: OMP_CLAUSE_GANG, |
19338 | str: c_name, list: clauses); |
19339 | break; |
19340 | case PRAGMA_OACC_CLAUSE_HOST: |
19341 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19342 | c_name = "host" ; |
19343 | break; |
19344 | case PRAGMA_OACC_CLAUSE_IF: |
19345 | clauses = c_parser_omp_clause_if (parser, list: clauses, is_omp: false); |
19346 | c_name = "if" ; |
19347 | break; |
19348 | case PRAGMA_OACC_CLAUSE_IF_PRESENT: |
19349 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_IF_PRESENT, |
19350 | list: clauses); |
19351 | c_name = "if_present" ; |
19352 | break; |
19353 | case PRAGMA_OACC_CLAUSE_INDEPENDENT: |
19354 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_INDEPENDENT, |
19355 | list: clauses); |
19356 | c_name = "independent" ; |
19357 | break; |
19358 | case PRAGMA_OACC_CLAUSE_LINK: |
19359 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19360 | c_name = "link" ; |
19361 | break; |
19362 | case PRAGMA_OACC_CLAUSE_NO_CREATE: |
19363 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19364 | c_name = "no_create" ; |
19365 | break; |
19366 | case PRAGMA_OACC_CLAUSE_NOHOST: |
19367 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_NOHOST, |
19368 | list: clauses); |
19369 | c_name = "nohost" ; |
19370 | break; |
19371 | case PRAGMA_OACC_CLAUSE_NUM_GANGS: |
19372 | clauses = c_parser_oacc_single_int_clause (parser, |
19373 | code: OMP_CLAUSE_NUM_GANGS, |
19374 | list: clauses); |
19375 | c_name = "num_gangs" ; |
19376 | break; |
19377 | case PRAGMA_OACC_CLAUSE_NUM_WORKERS: |
19378 | clauses = c_parser_oacc_single_int_clause (parser, |
19379 | code: OMP_CLAUSE_NUM_WORKERS, |
19380 | list: clauses); |
19381 | c_name = "num_workers" ; |
19382 | break; |
19383 | case PRAGMA_OACC_CLAUSE_PRESENT: |
19384 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19385 | c_name = "present" ; |
19386 | break; |
19387 | case PRAGMA_OACC_CLAUSE_PRIVATE: |
19388 | clauses = c_parser_omp_clause_private (parser, list: clauses); |
19389 | c_name = "private" ; |
19390 | break; |
19391 | case PRAGMA_OACC_CLAUSE_REDUCTION: |
19392 | clauses |
19393 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_REDUCTION, |
19394 | is_omp: false, list: clauses); |
19395 | c_name = "reduction" ; |
19396 | break; |
19397 | case PRAGMA_OACC_CLAUSE_SELF: |
19398 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST)) == 0) |
19399 | /* OpenACC compute construct */ |
19400 | clauses = c_parser_oacc_compute_clause_self (parser, list: clauses); |
19401 | else |
19402 | /* OpenACC 'update' directive */ |
19403 | clauses = c_parser_oacc_data_clause (parser, c_kind, list: clauses); |
19404 | c_name = "self" ; |
19405 | break; |
19406 | case PRAGMA_OACC_CLAUSE_SEQ: |
19407 | clauses = c_parser_oacc_simple_clause (loc: here, code: OMP_CLAUSE_SEQ, |
19408 | list: clauses); |
19409 | c_name = "seq" ; |
19410 | break; |
19411 | case PRAGMA_OACC_CLAUSE_TILE: |
19412 | clauses = c_parser_oacc_clause_tile (parser, list: clauses); |
19413 | c_name = "tile" ; |
19414 | break; |
19415 | case PRAGMA_OACC_CLAUSE_USE_DEVICE: |
19416 | clauses = c_parser_omp_clause_use_device_ptr (parser, list: clauses); |
19417 | c_name = "use_device" ; |
19418 | break; |
19419 | case PRAGMA_OACC_CLAUSE_VECTOR: |
19420 | c_name = "vector" ; |
19421 | clauses = c_parser_oacc_shape_clause (parser, loc: here, kind: OMP_CLAUSE_VECTOR, |
19422 | str: c_name, list: clauses); |
19423 | break; |
19424 | case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH: |
19425 | clauses = c_parser_oacc_single_int_clause (parser, |
19426 | code: OMP_CLAUSE_VECTOR_LENGTH, |
19427 | list: clauses); |
19428 | c_name = "vector_length" ; |
19429 | break; |
19430 | case PRAGMA_OACC_CLAUSE_WAIT: |
19431 | clauses = c_parser_oacc_clause_wait (parser, list: clauses); |
19432 | c_name = "wait" ; |
19433 | break; |
19434 | case PRAGMA_OACC_CLAUSE_WORKER: |
19435 | c_name = "worker" ; |
19436 | clauses = c_parser_oacc_shape_clause (parser, loc: here, kind: OMP_CLAUSE_WORKER, |
19437 | str: c_name, list: clauses); |
19438 | break; |
19439 | default: |
19440 | c_parser_error (parser, gmsgid: "expected an OpenACC clause" ); |
19441 | goto saw_error; |
19442 | } |
19443 | |
19444 | first = false; |
19445 | |
19446 | if (((mask >> c_kind) & 1) == 0) |
19447 | { |
19448 | /* Remove the invalid clause(s) from the list to avoid |
19449 | confusing the rest of the compiler. */ |
19450 | clauses = prev; |
19451 | error_at (here, "%qs is not valid for %qs" , c_name, where); |
19452 | } |
19453 | } |
19454 | |
19455 | saw_error: |
19456 | c_parser_skip_to_pragma_eol (parser); |
19457 | |
19458 | if (finish_p) |
19459 | return c_finish_omp_clauses (clauses, target_p ? C_ORT_ACC_TARGET |
19460 | : C_ORT_ACC); |
19461 | |
19462 | return clauses; |
19463 | } |
19464 | |
19465 | /* Parse all OpenMP clauses. The set clauses allowed by the directive |
19466 | is a bitmask in MASK. Return the list of clauses found. |
19467 | FINISH_P set if c_finish_omp_clauses should be called. |
19468 | NESTED non-zero if clauses should be terminated by closing paren instead |
19469 | of end of pragma. If it is 2, additionally commas are required in between |
19470 | the clauses. */ |
19471 | |
19472 | static tree |
19473 | c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, |
19474 | const char *where, bool finish_p = true, |
19475 | int nested = 0) |
19476 | { |
19477 | tree clauses = NULL; |
19478 | bool first = true; |
19479 | |
19480 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
19481 | { |
19482 | location_t here; |
19483 | pragma_omp_clause c_kind; |
19484 | const char *c_name; |
19485 | tree prev = clauses; |
19486 | |
19487 | if (nested && c_parser_next_token_is (parser, type: CPP_CLOSE_PAREN)) |
19488 | break; |
19489 | |
19490 | if (!first || nested != 2) |
19491 | { |
19492 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
19493 | c_parser_consume_token (parser); |
19494 | else if (nested == 2) |
19495 | error_at (c_parser_peek_token (parser)->location, |
19496 | "clauses in %<simd%> trait should be separated " |
19497 | "by %<,%>" ); |
19498 | } |
19499 | |
19500 | here = c_parser_peek_token (parser)->location; |
19501 | c_kind = c_parser_omp_clause_name (parser); |
19502 | |
19503 | switch (c_kind) |
19504 | { |
19505 | case PRAGMA_OMP_CLAUSE_BIND: |
19506 | clauses = c_parser_omp_clause_bind (parser, list: clauses); |
19507 | c_name = "bind" ; |
19508 | break; |
19509 | case PRAGMA_OMP_CLAUSE_COLLAPSE: |
19510 | clauses = c_parser_omp_clause_collapse (parser, list: clauses); |
19511 | c_name = "collapse" ; |
19512 | break; |
19513 | case PRAGMA_OMP_CLAUSE_COPYIN: |
19514 | clauses = c_parser_omp_clause_copyin (parser, list: clauses); |
19515 | c_name = "copyin" ; |
19516 | break; |
19517 | case PRAGMA_OMP_CLAUSE_COPYPRIVATE: |
19518 | clauses = c_parser_omp_clause_copyprivate (parser, list: clauses); |
19519 | c_name = "copyprivate" ; |
19520 | break; |
19521 | case PRAGMA_OMP_CLAUSE_DEFAULT: |
19522 | clauses = c_parser_omp_clause_default (parser, list: clauses, is_oacc: false); |
19523 | c_name = "default" ; |
19524 | break; |
19525 | case PRAGMA_OMP_CLAUSE_DETACH: |
19526 | clauses = c_parser_omp_clause_detach (parser, list: clauses); |
19527 | c_name = "detach" ; |
19528 | break; |
19529 | case PRAGMA_OMP_CLAUSE_FILTER: |
19530 | clauses = c_parser_omp_clause_filter (parser, list: clauses); |
19531 | c_name = "filter" ; |
19532 | break; |
19533 | case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: |
19534 | clauses = c_parser_omp_clause_firstprivate (parser, list: clauses); |
19535 | c_name = "firstprivate" ; |
19536 | break; |
19537 | case PRAGMA_OMP_CLAUSE_FINAL: |
19538 | clauses = c_parser_omp_clause_final (parser, list: clauses); |
19539 | c_name = "final" ; |
19540 | break; |
19541 | case PRAGMA_OMP_CLAUSE_GRAINSIZE: |
19542 | clauses = c_parser_omp_clause_grainsize (parser, list: clauses); |
19543 | c_name = "grainsize" ; |
19544 | break; |
19545 | case PRAGMA_OMP_CLAUSE_HINT: |
19546 | clauses = c_parser_omp_clause_hint (parser, list: clauses); |
19547 | c_name = "hint" ; |
19548 | break; |
19549 | case PRAGMA_OMP_CLAUSE_DEFAULTMAP: |
19550 | clauses = c_parser_omp_clause_defaultmap (parser, list: clauses); |
19551 | c_name = "defaultmap" ; |
19552 | break; |
19553 | case PRAGMA_OMP_CLAUSE_IF: |
19554 | clauses = c_parser_omp_clause_if (parser, list: clauses, is_omp: true); |
19555 | c_name = "if" ; |
19556 | break; |
19557 | case PRAGMA_OMP_CLAUSE_IN_REDUCTION: |
19558 | clauses |
19559 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_IN_REDUCTION, |
19560 | is_omp: true, list: clauses); |
19561 | c_name = "in_reduction" ; |
19562 | break; |
19563 | case PRAGMA_OMP_CLAUSE_INDIRECT: |
19564 | clauses = c_parser_omp_clause_indirect (parser, list: clauses); |
19565 | c_name = "indirect" ; |
19566 | break; |
19567 | case PRAGMA_OMP_CLAUSE_LASTPRIVATE: |
19568 | clauses = c_parser_omp_clause_lastprivate (parser, list: clauses); |
19569 | c_name = "lastprivate" ; |
19570 | break; |
19571 | case PRAGMA_OMP_CLAUSE_MERGEABLE: |
19572 | clauses = c_parser_omp_clause_mergeable (parser, list: clauses); |
19573 | c_name = "mergeable" ; |
19574 | break; |
19575 | case PRAGMA_OMP_CLAUSE_NOWAIT: |
19576 | clauses = c_parser_omp_clause_nowait (parser, list: clauses); |
19577 | c_name = "nowait" ; |
19578 | break; |
19579 | case PRAGMA_OMP_CLAUSE_NUM_TASKS: |
19580 | clauses = c_parser_omp_clause_num_tasks (parser, list: clauses); |
19581 | c_name = "num_tasks" ; |
19582 | break; |
19583 | case PRAGMA_OMP_CLAUSE_NUM_THREADS: |
19584 | clauses = c_parser_omp_clause_num_threads (parser, list: clauses); |
19585 | c_name = "num_threads" ; |
19586 | break; |
19587 | case PRAGMA_OMP_CLAUSE_ORDER: |
19588 | clauses = c_parser_omp_clause_order (parser, list: clauses); |
19589 | c_name = "order" ; |
19590 | break; |
19591 | case PRAGMA_OMP_CLAUSE_ORDERED: |
19592 | clauses = c_parser_omp_clause_ordered (parser, list: clauses); |
19593 | c_name = "ordered" ; |
19594 | break; |
19595 | case PRAGMA_OMP_CLAUSE_PRIORITY: |
19596 | clauses = c_parser_omp_clause_priority (parser, list: clauses); |
19597 | c_name = "priority" ; |
19598 | break; |
19599 | case PRAGMA_OMP_CLAUSE_PRIVATE: |
19600 | clauses = c_parser_omp_clause_private (parser, list: clauses); |
19601 | c_name = "private" ; |
19602 | break; |
19603 | case PRAGMA_OMP_CLAUSE_REDUCTION: |
19604 | clauses |
19605 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_REDUCTION, |
19606 | is_omp: true, list: clauses); |
19607 | c_name = "reduction" ; |
19608 | break; |
19609 | case PRAGMA_OMP_CLAUSE_SCHEDULE: |
19610 | clauses = c_parser_omp_clause_schedule (parser, list: clauses); |
19611 | c_name = "schedule" ; |
19612 | break; |
19613 | case PRAGMA_OMP_CLAUSE_SHARED: |
19614 | clauses = c_parser_omp_clause_shared (parser, list: clauses); |
19615 | c_name = "shared" ; |
19616 | break; |
19617 | case PRAGMA_OMP_CLAUSE_TASK_REDUCTION: |
19618 | clauses |
19619 | = c_parser_omp_clause_reduction (parser, kind: OMP_CLAUSE_TASK_REDUCTION, |
19620 | is_omp: true, list: clauses); |
19621 | c_name = "task_reduction" ; |
19622 | break; |
19623 | case PRAGMA_OMP_CLAUSE_UNTIED: |
19624 | clauses = c_parser_omp_clause_untied (parser, list: clauses); |
19625 | c_name = "untied" ; |
19626 | break; |
19627 | case PRAGMA_OMP_CLAUSE_INBRANCH: |
19628 | clauses = c_parser_omp_clause_branch (parser, code: OMP_CLAUSE_INBRANCH, |
19629 | list: clauses); |
19630 | c_name = "inbranch" ; |
19631 | break; |
19632 | case PRAGMA_OMP_CLAUSE_NONTEMPORAL: |
19633 | clauses = c_parser_omp_clause_nontemporal (parser, list: clauses); |
19634 | c_name = "nontemporal" ; |
19635 | break; |
19636 | case PRAGMA_OMP_CLAUSE_NOTINBRANCH: |
19637 | clauses = c_parser_omp_clause_branch (parser, code: OMP_CLAUSE_NOTINBRANCH, |
19638 | list: clauses); |
19639 | c_name = "notinbranch" ; |
19640 | break; |
19641 | case PRAGMA_OMP_CLAUSE_PARALLEL: |
19642 | clauses |
19643 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_PARALLEL, |
19644 | list: clauses); |
19645 | c_name = "parallel" ; |
19646 | if (!first) |
19647 | { |
19648 | clause_not_first: |
19649 | error_at (here, "%qs must be the first clause of %qs" , |
19650 | c_name, where); |
19651 | clauses = prev; |
19652 | } |
19653 | break; |
19654 | case PRAGMA_OMP_CLAUSE_FOR: |
19655 | clauses |
19656 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_FOR, |
19657 | list: clauses); |
19658 | c_name = "for" ; |
19659 | if (!first) |
19660 | goto clause_not_first; |
19661 | break; |
19662 | case PRAGMA_OMP_CLAUSE_SECTIONS: |
19663 | clauses |
19664 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_SECTIONS, |
19665 | list: clauses); |
19666 | c_name = "sections" ; |
19667 | if (!first) |
19668 | goto clause_not_first; |
19669 | break; |
19670 | case PRAGMA_OMP_CLAUSE_TASKGROUP: |
19671 | clauses |
19672 | = c_parser_omp_clause_cancelkind (parser, code: OMP_CLAUSE_TASKGROUP, |
19673 | list: clauses); |
19674 | c_name = "taskgroup" ; |
19675 | if (!first) |
19676 | goto clause_not_first; |
19677 | break; |
19678 | case PRAGMA_OMP_CLAUSE_LINK: |
19679 | clauses |
19680 | = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_LINK, list: clauses); |
19681 | c_name = "link" ; |
19682 | break; |
19683 | case PRAGMA_OMP_CLAUSE_TO: |
19684 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) |
19685 | { |
19686 | tree nl = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ENTER, |
19687 | list: clauses); |
19688 | for (tree c = nl; c != clauses; c = OMP_CLAUSE_CHAIN (c)) |
19689 | OMP_CLAUSE_ENTER_TO (c) = 1; |
19690 | clauses = nl; |
19691 | } |
19692 | else |
19693 | clauses = c_parser_omp_clause_from_to (parser, kind: OMP_CLAUSE_TO, |
19694 | list: clauses); |
19695 | c_name = "to" ; |
19696 | break; |
19697 | case PRAGMA_OMP_CLAUSE_FROM: |
19698 | clauses = c_parser_omp_clause_from_to (parser, kind: OMP_CLAUSE_FROM, |
19699 | list: clauses); |
19700 | c_name = "from" ; |
19701 | break; |
19702 | case PRAGMA_OMP_CLAUSE_UNIFORM: |
19703 | clauses = c_parser_omp_clause_uniform (parser, list: clauses); |
19704 | c_name = "uniform" ; |
19705 | break; |
19706 | case PRAGMA_OMP_CLAUSE_NUM_TEAMS: |
19707 | clauses = c_parser_omp_clause_num_teams (parser, list: clauses); |
19708 | c_name = "num_teams" ; |
19709 | break; |
19710 | case PRAGMA_OMP_CLAUSE_THREAD_LIMIT: |
19711 | clauses = c_parser_omp_clause_thread_limit (parser, list: clauses); |
19712 | c_name = "thread_limit" ; |
19713 | break; |
19714 | case PRAGMA_OMP_CLAUSE_ALIGNED: |
19715 | clauses = c_parser_omp_clause_aligned (parser, list: clauses); |
19716 | c_name = "aligned" ; |
19717 | break; |
19718 | case PRAGMA_OMP_CLAUSE_ALLOCATE: |
19719 | clauses = c_parser_omp_clause_allocate (parser, list: clauses); |
19720 | c_name = "allocate" ; |
19721 | break; |
19722 | case PRAGMA_OMP_CLAUSE_LINEAR: |
19723 | clauses = c_parser_omp_clause_linear (parser, list: clauses); |
19724 | c_name = "linear" ; |
19725 | break; |
19726 | case PRAGMA_OMP_CLAUSE_AFFINITY: |
19727 | clauses = c_parser_omp_clause_affinity (parser, list: clauses); |
19728 | c_name = "affinity" ; |
19729 | break; |
19730 | case PRAGMA_OMP_CLAUSE_DEPEND: |
19731 | clauses = c_parser_omp_clause_depend (parser, list: clauses); |
19732 | c_name = "depend" ; |
19733 | break; |
19734 | case PRAGMA_OMP_CLAUSE_DOACROSS: |
19735 | clauses = c_parser_omp_clause_doacross (parser, list: clauses); |
19736 | c_name = "doacross" ; |
19737 | break; |
19738 | case PRAGMA_OMP_CLAUSE_MAP: |
19739 | clauses = c_parser_omp_clause_map (parser, list: clauses); |
19740 | c_name = "map" ; |
19741 | break; |
19742 | case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR: |
19743 | clauses = c_parser_omp_clause_use_device_ptr (parser, list: clauses); |
19744 | c_name = "use_device_ptr" ; |
19745 | break; |
19746 | case PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR: |
19747 | clauses = c_parser_omp_clause_use_device_addr (parser, list: clauses); |
19748 | c_name = "use_device_addr" ; |
19749 | break; |
19750 | case PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR: |
19751 | clauses = c_parser_omp_clause_has_device_addr (parser, list: clauses); |
19752 | c_name = "has_device_addr" ; |
19753 | break; |
19754 | case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR: |
19755 | clauses = c_parser_omp_clause_is_device_ptr (parser, list: clauses); |
19756 | c_name = "is_device_ptr" ; |
19757 | break; |
19758 | case PRAGMA_OMP_CLAUSE_DEVICE: |
19759 | clauses = c_parser_omp_clause_device (parser, list: clauses); |
19760 | c_name = "device" ; |
19761 | break; |
19762 | case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE: |
19763 | clauses = c_parser_omp_clause_dist_schedule (parser, list: clauses); |
19764 | c_name = "dist_schedule" ; |
19765 | break; |
19766 | case PRAGMA_OMP_CLAUSE_PROC_BIND: |
19767 | clauses = c_parser_omp_clause_proc_bind (parser, list: clauses); |
19768 | c_name = "proc_bind" ; |
19769 | break; |
19770 | case PRAGMA_OMP_CLAUSE_DEVICE_TYPE: |
19771 | clauses = c_parser_omp_clause_device_type (parser, list: clauses); |
19772 | c_name = "device_type" ; |
19773 | break; |
19774 | case PRAGMA_OMP_CLAUSE_SAFELEN: |
19775 | clauses = c_parser_omp_clause_safelen (parser, list: clauses); |
19776 | c_name = "safelen" ; |
19777 | break; |
19778 | case PRAGMA_OMP_CLAUSE_SIMDLEN: |
19779 | clauses = c_parser_omp_clause_simdlen (parser, list: clauses); |
19780 | c_name = "simdlen" ; |
19781 | break; |
19782 | case PRAGMA_OMP_CLAUSE_NOGROUP: |
19783 | clauses = c_parser_omp_clause_nogroup (parser, list: clauses); |
19784 | c_name = "nogroup" ; |
19785 | break; |
19786 | case PRAGMA_OMP_CLAUSE_THREADS: |
19787 | clauses |
19788 | = c_parser_omp_clause_orderedkind (parser, code: OMP_CLAUSE_THREADS, |
19789 | list: clauses); |
19790 | c_name = "threads" ; |
19791 | break; |
19792 | case PRAGMA_OMP_CLAUSE_SIMD: |
19793 | clauses |
19794 | = c_parser_omp_clause_orderedkind (parser, code: OMP_CLAUSE_SIMD, |
19795 | list: clauses); |
19796 | c_name = "simd" ; |
19797 | break; |
19798 | case PRAGMA_OMP_CLAUSE_ENTER: |
19799 | clauses |
19800 | = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ENTER, |
19801 | list: clauses); |
19802 | c_name = "enter" ; |
19803 | break; |
19804 | default: |
19805 | c_parser_error (parser, gmsgid: "expected an OpenMP clause" ); |
19806 | goto saw_error; |
19807 | } |
19808 | |
19809 | first = false; |
19810 | |
19811 | if (((mask >> c_kind) & 1) == 0) |
19812 | { |
19813 | /* Remove the invalid clause(s) from the list to avoid |
19814 | confusing the rest of the compiler. */ |
19815 | clauses = prev; |
19816 | error_at (here, "%qs is not valid for %qs" , c_name, where); |
19817 | } |
19818 | } |
19819 | |
19820 | saw_error: |
19821 | if (!nested) |
19822 | c_parser_skip_to_pragma_eol (parser); |
19823 | |
19824 | if (finish_p) |
19825 | { |
19826 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0) |
19827 | return c_finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD); |
19828 | return c_finish_omp_clauses (clauses, C_ORT_OMP); |
19829 | } |
19830 | |
19831 | return clauses; |
19832 | } |
19833 | |
19834 | /* OpenACC 2.0, OpenMP 2.5: |
19835 | structured-block: |
19836 | statement |
19837 | |
19838 | In practice, we're also interested in adding the statement to an |
19839 | outer node. So it is convenient if we work around the fact that |
19840 | c_parser_statement calls add_stmt. */ |
19841 | |
19842 | static tree |
19843 | c_parser_omp_structured_block (c_parser *parser, bool *if_p) |
19844 | { |
19845 | tree stmt = push_stmt_list (); |
19846 | parser->omp_attrs_forbidden_p = true; |
19847 | c_parser_statement (parser, if_p); |
19848 | return pop_stmt_list (stmt); |
19849 | } |
19850 | |
19851 | /* OpenACC 2.0: |
19852 | # pragma acc cache (variable-list) new-line |
19853 | |
19854 | OpenACC 2.7: |
19855 | # pragma acc cache (readonly: variable-list) new-line |
19856 | |
19857 | LOC is the location of the #pragma token. |
19858 | */ |
19859 | |
19860 | static tree |
19861 | c_parser_oacc_cache (location_t loc, c_parser *parser) |
19862 | { |
19863 | tree stmt, clauses = NULL_TREE; |
19864 | bool readonly = false; |
19865 | location_t open_loc = c_parser_peek_token (parser)->location; |
19866 | matching_parens parens; |
19867 | if (parens.require_open (parser)) |
19868 | { |
19869 | c_token *token = c_parser_peek_token (parser); |
19870 | if (token->type == CPP_NAME |
19871 | && !strcmp (IDENTIFIER_POINTER (token->value), s2: "readonly" ) |
19872 | && c_parser_peek_2nd_token (parser)->type == CPP_COLON) |
19873 | { |
19874 | c_parser_consume_token (parser); |
19875 | c_parser_consume_token (parser); |
19876 | readonly = true; |
19877 | } |
19878 | clauses = c_parser_omp_variable_list (parser, clause_loc: open_loc, |
19879 | kind: OMP_CLAUSE__CACHE_, NULL_TREE); |
19880 | parens.skip_until_found_close (parser); |
19881 | } |
19882 | |
19883 | if (readonly) |
19884 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
19885 | OMP_CLAUSE__CACHE__READONLY (c) = 1; |
19886 | |
19887 | clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); |
19888 | |
19889 | c_parser_skip_to_pragma_eol (parser); |
19890 | |
19891 | stmt = make_node (OACC_CACHE); |
19892 | TREE_TYPE (stmt) = void_type_node; |
19893 | OACC_CACHE_CLAUSES (stmt) = clauses; |
19894 | SET_EXPR_LOCATION (stmt, loc); |
19895 | add_stmt (stmt); |
19896 | |
19897 | return stmt; |
19898 | } |
19899 | |
19900 | /* OpenACC 2.0: |
19901 | # pragma acc data oacc-data-clause[optseq] new-line |
19902 | structured-block |
19903 | |
19904 | LOC is the location of the #pragma token. |
19905 | */ |
19906 | |
19907 | #define OACC_DATA_CLAUSE_MASK \ |
19908 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
19909 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19910 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19911 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19912 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19913 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
19914 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19915 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
19916 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
19917 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) |
19918 | |
19919 | static tree |
19920 | c_parser_oacc_data (location_t loc, c_parser *parser, bool *if_p) |
19921 | { |
19922 | tree stmt, clauses, block; |
19923 | |
19924 | clauses = c_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK, |
19925 | where: "#pragma acc data" ); |
19926 | |
19927 | block = c_begin_omp_parallel (); |
19928 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
19929 | |
19930 | stmt = c_finish_oacc_data (loc, clauses, block); |
19931 | |
19932 | return stmt; |
19933 | } |
19934 | |
19935 | /* OpenACC 2.0: |
19936 | # pragma acc declare oacc-data-clause[optseq] new-line |
19937 | */ |
19938 | |
19939 | #define OACC_DECLARE_CLAUSE_MASK \ |
19940 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
19941 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
19942 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
19943 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
19944 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
19945 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT) \ |
19946 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_LINK) \ |
19947 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT)) |
19948 | |
19949 | static void |
19950 | c_parser_oacc_declare (c_parser *parser) |
19951 | { |
19952 | location_t pragma_loc = c_parser_peek_token (parser)->location; |
19953 | tree clauses, stmt, t, decl; |
19954 | |
19955 | bool error = false; |
19956 | |
19957 | c_parser_consume_pragma (parser); |
19958 | |
19959 | clauses = c_parser_oacc_all_clauses (parser, OACC_DECLARE_CLAUSE_MASK, |
19960 | where: "#pragma acc declare" ); |
19961 | if (!clauses) |
19962 | { |
19963 | error_at (pragma_loc, |
19964 | "no valid clauses specified in %<#pragma acc declare%>" ); |
19965 | return; |
19966 | } |
19967 | |
19968 | for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t)) |
19969 | { |
19970 | location_t loc = OMP_CLAUSE_LOCATION (t); |
19971 | decl = OMP_CLAUSE_DECL (t); |
19972 | if (!DECL_P (decl)) |
19973 | { |
19974 | error_at (loc, "array section in %<#pragma acc declare%>" ); |
19975 | error = true; |
19976 | continue; |
19977 | } |
19978 | |
19979 | switch (OMP_CLAUSE_MAP_KIND (t)) |
19980 | { |
19981 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
19982 | case GOMP_MAP_ALLOC: |
19983 | case GOMP_MAP_TO: |
19984 | case GOMP_MAP_FORCE_DEVICEPTR: |
19985 | case GOMP_MAP_DEVICE_RESIDENT: |
19986 | break; |
19987 | |
19988 | case GOMP_MAP_LINK: |
19989 | if (!global_bindings_p () |
19990 | && (TREE_STATIC (decl) |
19991 | || !DECL_EXTERNAL (decl))) |
19992 | { |
19993 | error_at (loc, |
19994 | "%qD must be a global variable in " |
19995 | "%<#pragma acc declare link%>" , |
19996 | decl); |
19997 | error = true; |
19998 | continue; |
19999 | } |
20000 | break; |
20001 | |
20002 | default: |
20003 | if (global_bindings_p ()) |
20004 | { |
20005 | error_at (loc, "invalid OpenACC clause at file scope" ); |
20006 | error = true; |
20007 | continue; |
20008 | } |
20009 | if (DECL_EXTERNAL (decl)) |
20010 | { |
20011 | error_at (loc, |
20012 | "invalid use of %<extern%> variable %qD " |
20013 | "in %<#pragma acc declare%>" , decl); |
20014 | error = true; |
20015 | continue; |
20016 | } |
20017 | else if (TREE_PUBLIC (decl)) |
20018 | { |
20019 | error_at (loc, |
20020 | "invalid use of %<global%> variable %qD " |
20021 | "in %<#pragma acc declare%>" , decl); |
20022 | error = true; |
20023 | continue; |
20024 | } |
20025 | break; |
20026 | } |
20027 | |
20028 | if (!c_check_in_current_scope (decl)) |
20029 | { |
20030 | error_at (loc, |
20031 | "%qD must be a variable declared in the same scope as " |
20032 | "%<#pragma acc declare%>" , decl); |
20033 | error = true; |
20034 | continue; |
20035 | } |
20036 | |
20037 | if (lookup_attribute (attr_name: "omp declare target" , DECL_ATTRIBUTES (decl)) |
20038 | || lookup_attribute (attr_name: "omp declare target link" , |
20039 | DECL_ATTRIBUTES (decl))) |
20040 | { |
20041 | error_at (loc, "variable %qD used more than once with " |
20042 | "%<#pragma acc declare%>" , decl); |
20043 | error = true; |
20044 | continue; |
20045 | } |
20046 | |
20047 | if (!error) |
20048 | { |
20049 | tree id; |
20050 | |
20051 | if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK) |
20052 | id = get_identifier ("omp declare target link" ); |
20053 | else |
20054 | id = get_identifier ("omp declare target" ); |
20055 | |
20056 | DECL_ATTRIBUTES (decl) |
20057 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl)); |
20058 | |
20059 | if (global_bindings_p ()) |
20060 | { |
20061 | symtab_node *node = symtab_node::get (decl); |
20062 | if (node != NULL) |
20063 | { |
20064 | node->offloadable = 1; |
20065 | if (ENABLE_OFFLOADING) |
20066 | { |
20067 | g->have_offload = true; |
20068 | if (is_a <varpool_node *> (p: node)) |
20069 | vec_safe_push (v&: offload_vars, obj: decl); |
20070 | } |
20071 | } |
20072 | } |
20073 | } |
20074 | } |
20075 | |
20076 | if (error || global_bindings_p ()) |
20077 | return; |
20078 | |
20079 | stmt = make_node (OACC_DECLARE); |
20080 | TREE_TYPE (stmt) = void_type_node; |
20081 | OACC_DECLARE_CLAUSES (stmt) = clauses; |
20082 | SET_EXPR_LOCATION (stmt, pragma_loc); |
20083 | |
20084 | add_stmt (stmt); |
20085 | |
20086 | return; |
20087 | } |
20088 | |
20089 | /* OpenACC 2.0: |
20090 | # pragma acc enter data oacc-enter-data-clause[optseq] new-line |
20091 | |
20092 | or |
20093 | |
20094 | # pragma acc exit data oacc-exit-data-clause[optseq] new-line |
20095 | |
20096 | |
20097 | LOC is the location of the #pragma token. |
20098 | */ |
20099 | |
20100 | #define OACC_ENTER_DATA_CLAUSE_MASK \ |
20101 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20102 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20103 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
20104 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
20105 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
20106 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20107 | |
20108 | #define OACC_EXIT_DATA_CLAUSE_MASK \ |
20109 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20110 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20111 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
20112 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ |
20113 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ |
20114 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \ |
20115 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20116 | |
20117 | static void |
20118 | c_parser_oacc_enter_exit_data (c_parser *parser, bool enter) |
20119 | { |
20120 | location_t loc = c_parser_peek_token (parser)->location; |
20121 | tree clauses, stmt; |
20122 | const char *p = "" ; |
20123 | |
20124 | c_parser_consume_pragma (parser); |
20125 | |
20126 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
20127 | { |
20128 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20129 | c_parser_consume_token (parser); |
20130 | } |
20131 | |
20132 | if (strcmp (s1: p, s2: "data" ) != 0) |
20133 | { |
20134 | error_at (loc, "expected %<data%> after %<#pragma acc %s%>" , |
20135 | enter ? "enter" : "exit" ); |
20136 | parser->error = true; |
20137 | c_parser_skip_to_pragma_eol (parser); |
20138 | return; |
20139 | } |
20140 | |
20141 | if (enter) |
20142 | clauses = c_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK, |
20143 | where: "#pragma acc enter data" ); |
20144 | else |
20145 | clauses = c_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK, |
20146 | where: "#pragma acc exit data" ); |
20147 | |
20148 | if (omp_find_clause (clauses, kind: OMP_CLAUSE_MAP) == NULL_TREE) |
20149 | { |
20150 | error_at (loc, "%<#pragma acc %s data%> has no data movement clause" , |
20151 | enter ? "enter" : "exit" ); |
20152 | return; |
20153 | } |
20154 | |
20155 | stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA); |
20156 | TREE_TYPE (stmt) = void_type_node; |
20157 | OMP_STANDALONE_CLAUSES (stmt) = clauses; |
20158 | SET_EXPR_LOCATION (stmt, loc); |
20159 | add_stmt (stmt); |
20160 | } |
20161 | |
20162 | |
20163 | /* OpenACC 2.0: |
20164 | # pragma acc host_data oacc-data-clause[optseq] new-line |
20165 | structured-block |
20166 | */ |
20167 | |
20168 | #define OACC_HOST_DATA_CLAUSE_MASK \ |
20169 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_USE_DEVICE) \ |
20170 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20171 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) ) |
20172 | |
20173 | static tree |
20174 | c_parser_oacc_host_data (location_t loc, c_parser *parser, bool *if_p) |
20175 | { |
20176 | tree stmt, clauses, block; |
20177 | |
20178 | clauses = c_parser_oacc_all_clauses (parser, OACC_HOST_DATA_CLAUSE_MASK, |
20179 | where: "#pragma acc host_data" , finish_p: false); |
20180 | if (!omp_find_clause (clauses, kind: OMP_CLAUSE_USE_DEVICE_PTR)) |
20181 | { |
20182 | error_at (loc, "%<host_data%> construct requires %<use_device%> clause" ); |
20183 | return error_mark_node; |
20184 | } |
20185 | clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); |
20186 | block = c_begin_omp_parallel (); |
20187 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
20188 | stmt = c_finish_oacc_host_data (loc, clauses, block); |
20189 | return stmt; |
20190 | } |
20191 | |
20192 | |
20193 | /* OpenACC 2.0: |
20194 | |
20195 | # pragma acc loop oacc-loop-clause[optseq] new-line |
20196 | structured-block |
20197 | |
20198 | LOC is the location of the #pragma token. |
20199 | */ |
20200 | |
20201 | #define OACC_LOOP_CLAUSE_MASK \ |
20202 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \ |
20203 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ |
20204 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ |
20205 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ |
20206 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ |
20207 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ |
20208 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_AUTO) \ |
20209 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_INDEPENDENT) \ |
20210 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ |
20211 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_TILE) ) |
20212 | static tree |
20213 | c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, |
20214 | omp_clause_mask mask, tree *cclauses, bool *if_p) |
20215 | { |
20216 | bool is_parallel = ((mask >> PRAGMA_OACC_CLAUSE_REDUCTION) & 1) == 1; |
20217 | |
20218 | strcat (dest: p_name, src: " loop" ); |
20219 | mask |= OACC_LOOP_CLAUSE_MASK; |
20220 | |
20221 | tree clauses = c_parser_oacc_all_clauses (parser, mask, where: p_name, |
20222 | /*finish_p=*/cclauses == NULL, |
20223 | /*target=*/target_p: is_parallel); |
20224 | if (cclauses) |
20225 | { |
20226 | clauses = c_oacc_split_loop_clauses (clauses, cclauses, is_parallel); |
20227 | if (*cclauses) |
20228 | *cclauses = c_finish_omp_clauses (*cclauses, C_ORT_ACC_TARGET); |
20229 | if (clauses) |
20230 | clauses = c_finish_omp_clauses (clauses, C_ORT_ACC); |
20231 | } |
20232 | |
20233 | tree block = c_begin_compound_stmt (true); |
20234 | tree stmt = c_parser_omp_for_loop (loc, parser, OACC_LOOP, clauses, NULL, |
20235 | if_p); |
20236 | block = c_end_compound_stmt (loc, block, true); |
20237 | add_stmt (block); |
20238 | |
20239 | return stmt; |
20240 | } |
20241 | |
20242 | /* OpenACC 2.0: |
20243 | # pragma acc kernels oacc-kernels-clause[optseq] new-line |
20244 | structured-block |
20245 | |
20246 | or |
20247 | |
20248 | # pragma acc parallel oacc-parallel-clause[optseq] new-line |
20249 | structured-block |
20250 | |
20251 | OpenACC 2.6: |
20252 | |
20253 | # pragma acc serial oacc-serial-clause[optseq] new-line |
20254 | structured-block |
20255 | |
20256 | LOC is the location of the #pragma token. |
20257 | */ |
20258 | |
20259 | #define OACC_KERNELS_CLAUSE_MASK \ |
20260 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20261 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
20262 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
20263 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
20264 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
20265 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
20266 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
20267 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
20268 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20269 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
20270 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ |
20271 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ |
20272 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ |
20273 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
20274 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ |
20275 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20276 | |
20277 | #define OACC_PARALLEL_CLAUSE_MASK \ |
20278 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20279 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
20280 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
20281 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
20282 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
20283 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
20284 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
20285 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
20286 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20287 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
20288 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ |
20289 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ |
20290 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ |
20291 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ |
20292 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ |
20293 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ |
20294 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
20295 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ |
20296 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20297 | |
20298 | #define OACC_SERIAL_CLAUSE_MASK \ |
20299 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20300 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ |
20301 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ |
20302 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ |
20303 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ |
20304 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ |
20305 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \ |
20306 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ |
20307 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20308 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \ |
20309 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \ |
20310 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \ |
20311 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ |
20312 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ |
20313 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
20314 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20315 | |
20316 | static tree |
20317 | c_parser_oacc_compute (location_t loc, c_parser *parser, |
20318 | enum pragma_kind p_kind, char *p_name, bool *if_p) |
20319 | { |
20320 | omp_clause_mask mask; |
20321 | enum tree_code code; |
20322 | switch (p_kind) |
20323 | { |
20324 | case PRAGMA_OACC_KERNELS: |
20325 | strcat (dest: p_name, src: " kernels" ); |
20326 | mask = OACC_KERNELS_CLAUSE_MASK; |
20327 | code = OACC_KERNELS; |
20328 | break; |
20329 | case PRAGMA_OACC_PARALLEL: |
20330 | strcat (dest: p_name, src: " parallel" ); |
20331 | mask = OACC_PARALLEL_CLAUSE_MASK; |
20332 | code = OACC_PARALLEL; |
20333 | break; |
20334 | case PRAGMA_OACC_SERIAL: |
20335 | strcat (dest: p_name, src: " serial" ); |
20336 | mask = OACC_SERIAL_CLAUSE_MASK; |
20337 | code = OACC_SERIAL; |
20338 | break; |
20339 | default: |
20340 | gcc_unreachable (); |
20341 | } |
20342 | |
20343 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
20344 | { |
20345 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20346 | if (strcmp (s1: p, s2: "loop" ) == 0) |
20347 | { |
20348 | c_parser_consume_token (parser); |
20349 | tree block = c_begin_omp_parallel (); |
20350 | tree clauses; |
20351 | c_parser_oacc_loop (loc, parser, p_name, mask, cclauses: &clauses, if_p); |
20352 | return c_finish_omp_construct (loc, code, block, clauses); |
20353 | } |
20354 | } |
20355 | |
20356 | tree clauses = c_parser_oacc_all_clauses (parser, mask, where: p_name, |
20357 | /*finish_p=*/true, |
20358 | /*target=*/target_p: true); |
20359 | |
20360 | tree block = c_begin_omp_parallel (); |
20361 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
20362 | |
20363 | return c_finish_omp_construct (loc, code, block, clauses); |
20364 | } |
20365 | |
20366 | /* OpenACC 2.0: |
20367 | # pragma acc routine oacc-routine-clause[optseq] new-line |
20368 | function-definition |
20369 | |
20370 | # pragma acc routine ( name ) oacc-routine-clause[optseq] new-line |
20371 | */ |
20372 | |
20373 | #define OACC_ROUTINE_CLAUSE_MASK \ |
20374 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ |
20375 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ |
20376 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ |
20377 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ |
20378 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) |
20379 | |
20380 | /* Parse an OpenACC routine directive. For named directives, we apply |
20381 | immediately to the named function. For unnamed ones we then parse |
20382 | a declaration or definition, which must be for a function. */ |
20383 | |
20384 | static void |
20385 | c_parser_oacc_routine (c_parser *parser, enum pragma_context context) |
20386 | { |
20387 | gcc_checking_assert (context == pragma_external); |
20388 | |
20389 | oacc_routine_data data; |
20390 | data.error_seen = false; |
20391 | data.fndecl_seen = false; |
20392 | data.loc = c_parser_peek_token (parser)->location; |
20393 | |
20394 | c_parser_consume_pragma (parser); |
20395 | |
20396 | /* Look for optional '( name )'. */ |
20397 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
20398 | { |
20399 | c_parser_consume_token (parser); /* '(' */ |
20400 | |
20401 | tree decl = NULL_TREE; |
20402 | c_token *name_token = c_parser_peek_token (parser); |
20403 | location_t name_loc = name_token->location; |
20404 | if (name_token->type == CPP_NAME |
20405 | && (name_token->id_kind == C_ID_ID |
20406 | || name_token->id_kind == C_ID_TYPENAME)) |
20407 | { |
20408 | decl = lookup_name (name_token->value); |
20409 | if (!decl) |
20410 | error_at (name_loc, |
20411 | "%qE has not been declared" , name_token->value); |
20412 | c_parser_consume_token (parser); |
20413 | } |
20414 | else |
20415 | c_parser_error (parser, gmsgid: "expected function name" ); |
20416 | |
20417 | if (!decl |
20418 | || !c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
20419 | { |
20420 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
20421 | return; |
20422 | } |
20423 | |
20424 | data.clauses |
20425 | = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, |
20426 | where: "#pragma acc routine" ); |
20427 | /* The clauses are in reverse order; fix that to make later diagnostic |
20428 | emission easier. */ |
20429 | data.clauses = nreverse (data.clauses); |
20430 | |
20431 | if (TREE_CODE (decl) != FUNCTION_DECL) |
20432 | { |
20433 | error_at (name_loc, "%qD does not refer to a function" , decl); |
20434 | return; |
20435 | } |
20436 | |
20437 | c_finish_oacc_routine (&data, decl, false); |
20438 | } |
20439 | else /* No optional '( name )'. */ |
20440 | { |
20441 | data.clauses |
20442 | = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, |
20443 | where: "#pragma acc routine" ); |
20444 | /* The clauses are in reverse order; fix that to make later diagnostic |
20445 | emission easier. */ |
20446 | data.clauses = nreverse (data.clauses); |
20447 | |
20448 | /* Emit a helpful diagnostic if there's another pragma following this |
20449 | one. Also don't allow a static assertion declaration, as in the |
20450 | following we'll just parse a *single* "declaration or function |
20451 | definition", and the static assertion counts an one. */ |
20452 | if (c_parser_next_token_is (parser, type: CPP_PRAGMA) |
20453 | || c_parser_next_token_is_keyword (parser, keyword: RID_STATIC_ASSERT)) |
20454 | { |
20455 | error_at (data.loc, |
20456 | "%<#pragma acc routine%> not immediately followed by" |
20457 | " function declaration or definition" ); |
20458 | /* ..., and then just keep going. */ |
20459 | return; |
20460 | } |
20461 | |
20462 | /* We only have to consider the pragma_external case here. */ |
20463 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
20464 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION) |
20465 | { |
20466 | int ext = disable_extension_diagnostics (); |
20467 | do |
20468 | c_parser_consume_token (parser); |
20469 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
20470 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION); |
20471 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
20472 | NULL, NULL, have_attrs: false, NULL, oacc_routine_data: &data); |
20473 | restore_extension_diagnostics (flags: ext); |
20474 | } |
20475 | else |
20476 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
20477 | NULL, NULL, have_attrs: false, NULL, oacc_routine_data: &data); |
20478 | } |
20479 | } |
20480 | |
20481 | /* Finalize an OpenACC routine pragma, applying it to FNDECL. |
20482 | IS_DEFN is true if we're applying it to the definition. */ |
20483 | |
20484 | static void |
20485 | c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, |
20486 | bool is_defn) |
20487 | { |
20488 | /* Keep going if we're in error reporting mode. */ |
20489 | if (data->error_seen |
20490 | || fndecl == error_mark_node) |
20491 | return; |
20492 | |
20493 | if (data->fndecl_seen) |
20494 | { |
20495 | error_at (data->loc, |
20496 | "%<#pragma acc routine%> not immediately followed by" |
20497 | " a single function declaration or definition" ); |
20498 | data->error_seen = true; |
20499 | return; |
20500 | } |
20501 | if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) |
20502 | { |
20503 | error_at (data->loc, |
20504 | "%<#pragma acc routine%> not immediately followed by" |
20505 | " function declaration or definition" ); |
20506 | data->error_seen = true; |
20507 | return; |
20508 | } |
20509 | |
20510 | int compatible |
20511 | = oacc_verify_routine_clauses (fndecl, &data->clauses, data->loc, |
20512 | "#pragma acc routine" ); |
20513 | if (compatible < 0) |
20514 | { |
20515 | data->error_seen = true; |
20516 | return; |
20517 | } |
20518 | if (compatible > 0) |
20519 | { |
20520 | } |
20521 | else |
20522 | { |
20523 | if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) |
20524 | { |
20525 | error_at (data->loc, |
20526 | TREE_USED (fndecl) |
20527 | ? G_("%<#pragma acc routine%> must be applied before use" ) |
20528 | : G_("%<#pragma acc routine%> must be applied before" |
20529 | " definition" )); |
20530 | data->error_seen = true; |
20531 | return; |
20532 | } |
20533 | |
20534 | /* Set the routine's level of parallelism. */ |
20535 | tree dims = oacc_build_routine_dims (clauses: data->clauses); |
20536 | oacc_replace_fn_attrib (fn: fndecl, dims); |
20537 | |
20538 | /* Add an "omp declare target" attribute. */ |
20539 | DECL_ATTRIBUTES (fndecl) |
20540 | = tree_cons (get_identifier ("omp declare target" ), |
20541 | data->clauses, DECL_ATTRIBUTES (fndecl)); |
20542 | } |
20543 | |
20544 | /* Remember that we've used this "#pragma acc routine". */ |
20545 | data->fndecl_seen = true; |
20546 | } |
20547 | |
20548 | /* OpenACC 2.0: |
20549 | # pragma acc update oacc-update-clause[optseq] new-line |
20550 | */ |
20551 | |
20552 | #define OACC_UPDATE_CLAUSE_MASK \ |
20553 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ |
20554 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \ |
20555 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \ |
20556 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ |
20557 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) \ |
20558 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ |
20559 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) |
20560 | |
20561 | static void |
20562 | c_parser_oacc_update (c_parser *parser) |
20563 | { |
20564 | location_t loc = c_parser_peek_token (parser)->location; |
20565 | |
20566 | c_parser_consume_pragma (parser); |
20567 | |
20568 | tree clauses = c_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK, |
20569 | where: "#pragma acc update" ); |
20570 | if (omp_find_clause (clauses, kind: OMP_CLAUSE_MAP) == NULL_TREE) |
20571 | { |
20572 | error_at (loc, |
20573 | "%<#pragma acc update%> must contain at least one " |
20574 | "%<device%> or %<host%> or %<self%> clause" ); |
20575 | return; |
20576 | } |
20577 | |
20578 | if (parser->error) |
20579 | return; |
20580 | |
20581 | tree stmt = make_node (OACC_UPDATE); |
20582 | TREE_TYPE (stmt) = void_type_node; |
20583 | OACC_UPDATE_CLAUSES (stmt) = clauses; |
20584 | SET_EXPR_LOCATION (stmt, loc); |
20585 | add_stmt (stmt); |
20586 | } |
20587 | |
20588 | /* OpenACC 2.0: |
20589 | # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line |
20590 | |
20591 | LOC is the location of the #pragma token. |
20592 | */ |
20593 | |
20594 | #define OACC_WAIT_CLAUSE_MASK \ |
20595 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) |
20596 | |
20597 | static tree |
20598 | c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) |
20599 | { |
20600 | tree clauses, list = NULL_TREE, stmt = NULL_TREE; |
20601 | |
20602 | if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) |
20603 | list = c_parser_oacc_wait_list (parser, clause_loc: loc, list); |
20604 | |
20605 | strcpy (dest: p_name, src: " wait" ); |
20606 | clauses = c_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, where: p_name); |
20607 | stmt = c_finish_oacc_wait (loc, list, clauses); |
20608 | add_stmt (stmt); |
20609 | |
20610 | return stmt; |
20611 | } |
20612 | |
20613 | struct c_omp_loc_tree |
20614 | { |
20615 | location_t loc; |
20616 | tree var; |
20617 | }; |
20618 | |
20619 | /* Check whether the expression used in the allocator clause is declared or |
20620 | modified between the variable declaration and its allocate directive. */ |
20621 | static tree |
20622 | c_check_omp_allocate_allocator_r (tree *tp, int *, void *data) |
20623 | { |
20624 | tree var = ((struct c_omp_loc_tree *) data)->var; |
20625 | location_t loc = ((struct c_omp_loc_tree *) data)->loc; |
20626 | if (TREE_CODE (*tp) == VAR_DECL && c_check_in_current_scope (*tp)) |
20627 | { |
20628 | if (linemap_location_before_p (set: line_table, DECL_SOURCE_LOCATION (var), |
20629 | DECL_SOURCE_LOCATION (*tp))) |
20630 | { |
20631 | error_at (loc, "variable %qD used in the %<allocator%> clause must " |
20632 | "be declared before %qD" , *tp, var); |
20633 | inform (DECL_SOURCE_LOCATION (*tp), "declared here" ); |
20634 | inform (DECL_SOURCE_LOCATION (var), |
20635 | "to be allocated variable declared here" ); |
20636 | return *tp; |
20637 | } |
20638 | else |
20639 | { |
20640 | gcc_assert (cur_stmt_list |
20641 | && TREE_CODE (cur_stmt_list) == STATEMENT_LIST); |
20642 | |
20643 | tree_stmt_iterator l = tsi_last (cur_stmt_list); |
20644 | while (!tsi_end_p (i: l)) |
20645 | { |
20646 | if (linemap_location_before_p (set: line_table, EXPR_LOCATION (*l), |
20647 | DECL_SOURCE_LOCATION (var))) |
20648 | break; |
20649 | if (TREE_CODE (*l) == MODIFY_EXPR |
20650 | && TREE_OPERAND (*l, 0) == *tp) |
20651 | { |
20652 | error_at (loc, |
20653 | "variable %qD used in the %<allocator%> clause " |
20654 | "must not be modified between declaration of %qD " |
20655 | "and its %<allocate%> directive" , *tp, var); |
20656 | inform (EXPR_LOCATION (*l), "modified here" ); |
20657 | inform (DECL_SOURCE_LOCATION (var), |
20658 | "to be allocated variable declared here" ); |
20659 | return *tp; |
20660 | } |
20661 | --l; |
20662 | } |
20663 | } |
20664 | } |
20665 | return NULL_TREE; |
20666 | } |
20667 | |
20668 | /* OpenMP 5.x: |
20669 | # pragma omp allocate (list) clauses |
20670 | |
20671 | OpenMP 5.0 clause: |
20672 | allocator (omp_allocator_handle_t expression) |
20673 | |
20674 | OpenMP 5.1 additional clause: |
20675 | align (constant-expression)] */ |
20676 | |
20677 | static void |
20678 | c_parser_omp_allocate (c_parser *parser) |
20679 | { |
20680 | tree alignment = NULL_TREE; |
20681 | tree allocator = NULL_TREE; |
20682 | c_parser_consume_pragma (parser); |
20683 | location_t loc = c_parser_peek_token (parser)->location; |
20684 | location_t allocator_loc = UNKNOWN_LOCATION; |
20685 | tree nl = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ALLOCATE, NULL_TREE); |
20686 | do |
20687 | { |
20688 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
20689 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
20690 | c_parser_consume_token (parser); |
20691 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
20692 | break; |
20693 | matching_parens parens; |
20694 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20695 | c_parser_consume_token (parser); |
20696 | location_t expr_loc = c_parser_peek_token (parser)->location; |
20697 | if (strcmp (s1: "align" , s2: p) != 0 && strcmp (s1: "allocator" , s2: p) != 0) |
20698 | { |
20699 | error_at (c_parser_peek_token (parser)->location, |
20700 | "expected %<allocator%> or %<align%>" ); |
20701 | break; |
20702 | } |
20703 | if (!parens.require_open (parser)) |
20704 | break; |
20705 | |
20706 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
20707 | expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); |
20708 | expr_loc = c_parser_peek_token (parser)->location; |
20709 | if (expr.value == error_mark_node) |
20710 | ; |
20711 | else if (p[2] == 'i' && alignment) |
20712 | { |
20713 | error_at (expr_loc, "too many %qs clauses" , "align" ); |
20714 | break; |
20715 | } |
20716 | else if (p[2] == 'i') |
20717 | { |
20718 | alignment = c_fully_fold (expr.value, false, NULL); |
20719 | if (TREE_CODE (alignment) != INTEGER_CST |
20720 | || !INTEGRAL_TYPE_P (TREE_TYPE (alignment)) |
20721 | || tree_int_cst_sgn (alignment) != 1 |
20722 | || !integer_pow2p (alignment)) |
20723 | { |
20724 | error_at (expr_loc, "%<align%> clause argument needs to be " |
20725 | "positive constant power of two integer " |
20726 | "expression" ); |
20727 | alignment = NULL_TREE; |
20728 | } |
20729 | } |
20730 | else if (allocator) |
20731 | { |
20732 | error_at (expr_loc, "too many %qs clauses" , "allocator" ); |
20733 | break; |
20734 | } |
20735 | else |
20736 | { |
20737 | allocator = c_fully_fold (expr.value, false, NULL); |
20738 | allocator_loc = expr_loc; |
20739 | tree orig_type |
20740 | = expr.original_type ? expr.original_type : TREE_TYPE (allocator); |
20741 | orig_type = TYPE_MAIN_VARIANT (orig_type); |
20742 | if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) |
20743 | || TREE_CODE (orig_type) != ENUMERAL_TYPE |
20744 | || TYPE_NAME (orig_type) |
20745 | != get_identifier ("omp_allocator_handle_t" )) |
20746 | { |
20747 | error_at (expr_loc, |
20748 | "%<allocator%> clause allocator expression has type " |
20749 | "%qT rather than %<omp_allocator_handle_t%>" , |
20750 | TREE_TYPE (allocator)); |
20751 | allocator = NULL_TREE; |
20752 | } |
20753 | } |
20754 | parens.skip_until_found_close (parser); |
20755 | } while (true); |
20756 | c_parser_skip_to_pragma_eol (parser); |
20757 | |
20758 | c_mark_decl_jump_unsafe_in_current_scope (); |
20759 | for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c)) |
20760 | { |
20761 | tree var = OMP_CLAUSE_DECL (c); |
20762 | if (TREE_CODE (var) == PARM_DECL) |
20763 | { |
20764 | error_at (OMP_CLAUSE_LOCATION (nl), |
20765 | "function parameter %qD may not appear as list item in an " |
20766 | "%<allocate%> directive" , var); |
20767 | continue; |
20768 | } |
20769 | if (!c_check_in_current_scope (var)) |
20770 | { |
20771 | error_at (OMP_CLAUSE_LOCATION (nl), |
20772 | "%<allocate%> directive must be in the same scope as %qD" , |
20773 | var); |
20774 | inform (DECL_SOURCE_LOCATION (var), "declared here" ); |
20775 | continue; |
20776 | } |
20777 | if (lookup_attribute (attr_name: "omp allocate" , DECL_ATTRIBUTES (var))) |
20778 | { |
20779 | error_at (OMP_CLAUSE_LOCATION (nl), |
20780 | "%qD already appeared as list item in an " |
20781 | "%<allocate%> directive" , var); |
20782 | continue; |
20783 | } |
20784 | if (TREE_STATIC (var)) |
20785 | { |
20786 | if (allocator == NULL_TREE && allocator_loc == UNKNOWN_LOCATION) |
20787 | error_at (loc, "%<allocator%> clause required for " |
20788 | "static variable %qD" , var); |
20789 | else if (allocator |
20790 | && (wi::to_widest (t: allocator) < 1 |
20791 | || wi::to_widest (t: allocator) > 8)) |
20792 | /* 8 = largest predefined memory allocator. */ |
20793 | error_at (allocator_loc, |
20794 | "%<allocator%> clause requires a predefined allocator as " |
20795 | "%qD is static" , var); |
20796 | else |
20797 | sorry_at (OMP_CLAUSE_LOCATION (nl), |
20798 | "%<#pragma omp allocate%> for static variables like " |
20799 | "%qD not yet supported" , var); |
20800 | continue; |
20801 | } |
20802 | if (allocator) |
20803 | { |
20804 | struct c_omp_loc_tree data |
20805 | = {EXPR_LOC_OR_LOC (allocator, OMP_CLAUSE_LOCATION (nl)), .var: var}; |
20806 | walk_tree (&allocator, c_check_omp_allocate_allocator_r, &data, NULL); |
20807 | } |
20808 | DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("omp allocate" ), |
20809 | build_tree_list (allocator, alignment), |
20810 | DECL_ATTRIBUTES (var)); |
20811 | } |
20812 | } |
20813 | |
20814 | /* OpenMP 2.5: |
20815 | # pragma omp atomic new-line |
20816 | expression-stmt |
20817 | |
20818 | expression-stmt: |
20819 | x binop= expr | x++ | ++x | x-- | --x |
20820 | binop: |
20821 | +, *, -, /, &, ^, |, <<, >> |
20822 | |
20823 | where x is an lvalue expression with scalar type. |
20824 | |
20825 | OpenMP 3.1: |
20826 | # pragma omp atomic new-line |
20827 | update-stmt |
20828 | |
20829 | # pragma omp atomic read new-line |
20830 | read-stmt |
20831 | |
20832 | # pragma omp atomic write new-line |
20833 | write-stmt |
20834 | |
20835 | # pragma omp atomic update new-line |
20836 | update-stmt |
20837 | |
20838 | # pragma omp atomic capture new-line |
20839 | capture-stmt |
20840 | |
20841 | # pragma omp atomic capture new-line |
20842 | capture-block |
20843 | |
20844 | read-stmt: |
20845 | v = x |
20846 | write-stmt: |
20847 | x = expr |
20848 | update-stmt: |
20849 | expression-stmt | x = x binop expr |
20850 | capture-stmt: |
20851 | v = expression-stmt |
20852 | capture-block: |
20853 | { v = x; update-stmt; } | { update-stmt; v = x; } |
20854 | |
20855 | OpenMP 4.0: |
20856 | update-stmt: |
20857 | expression-stmt | x = x binop expr | x = expr binop x |
20858 | capture-stmt: |
20859 | v = update-stmt |
20860 | capture-block: |
20861 | { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; } |
20862 | |
20863 | OpenMP 5.1: |
20864 | # pragma omp atomic compare new-line |
20865 | conditional-update-atomic |
20866 | |
20867 | # pragma omp atomic compare capture new-line |
20868 | conditional-update-capture-atomic |
20869 | |
20870 | conditional-update-atomic: |
20871 | cond-expr-stmt | cond-update-stmt |
20872 | cond-expr-stmt: |
20873 | x = expr ordop x ? expr : x; |
20874 | x = x ordop expr ? expr : x; |
20875 | x = x == e ? d : x; |
20876 | cond-update-stmt: |
20877 | if (expr ordop x) { x = expr; } |
20878 | if (x ordop expr) { x = expr; } |
20879 | if (x == e) { x = d; } |
20880 | ordop: |
20881 | <, > |
20882 | conditional-update-capture-atomic: |
20883 | v = cond-expr-stmt |
20884 | { v = x; cond-expr-stmt } |
20885 | { cond-expr-stmt v = x; } |
20886 | { v = x; cond-update-stmt } |
20887 | { cond-update-stmt v = x; } |
20888 | if (x == e) { x = d; } else { v = x; } |
20889 | { r = x == e; if (r) { x = d; } } |
20890 | { r = x == e; if (r) { x = d; } else { v = x; } } |
20891 | |
20892 | where x, r and v are lvalue expressions with scalar type, |
20893 | expr, e and d are expressions with scalar type and e might be |
20894 | the same as v. |
20895 | |
20896 | LOC is the location of the #pragma token. */ |
20897 | |
20898 | static void |
20899 | c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc) |
20900 | { |
20901 | tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE; |
20902 | tree lhs1 = NULL_TREE, rhs1 = NULL_TREE; |
20903 | tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE; |
20904 | enum tree_code code = ERROR_MARK, opcode = NOP_EXPR; |
20905 | enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED; |
20906 | struct c_expr expr; |
20907 | location_t eloc; |
20908 | bool structured_block = false; |
20909 | bool swapped = false; |
20910 | bool non_lvalue_p; |
20911 | tree clauses = NULL_TREE; |
20912 | bool capture = false; |
20913 | bool compare = false; |
20914 | bool weak = false; |
20915 | enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED; |
20916 | bool no_semicolon = false; |
20917 | bool = false; |
20918 | |
20919 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
20920 | { |
20921 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
20922 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
20923 | c_parser_consume_token (parser); |
20924 | |
20925 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
20926 | { |
20927 | const char *p |
20928 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20929 | location_t cloc = c_parser_peek_token (parser)->location; |
20930 | enum tree_code new_code = ERROR_MARK; |
20931 | enum omp_memory_order new_memory_order |
20932 | = OMP_MEMORY_ORDER_UNSPECIFIED; |
20933 | bool new_capture = false; |
20934 | bool new_compare = false; |
20935 | bool new_weak = false; |
20936 | enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED; |
20937 | |
20938 | if (!strcmp (s1: p, s2: "read" )) |
20939 | new_code = OMP_ATOMIC_READ; |
20940 | else if (!strcmp (s1: p, s2: "write" )) |
20941 | new_code = NOP_EXPR; |
20942 | else if (!strcmp (s1: p, s2: "update" )) |
20943 | new_code = OMP_ATOMIC; |
20944 | else if (openacc && !strcmp (s1: p, s2: "capture" )) |
20945 | new_code = OMP_ATOMIC_CAPTURE_NEW; |
20946 | else if (openacc) |
20947 | { |
20948 | p = NULL; |
20949 | error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " |
20950 | "or %<capture%> clause" ); |
20951 | } |
20952 | else if (!strcmp (s1: p, s2: "capture" )) |
20953 | new_capture = true; |
20954 | else if (!strcmp (s1: p, s2: "compare" )) |
20955 | new_compare = true; |
20956 | else if (!strcmp (s1: p, s2: "weak" )) |
20957 | new_weak = true; |
20958 | else if (!strcmp (s1: p, s2: "fail" )) |
20959 | { |
20960 | matching_parens parens; |
20961 | |
20962 | c_parser_consume_token (parser); |
20963 | if (!parens.require_open (parser)) |
20964 | continue; |
20965 | |
20966 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
20967 | { |
20968 | const char *q |
20969 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
20970 | |
20971 | if (!strcmp (s1: q, s2: "seq_cst" )) |
20972 | new_fail = OMP_MEMORY_ORDER_SEQ_CST; |
20973 | else if (!strcmp (s1: q, s2: "acquire" )) |
20974 | new_fail = OMP_MEMORY_ORDER_ACQUIRE; |
20975 | else if (!strcmp (s1: q, s2: "relaxed" )) |
20976 | new_fail = OMP_MEMORY_ORDER_RELAXED; |
20977 | } |
20978 | |
20979 | if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED) |
20980 | { |
20981 | c_parser_consume_token (parser); |
20982 | if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) |
20983 | error_at (cloc, "too many %qs clauses" , "fail" ); |
20984 | else |
20985 | fail = new_fail; |
20986 | } |
20987 | else |
20988 | c_parser_error (parser, gmsgid: "expected %<seq_cst%>, %<acquire%> " |
20989 | "or %<relaxed%>" ); |
20990 | parens.skip_until_found_close (parser); |
20991 | continue; |
20992 | } |
20993 | else if (!strcmp (s1: p, s2: "seq_cst" )) |
20994 | new_memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
20995 | else if (!strcmp (s1: p, s2: "acq_rel" )) |
20996 | new_memory_order = OMP_MEMORY_ORDER_ACQ_REL; |
20997 | else if (!strcmp (s1: p, s2: "release" )) |
20998 | new_memory_order = OMP_MEMORY_ORDER_RELEASE; |
20999 | else if (!strcmp (s1: p, s2: "acquire" )) |
21000 | new_memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
21001 | else if (!strcmp (s1: p, s2: "relaxed" )) |
21002 | new_memory_order = OMP_MEMORY_ORDER_RELAXED; |
21003 | else if (!strcmp (s1: p, s2: "hint" )) |
21004 | { |
21005 | c_parser_consume_token (parser); |
21006 | clauses = c_parser_omp_clause_hint (parser, list: clauses); |
21007 | continue; |
21008 | } |
21009 | else |
21010 | { |
21011 | p = NULL; |
21012 | error_at (cloc, "expected %<read%>, %<write%>, %<update%>, " |
21013 | "%<capture%>, %<compare%>, %<weak%>, %<fail%>, " |
21014 | "%<seq_cst%>, %<acq_rel%>, %<release%>, " |
21015 | "%<relaxed%> or %<hint%> clause" ); |
21016 | } |
21017 | if (p) |
21018 | { |
21019 | if (new_code != ERROR_MARK) |
21020 | { |
21021 | /* OpenACC permits 'update capture'. */ |
21022 | if (openacc |
21023 | && code == OMP_ATOMIC |
21024 | && new_code == OMP_ATOMIC_CAPTURE_NEW) |
21025 | code = new_code; |
21026 | else if (code != ERROR_MARK) |
21027 | error_at (cloc, "too many atomic clauses" ); |
21028 | else |
21029 | code = new_code; |
21030 | } |
21031 | else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) |
21032 | { |
21033 | if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED) |
21034 | error_at (cloc, "too many memory order clauses" ); |
21035 | else |
21036 | memory_order = new_memory_order; |
21037 | } |
21038 | else if (new_capture) |
21039 | { |
21040 | if (capture) |
21041 | error_at (cloc, "too many %qs clauses" , "capture" ); |
21042 | else |
21043 | capture = true; |
21044 | } |
21045 | else if (new_compare) |
21046 | { |
21047 | if (compare) |
21048 | error_at (cloc, "too many %qs clauses" , "compare" ); |
21049 | else |
21050 | compare = true; |
21051 | } |
21052 | else if (new_weak) |
21053 | { |
21054 | if (weak) |
21055 | error_at (cloc, "too many %qs clauses" , "weak" ); |
21056 | else |
21057 | weak = true; |
21058 | } |
21059 | c_parser_consume_token (parser); |
21060 | continue; |
21061 | } |
21062 | } |
21063 | break; |
21064 | } |
21065 | c_parser_skip_to_pragma_eol (parser); |
21066 | |
21067 | if (code == ERROR_MARK) |
21068 | code = OMP_ATOMIC; |
21069 | if (capture) |
21070 | { |
21071 | if (code != OMP_ATOMIC) |
21072 | error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " |
21073 | "clauses" , "capture" ); |
21074 | else |
21075 | code = OMP_ATOMIC_CAPTURE_NEW; |
21076 | } |
21077 | if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW) |
21078 | { |
21079 | error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> " |
21080 | "clauses" , "compare" ); |
21081 | compare = false; |
21082 | } |
21083 | if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare) |
21084 | { |
21085 | error_at (loc, "%qs clause requires %qs clause" , "fail" , "compare" ); |
21086 | fail = OMP_MEMORY_ORDER_UNSPECIFIED; |
21087 | } |
21088 | if (weak && !compare) |
21089 | { |
21090 | error_at (loc, "%qs clause requires %qs clause" , "weak" , "compare" ); |
21091 | weak = false; |
21092 | } |
21093 | if (openacc) |
21094 | memory_order = OMP_MEMORY_ORDER_RELAXED; |
21095 | else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED) |
21096 | { |
21097 | omp_requires_mask |
21098 | = (enum omp_requires) (omp_requires_mask |
21099 | | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED); |
21100 | switch ((enum omp_memory_order) |
21101 | (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER)) |
21102 | { |
21103 | case OMP_MEMORY_ORDER_UNSPECIFIED: |
21104 | case OMP_MEMORY_ORDER_RELAXED: |
21105 | memory_order = OMP_MEMORY_ORDER_RELAXED; |
21106 | break; |
21107 | case OMP_MEMORY_ORDER_SEQ_CST: |
21108 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
21109 | break; |
21110 | case OMP_MEMORY_ORDER_ACQUIRE: |
21111 | if (code == NOP_EXPR) /* atomic write */ |
21112 | { |
21113 | error_at (loc, "%<#pragma omp atomic write%> incompatible with " |
21114 | "%<acquire%> clause implicitly provided by a " |
21115 | "%<requires%> directive" ); |
21116 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
21117 | } |
21118 | else |
21119 | memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
21120 | break; |
21121 | case OMP_MEMORY_ORDER_RELEASE: |
21122 | if (code == OMP_ATOMIC_READ) |
21123 | { |
21124 | error_at (loc, "%<#pragma omp atomic read%> incompatible with " |
21125 | "%<release%> clause implicitly provided by a " |
21126 | "%<requires%> directive" ); |
21127 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
21128 | } |
21129 | else |
21130 | memory_order = OMP_MEMORY_ORDER_RELEASE; |
21131 | break; |
21132 | case OMP_MEMORY_ORDER_ACQ_REL: |
21133 | switch (code) |
21134 | { |
21135 | case OMP_ATOMIC_READ: |
21136 | memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
21137 | break; |
21138 | case NOP_EXPR: /* atomic write */ |
21139 | memory_order = OMP_MEMORY_ORDER_RELEASE; |
21140 | break; |
21141 | default: |
21142 | memory_order = OMP_MEMORY_ORDER_ACQ_REL; |
21143 | break; |
21144 | } |
21145 | break; |
21146 | default: |
21147 | gcc_unreachable (); |
21148 | } |
21149 | } |
21150 | else |
21151 | switch (code) |
21152 | { |
21153 | case OMP_ATOMIC_READ: |
21154 | if (memory_order == OMP_MEMORY_ORDER_RELEASE) |
21155 | { |
21156 | error_at (loc, "%<#pragma omp atomic read%> incompatible with " |
21157 | "%<release%> clause" ); |
21158 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
21159 | } |
21160 | else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) |
21161 | memory_order = OMP_MEMORY_ORDER_ACQUIRE; |
21162 | break; |
21163 | case NOP_EXPR: /* atomic write */ |
21164 | if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) |
21165 | { |
21166 | error_at (loc, "%<#pragma omp atomic write%> incompatible with " |
21167 | "%<acquire%> clause" ); |
21168 | memory_order = OMP_MEMORY_ORDER_SEQ_CST; |
21169 | } |
21170 | else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) |
21171 | memory_order = OMP_MEMORY_ORDER_RELEASE; |
21172 | break; |
21173 | default: |
21174 | break; |
21175 | } |
21176 | if (fail != OMP_MEMORY_ORDER_UNSPECIFIED) |
21177 | memory_order |
21178 | = (enum omp_memory_order) (memory_order |
21179 | | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT)); |
21180 | |
21181 | switch (code) |
21182 | { |
21183 | case OMP_ATOMIC_READ: |
21184 | case NOP_EXPR: /* atomic write */ |
21185 | v = c_parser_cast_expression (parser, NULL).value; |
21186 | non_lvalue_p = !lvalue_p (v); |
21187 | v = c_fully_fold (v, false, NULL, true); |
21188 | if (v == error_mark_node) |
21189 | goto saw_error; |
21190 | if (non_lvalue_p) |
21191 | v = non_lvalue (v); |
21192 | loc = c_parser_peek_token (parser)->location; |
21193 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
21194 | goto saw_error; |
21195 | if (code == NOP_EXPR) |
21196 | { |
21197 | lhs = c_parser_expression (parser).value; |
21198 | lhs = c_fully_fold (lhs, false, NULL); |
21199 | if (lhs == error_mark_node) |
21200 | goto saw_error; |
21201 | } |
21202 | else |
21203 | { |
21204 | lhs = c_parser_cast_expression (parser, NULL).value; |
21205 | non_lvalue_p = !lvalue_p (lhs); |
21206 | lhs = c_fully_fold (lhs, false, NULL, true); |
21207 | if (lhs == error_mark_node) |
21208 | goto saw_error; |
21209 | if (non_lvalue_p) |
21210 | lhs = non_lvalue (lhs); |
21211 | } |
21212 | if (code == NOP_EXPR) |
21213 | { |
21214 | /* atomic write is represented by OMP_ATOMIC with NOP_EXPR |
21215 | opcode. */ |
21216 | code = OMP_ATOMIC; |
21217 | rhs = lhs; |
21218 | lhs = v; |
21219 | v = NULL_TREE; |
21220 | } |
21221 | goto done; |
21222 | case OMP_ATOMIC_CAPTURE_NEW: |
21223 | if (c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
21224 | { |
21225 | c_parser_consume_token (parser); |
21226 | structured_block = true; |
21227 | } |
21228 | else if (compare |
21229 | && c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
21230 | break; |
21231 | else |
21232 | { |
21233 | v = c_parser_cast_expression (parser, NULL).value; |
21234 | non_lvalue_p = !lvalue_p (v); |
21235 | v = c_fully_fold (v, false, NULL, true); |
21236 | if (v == error_mark_node) |
21237 | goto saw_error; |
21238 | if (non_lvalue_p) |
21239 | v = non_lvalue (v); |
21240 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
21241 | goto saw_error; |
21242 | if (compare && c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
21243 | { |
21244 | eloc = c_parser_peek_token (parser)->location; |
21245 | error_at (eloc, "expected expression" ); |
21246 | goto saw_error; |
21247 | } |
21248 | } |
21249 | break; |
21250 | default: |
21251 | break; |
21252 | } |
21253 | |
21254 | /* For structured_block case we don't know yet whether |
21255 | old or new x should be captured. */ |
21256 | restart: |
21257 | if (compare && c_parser_next_token_is_keyword (parser, keyword: RID_IF)) |
21258 | { |
21259 | c_parser_consume_token (parser); |
21260 | |
21261 | matching_parens parens; |
21262 | if (!parens.require_open (parser)) |
21263 | goto saw_error; |
21264 | eloc = c_parser_peek_token (parser)->location; |
21265 | c_expr cmp_expr; |
21266 | if (r) |
21267 | { |
21268 | cmp_expr = c_parser_cast_expression (parser, NULL); |
21269 | cmp_expr = default_function_array_conversion (eloc, cmp_expr); |
21270 | } |
21271 | else |
21272 | cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node); |
21273 | parens.skip_until_found_close (parser); |
21274 | if (cmp_expr.value == error_mark_node) |
21275 | goto saw_error; |
21276 | if (r) |
21277 | { |
21278 | if (!c_tree_equal (cmp_expr.value, unfolded_lhs)) |
21279 | goto bad_if; |
21280 | cmp_expr.value = rhs1; |
21281 | rhs1 = NULL_TREE; |
21282 | gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR); |
21283 | } |
21284 | if (TREE_CODE (cmp_expr.value) == EQ_EXPR) |
21285 | ; |
21286 | else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW) |
21287 | { |
21288 | error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), |
21289 | "expected %<==%> comparison in %<if%> condition" ); |
21290 | goto saw_error; |
21291 | } |
21292 | else if (TREE_CODE (cmp_expr.value) != GT_EXPR |
21293 | && TREE_CODE (cmp_expr.value) != LT_EXPR) |
21294 | { |
21295 | error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc), |
21296 | "expected %<==%>, %<<%> or %<>%> comparison in %<if%> " |
21297 | "condition" ); |
21298 | goto saw_error; |
21299 | } |
21300 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
21301 | goto saw_error; |
21302 | |
21303 | extra_scope = true; |
21304 | eloc = c_parser_peek_token (parser)->location; |
21305 | expr = c_parser_cast_expression (parser, NULL); |
21306 | lhs = expr.value; |
21307 | expr = default_function_array_conversion (eloc, expr); |
21308 | unfolded_lhs = expr.value; |
21309 | lhs = c_fully_fold (lhs, false, NULL, true); |
21310 | orig_lhs = lhs; |
21311 | if (lhs == error_mark_node) |
21312 | goto saw_error; |
21313 | if (!lvalue_p (unfolded_lhs)) |
21314 | lhs = non_lvalue (lhs); |
21315 | if (!c_parser_next_token_is (parser, type: CPP_EQ)) |
21316 | { |
21317 | c_parser_error (parser, gmsgid: "expected %<=%>" ); |
21318 | goto saw_error; |
21319 | } |
21320 | c_parser_consume_token (parser); |
21321 | eloc = c_parser_peek_token (parser)->location; |
21322 | expr = c_parser_expr_no_commas (parser, NULL); |
21323 | rhs1 = expr.value; |
21324 | |
21325 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
21326 | goto saw_error; |
21327 | |
21328 | if (!c_parser_require (parser, type: CPP_CLOSE_BRACE, msgid: "expected %<}%>" )) |
21329 | goto saw_error; |
21330 | |
21331 | extra_scope = false; |
21332 | no_semicolon = true; |
21333 | |
21334 | if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs)) |
21335 | { |
21336 | if (TREE_CODE (cmp_expr.value) == EQ_EXPR) |
21337 | { |
21338 | opcode = COND_EXPR; |
21339 | rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), |
21340 | false, NULL, true); |
21341 | rhs1 = c_fully_fold (rhs1, false, NULL, true); |
21342 | } |
21343 | else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1)) |
21344 | { |
21345 | opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR |
21346 | ? MIN_EXPR : MAX_EXPR); |
21347 | rhs = c_fully_fold (rhs1, false, NULL, true); |
21348 | rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0), |
21349 | false, NULL, true); |
21350 | } |
21351 | else |
21352 | goto bad_if; |
21353 | } |
21354 | else if (TREE_CODE (cmp_expr.value) == EQ_EXPR) |
21355 | goto bad_if; |
21356 | else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs) |
21357 | && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1)) |
21358 | { |
21359 | opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR |
21360 | ? MAX_EXPR : MIN_EXPR); |
21361 | rhs = c_fully_fold (rhs1, false, NULL, true); |
21362 | rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1), |
21363 | false, NULL, true); |
21364 | } |
21365 | else |
21366 | { |
21367 | bad_if: |
21368 | c_parser_error (parser, |
21369 | gmsgid: "invalid form of %<#pragma omp atomic compare%>" ); |
21370 | goto saw_error; |
21371 | } |
21372 | |
21373 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ELSE)) |
21374 | { |
21375 | if (code != OMP_ATOMIC_CAPTURE_NEW |
21376 | || (structured_block && r == NULL_TREE) |
21377 | || TREE_CODE (cmp_expr.value) != EQ_EXPR) |
21378 | { |
21379 | eloc = c_parser_peek_token (parser)->location; |
21380 | error_at (eloc, "unexpected %<else%>" ); |
21381 | goto saw_error; |
21382 | } |
21383 | |
21384 | c_parser_consume_token (parser); |
21385 | |
21386 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
21387 | goto saw_error; |
21388 | |
21389 | extra_scope = true; |
21390 | v = c_parser_cast_expression (parser, NULL).value; |
21391 | non_lvalue_p = !lvalue_p (v); |
21392 | v = c_fully_fold (v, false, NULL, true); |
21393 | if (v == error_mark_node) |
21394 | goto saw_error; |
21395 | if (non_lvalue_p) |
21396 | v = non_lvalue (v); |
21397 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
21398 | goto saw_error; |
21399 | |
21400 | expr = c_parser_expr_no_commas (parser, NULL); |
21401 | |
21402 | if (!c_tree_equal (expr.value, unfolded_lhs)) |
21403 | goto bad_if; |
21404 | |
21405 | if (!c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
21406 | goto saw_error; |
21407 | |
21408 | if (!c_parser_require (parser, type: CPP_CLOSE_BRACE, msgid: "expected %<}%>" )) |
21409 | goto saw_error; |
21410 | |
21411 | extra_scope = false; |
21412 | code = OMP_ATOMIC_CAPTURE_OLD; |
21413 | if (r == NULL_TREE) |
21414 | /* Signal to c_finish_omp_atomic that in |
21415 | if (x == e) { x = d; } else { v = x; } |
21416 | case the store to v should be conditional. */ |
21417 | r = void_list_node; |
21418 | } |
21419 | else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) |
21420 | { |
21421 | c_parser_require_keyword (parser, keyword: RID_ELSE, msgid: "expected %<else%>" ); |
21422 | goto saw_error; |
21423 | } |
21424 | else if (code == OMP_ATOMIC_CAPTURE_NEW |
21425 | && r != NULL_TREE |
21426 | && v == NULL_TREE) |
21427 | code = OMP_ATOMIC; |
21428 | goto stmt_done; |
21429 | } |
21430 | eloc = c_parser_peek_token (parser)->location; |
21431 | expr = c_parser_cast_expression (parser, NULL); |
21432 | lhs = expr.value; |
21433 | expr = default_function_array_conversion (eloc, expr); |
21434 | unfolded_lhs = expr.value; |
21435 | lhs = c_fully_fold (lhs, false, NULL, true); |
21436 | orig_lhs = lhs; |
21437 | switch (TREE_CODE (lhs)) |
21438 | { |
21439 | invalid_compare: |
21440 | error_at (eloc, "invalid form of %<pragma omp atomic compare%>" ); |
21441 | /* FALLTHRU */ |
21442 | case ERROR_MARK: |
21443 | saw_error: |
21444 | c_parser_skip_to_end_of_block_or_statement (parser); |
21445 | if (extra_scope && c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
21446 | c_parser_consume_token (parser); |
21447 | if (structured_block) |
21448 | { |
21449 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
21450 | c_parser_consume_token (parser); |
21451 | else if (code == OMP_ATOMIC_CAPTURE_NEW) |
21452 | { |
21453 | c_parser_skip_to_end_of_block_or_statement (parser); |
21454 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
21455 | c_parser_consume_token (parser); |
21456 | } |
21457 | } |
21458 | return; |
21459 | |
21460 | case POSTINCREMENT_EXPR: |
21461 | if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) |
21462 | code = OMP_ATOMIC_CAPTURE_OLD; |
21463 | /* FALLTHROUGH */ |
21464 | case PREINCREMENT_EXPR: |
21465 | lhs = TREE_OPERAND (lhs, 0); |
21466 | unfolded_lhs = NULL_TREE; |
21467 | opcode = PLUS_EXPR; |
21468 | rhs = integer_one_node; |
21469 | if (compare) |
21470 | goto invalid_compare; |
21471 | break; |
21472 | |
21473 | case POSTDECREMENT_EXPR: |
21474 | if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block) |
21475 | code = OMP_ATOMIC_CAPTURE_OLD; |
21476 | /* FALLTHROUGH */ |
21477 | case PREDECREMENT_EXPR: |
21478 | lhs = TREE_OPERAND (lhs, 0); |
21479 | unfolded_lhs = NULL_TREE; |
21480 | opcode = MINUS_EXPR; |
21481 | rhs = integer_one_node; |
21482 | if (compare) |
21483 | goto invalid_compare; |
21484 | break; |
21485 | |
21486 | case COMPOUND_EXPR: |
21487 | if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR |
21488 | && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR |
21489 | && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR |
21490 | && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) |
21491 | && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND |
21492 | (TREE_OPERAND (lhs, 1), 0), 0)))) |
21493 | /* Undo effects of boolean_increment for post {in,de}crement. */ |
21494 | lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); |
21495 | /* FALLTHRU */ |
21496 | case MODIFY_EXPR: |
21497 | if (TREE_CODE (lhs) == MODIFY_EXPR |
21498 | && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0)))) |
21499 | { |
21500 | /* Undo effects of boolean_increment. */ |
21501 | if (integer_onep (TREE_OPERAND (lhs, 1))) |
21502 | { |
21503 | /* This is pre or post increment. */ |
21504 | rhs = TREE_OPERAND (lhs, 1); |
21505 | lhs = TREE_OPERAND (lhs, 0); |
21506 | unfolded_lhs = NULL_TREE; |
21507 | opcode = NOP_EXPR; |
21508 | if (code == OMP_ATOMIC_CAPTURE_NEW |
21509 | && !structured_block |
21510 | && TREE_CODE (orig_lhs) == COMPOUND_EXPR) |
21511 | code = OMP_ATOMIC_CAPTURE_OLD; |
21512 | if (compare) |
21513 | goto invalid_compare; |
21514 | break; |
21515 | } |
21516 | if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR |
21517 | && TREE_OPERAND (lhs, 0) |
21518 | == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) |
21519 | { |
21520 | /* This is pre or post decrement. */ |
21521 | rhs = TREE_OPERAND (lhs, 1); |
21522 | lhs = TREE_OPERAND (lhs, 0); |
21523 | unfolded_lhs = NULL_TREE; |
21524 | opcode = NOP_EXPR; |
21525 | if (code == OMP_ATOMIC_CAPTURE_NEW |
21526 | && !structured_block |
21527 | && TREE_CODE (orig_lhs) == COMPOUND_EXPR) |
21528 | code = OMP_ATOMIC_CAPTURE_OLD; |
21529 | if (compare) |
21530 | goto invalid_compare; |
21531 | break; |
21532 | } |
21533 | } |
21534 | /* FALLTHRU */ |
21535 | default: |
21536 | if (!lvalue_p (unfolded_lhs)) |
21537 | lhs = non_lvalue (lhs); |
21538 | if (compare && !c_parser_next_token_is (parser, type: CPP_EQ)) |
21539 | { |
21540 | c_parser_error (parser, gmsgid: "expected %<=%>" ); |
21541 | goto saw_error; |
21542 | } |
21543 | switch (c_parser_peek_token (parser)->type) |
21544 | { |
21545 | case CPP_MULT_EQ: |
21546 | opcode = MULT_EXPR; |
21547 | break; |
21548 | case CPP_DIV_EQ: |
21549 | opcode = TRUNC_DIV_EXPR; |
21550 | break; |
21551 | case CPP_PLUS_EQ: |
21552 | opcode = PLUS_EXPR; |
21553 | break; |
21554 | case CPP_MINUS_EQ: |
21555 | opcode = MINUS_EXPR; |
21556 | break; |
21557 | case CPP_LSHIFT_EQ: |
21558 | opcode = LSHIFT_EXPR; |
21559 | break; |
21560 | case CPP_RSHIFT_EQ: |
21561 | opcode = RSHIFT_EXPR; |
21562 | break; |
21563 | case CPP_AND_EQ: |
21564 | opcode = BIT_AND_EXPR; |
21565 | break; |
21566 | case CPP_OR_EQ: |
21567 | opcode = BIT_IOR_EXPR; |
21568 | break; |
21569 | case CPP_XOR_EQ: |
21570 | opcode = BIT_XOR_EXPR; |
21571 | break; |
21572 | case CPP_EQ: |
21573 | c_parser_consume_token (parser); |
21574 | eloc = c_parser_peek_token (parser)->location; |
21575 | expr = c_parser_expr_no_commas (parser, NULL, omp_atomic_lhs: unfolded_lhs); |
21576 | rhs1 = expr.value; |
21577 | switch (TREE_CODE (rhs1)) |
21578 | { |
21579 | case MULT_EXPR: |
21580 | case TRUNC_DIV_EXPR: |
21581 | case RDIV_EXPR: |
21582 | case PLUS_EXPR: |
21583 | case MINUS_EXPR: |
21584 | case LSHIFT_EXPR: |
21585 | case RSHIFT_EXPR: |
21586 | case BIT_AND_EXPR: |
21587 | case BIT_IOR_EXPR: |
21588 | case BIT_XOR_EXPR: |
21589 | if (compare) |
21590 | break; |
21591 | if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) |
21592 | { |
21593 | opcode = TREE_CODE (rhs1); |
21594 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21595 | true); |
21596 | rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, |
21597 | true); |
21598 | goto stmt_done; |
21599 | } |
21600 | if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) |
21601 | { |
21602 | opcode = TREE_CODE (rhs1); |
21603 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, |
21604 | true); |
21605 | rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21606 | true); |
21607 | swapped = !commutative_tree_code (opcode); |
21608 | goto stmt_done; |
21609 | } |
21610 | break; |
21611 | case COND_EXPR: |
21612 | if (!compare) |
21613 | break; |
21614 | if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR |
21615 | && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR |
21616 | && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR) |
21617 | break; |
21618 | if (!TREE_OPERAND (rhs1, 1)) |
21619 | break; |
21620 | if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs)) |
21621 | break; |
21622 | if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), |
21623 | unfolded_lhs)) |
21624 | { |
21625 | if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) |
21626 | { |
21627 | opcode = COND_EXPR; |
21628 | rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, |
21629 | 0), 1), |
21630 | false, NULL, true); |
21631 | rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, |
21632 | NULL, true); |
21633 | goto stmt_done; |
21634 | } |
21635 | if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), |
21636 | TREE_OPERAND (rhs1, 1))) |
21637 | { |
21638 | opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR |
21639 | ? MIN_EXPR : MAX_EXPR); |
21640 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21641 | true); |
21642 | rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, |
21643 | 0), 0), |
21644 | false, NULL, true); |
21645 | goto stmt_done; |
21646 | } |
21647 | } |
21648 | else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR) |
21649 | break; |
21650 | else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), |
21651 | unfolded_lhs)) |
21652 | { |
21653 | if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0), |
21654 | TREE_OPERAND (rhs1, 1))) |
21655 | { |
21656 | opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR |
21657 | ? MAX_EXPR : MIN_EXPR); |
21658 | rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, |
21659 | true); |
21660 | rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1, |
21661 | 0), 1), |
21662 | false, NULL, true); |
21663 | goto stmt_done; |
21664 | } |
21665 | } |
21666 | break; |
21667 | case EQ_EXPR: |
21668 | if (!compare |
21669 | || code != OMP_ATOMIC_CAPTURE_NEW |
21670 | || !structured_block |
21671 | || v |
21672 | || r) |
21673 | break; |
21674 | if (c_parser_next_token_is (parser, type: CPP_SEMICOLON) |
21675 | && c_parser_peek_2nd_token (parser)->keyword == RID_IF) |
21676 | { |
21677 | r = lhs; |
21678 | lhs = NULL_TREE; |
21679 | c_parser_consume_token (parser); |
21680 | goto restart; |
21681 | } |
21682 | break; |
21683 | case ERROR_MARK: |
21684 | goto saw_error; |
21685 | default: |
21686 | break; |
21687 | } |
21688 | if (c_parser_peek_token (parser)->type == CPP_SEMICOLON) |
21689 | { |
21690 | if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW) |
21691 | { |
21692 | code = OMP_ATOMIC_CAPTURE_OLD; |
21693 | v = lhs; |
21694 | lhs = NULL_TREE; |
21695 | expr = default_function_array_read_conversion (eloc, expr); |
21696 | unfolded_lhs1 = expr.value; |
21697 | lhs1 = c_fully_fold (unfolded_lhs1, false, NULL, true); |
21698 | rhs1 = NULL_TREE; |
21699 | c_parser_consume_token (parser); |
21700 | goto restart; |
21701 | } |
21702 | if (structured_block && !compare) |
21703 | { |
21704 | opcode = NOP_EXPR; |
21705 | expr = default_function_array_read_conversion (eloc, expr); |
21706 | rhs = c_fully_fold (expr.value, false, NULL, true); |
21707 | rhs1 = NULL_TREE; |
21708 | goto stmt_done; |
21709 | } |
21710 | } |
21711 | c_parser_error (parser, gmsgid: "invalid form of %<#pragma omp atomic%>" ); |
21712 | goto saw_error; |
21713 | default: |
21714 | c_parser_error (parser, |
21715 | gmsgid: "invalid operator for %<#pragma omp atomic%>" ); |
21716 | goto saw_error; |
21717 | } |
21718 | |
21719 | /* Arrange to pass the location of the assignment operator to |
21720 | c_finish_omp_atomic. */ |
21721 | loc = c_parser_peek_token (parser)->location; |
21722 | c_parser_consume_token (parser); |
21723 | eloc = c_parser_peek_token (parser)->location; |
21724 | expr = c_parser_expression (parser); |
21725 | expr = default_function_array_read_conversion (eloc, expr); |
21726 | rhs = expr.value; |
21727 | rhs = c_fully_fold (rhs, false, NULL, true); |
21728 | break; |
21729 | } |
21730 | stmt_done: |
21731 | if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE) |
21732 | { |
21733 | if (!no_semicolon |
21734 | && !c_parser_require (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" )) |
21735 | goto saw_error; |
21736 | no_semicolon = false; |
21737 | v = c_parser_cast_expression (parser, NULL).value; |
21738 | non_lvalue_p = !lvalue_p (v); |
21739 | v = c_fully_fold (v, false, NULL, true); |
21740 | if (v == error_mark_node) |
21741 | goto saw_error; |
21742 | if (non_lvalue_p) |
21743 | v = non_lvalue (v); |
21744 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
21745 | goto saw_error; |
21746 | eloc = c_parser_peek_token (parser)->location; |
21747 | expr = c_parser_cast_expression (parser, NULL); |
21748 | lhs1 = expr.value; |
21749 | expr = default_function_array_read_conversion (eloc, expr); |
21750 | unfolded_lhs1 = expr.value; |
21751 | lhs1 = c_fully_fold (lhs1, false, NULL, true); |
21752 | if (lhs1 == error_mark_node) |
21753 | goto saw_error; |
21754 | if (!lvalue_p (unfolded_lhs1)) |
21755 | lhs1 = non_lvalue (lhs1); |
21756 | } |
21757 | if (structured_block) |
21758 | { |
21759 | if (!no_semicolon) |
21760 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
21761 | c_parser_require (parser, type: CPP_CLOSE_BRACE, msgid: "expected %<}%>" ); |
21762 | } |
21763 | done: |
21764 | if (weak && opcode != COND_EXPR) |
21765 | { |
21766 | error_at (loc, "%<weak%> clause requires atomic equality comparison" ); |
21767 | weak = false; |
21768 | } |
21769 | if (unfolded_lhs && unfolded_lhs1 |
21770 | && !c_tree_equal (unfolded_lhs, unfolded_lhs1)) |
21771 | { |
21772 | error ("%<#pragma omp atomic capture%> uses two different " |
21773 | "expressions for memory" ); |
21774 | stmt = error_mark_node; |
21775 | } |
21776 | else |
21777 | stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r, |
21778 | swapped, memory_order, weak); |
21779 | if (stmt != error_mark_node) |
21780 | add_stmt (stmt); |
21781 | |
21782 | if (!structured_block && !no_semicolon) |
21783 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
21784 | } |
21785 | |
21786 | |
21787 | /* OpenMP 2.5: |
21788 | # pragma omp barrier new-line |
21789 | */ |
21790 | |
21791 | static void |
21792 | c_parser_omp_barrier (c_parser *parser) |
21793 | { |
21794 | location_t loc = c_parser_peek_token (parser)->location; |
21795 | c_parser_consume_pragma (parser); |
21796 | c_parser_skip_to_pragma_eol (parser); |
21797 | |
21798 | c_finish_omp_barrier (loc); |
21799 | } |
21800 | |
21801 | /* OpenMP 2.5: |
21802 | # pragma omp critical [(name)] new-line |
21803 | structured-block |
21804 | |
21805 | OpenMP 4.5: |
21806 | # pragma omp critical [(name) [hint(expression)]] new-line |
21807 | |
21808 | LOC is the location of the #pragma itself. */ |
21809 | |
21810 | #define OMP_CRITICAL_CLAUSE_MASK \ |
21811 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) ) |
21812 | |
21813 | static tree |
21814 | c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p) |
21815 | { |
21816 | tree stmt, name = NULL_TREE, clauses = NULL_TREE; |
21817 | |
21818 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
21819 | { |
21820 | c_parser_consume_token (parser); |
21821 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21822 | { |
21823 | name = c_parser_peek_token (parser)->value; |
21824 | c_parser_consume_token (parser); |
21825 | c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" ); |
21826 | } |
21827 | else |
21828 | c_parser_error (parser, gmsgid: "expected identifier" ); |
21829 | |
21830 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
21831 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
21832 | c_parser_consume_token (parser); |
21833 | } |
21834 | clauses = c_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK, |
21835 | where: "#pragma omp critical" ); |
21836 | stmt = c_parser_omp_structured_block (parser, if_p); |
21837 | return c_finish_omp_critical (loc, stmt, name, clauses); |
21838 | } |
21839 | |
21840 | /* OpenMP 5.0: |
21841 | # pragma omp depobj ( depobj ) depobj-clause new-line |
21842 | |
21843 | depobj-clause: |
21844 | depend (dependence-type : locator) |
21845 | destroy |
21846 | update (dependence-type) |
21847 | |
21848 | OpenMP 5.2 additionally: |
21849 | destroy ( depobj ) |
21850 | |
21851 | dependence-type: |
21852 | in |
21853 | out |
21854 | inout |
21855 | mutexinout */ |
21856 | |
21857 | static void |
21858 | c_parser_omp_depobj (c_parser *parser) |
21859 | { |
21860 | location_t loc = c_parser_peek_token (parser)->location; |
21861 | c_parser_consume_pragma (parser); |
21862 | matching_parens parens; |
21863 | if (!parens.require_open (parser)) |
21864 | { |
21865 | c_parser_skip_to_pragma_eol (parser); |
21866 | return; |
21867 | } |
21868 | |
21869 | tree depobj = c_parser_expr_no_commas (parser, NULL).value; |
21870 | if (depobj != error_mark_node) |
21871 | { |
21872 | if (!lvalue_p (depobj)) |
21873 | { |
21874 | error_at (EXPR_LOC_OR_LOC (depobj, loc), |
21875 | "%<depobj%> expression is not lvalue expression" ); |
21876 | depobj = error_mark_node; |
21877 | } |
21878 | else |
21879 | { |
21880 | tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR, |
21881 | depobj, false); |
21882 | if (addr == error_mark_node) |
21883 | depobj = error_mark_node; |
21884 | else |
21885 | depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc), |
21886 | addr, RO_UNARY_STAR); |
21887 | } |
21888 | } |
21889 | |
21890 | parens.skip_until_found_close (parser); |
21891 | tree clause = NULL_TREE; |
21892 | enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID; |
21893 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
21894 | c_parser_consume_token (parser); |
21895 | location_t c_loc = c_parser_peek_token (parser)->location; |
21896 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21897 | { |
21898 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21899 | |
21900 | c_parser_consume_token (parser); |
21901 | if (!strcmp (s1: "depend" , s2: p)) |
21902 | { |
21903 | clause = c_parser_omp_clause_depend (parser, NULL_TREE); |
21904 | clause = c_finish_omp_clauses (clause, C_ORT_OMP); |
21905 | if (!clause) |
21906 | clause = error_mark_node; |
21907 | } |
21908 | else if (!strcmp (s1: "destroy" , s2: p)) |
21909 | { |
21910 | matching_parens c_parens; |
21911 | kind = OMP_CLAUSE_DEPEND_LAST; |
21912 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN) |
21913 | && c_parens.require_open (parser)) |
21914 | { |
21915 | tree destobj = c_parser_expr_no_commas (parser, NULL).value; |
21916 | if (!lvalue_p (destobj)) |
21917 | error_at (EXPR_LOC_OR_LOC (destobj, c_loc), |
21918 | "%<destroy%> expression is not lvalue expression" ); |
21919 | else if (depobj != error_mark_node |
21920 | && !operand_equal_p (destobj, depobj, |
21921 | flags: OEP_MATCH_SIDE_EFFECTS |
21922 | | OEP_LEXICOGRAPHIC)) |
21923 | warning_at (EXPR_LOC_OR_LOC (destobj, c_loc), OPT_Wopenmp, |
21924 | "the %<destroy%> expression %qE should be the same " |
21925 | "as the %<depobj%> argument %qE" , destobj, depobj); |
21926 | c_parens.skip_until_found_close (parser); |
21927 | } |
21928 | } |
21929 | else if (!strcmp (s1: "update" , s2: p)) |
21930 | { |
21931 | matching_parens c_parens; |
21932 | if (c_parens.require_open (parser)) |
21933 | { |
21934 | location_t c2_loc = c_parser_peek_token (parser)->location; |
21935 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21936 | { |
21937 | const char *p2 |
21938 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21939 | |
21940 | c_parser_consume_token (parser); |
21941 | if (!strcmp (s1: "in" , s2: p2)) |
21942 | kind = OMP_CLAUSE_DEPEND_IN; |
21943 | else if (!strcmp (s1: "out" , s2: p2)) |
21944 | kind = OMP_CLAUSE_DEPEND_OUT; |
21945 | else if (!strcmp (s1: "inout" , s2: p2)) |
21946 | kind = OMP_CLAUSE_DEPEND_INOUT; |
21947 | else if (!strcmp (s1: "mutexinoutset" , s2: p2)) |
21948 | kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; |
21949 | else if (!strcmp (s1: "inoutset" , s2: p2)) |
21950 | kind = OMP_CLAUSE_DEPEND_INOUTSET; |
21951 | } |
21952 | if (kind == OMP_CLAUSE_DEPEND_INVALID) |
21953 | { |
21954 | clause = error_mark_node; |
21955 | error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%>, " |
21956 | "%<mutexinoutset%> or %<inoutset%>" ); |
21957 | } |
21958 | c_parens.skip_until_found_close (parser); |
21959 | } |
21960 | else |
21961 | clause = error_mark_node; |
21962 | } |
21963 | } |
21964 | if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID) |
21965 | { |
21966 | clause = error_mark_node; |
21967 | error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause" ); |
21968 | } |
21969 | c_parser_skip_to_pragma_eol (parser); |
21970 | |
21971 | c_finish_omp_depobj (loc, depobj, kind, clause); |
21972 | } |
21973 | |
21974 | |
21975 | /* OpenMP 2.5: |
21976 | # pragma omp flush flush-vars[opt] new-line |
21977 | |
21978 | flush-vars: |
21979 | ( variable-list ) |
21980 | |
21981 | OpenMP 5.0: |
21982 | # pragma omp flush memory-order-clause new-line */ |
21983 | |
21984 | static void |
21985 | c_parser_omp_flush (c_parser *parser) |
21986 | { |
21987 | location_t loc = c_parser_peek_token (parser)->location; |
21988 | c_parser_consume_pragma (parser); |
21989 | enum memmodel mo = MEMMODEL_LAST; |
21990 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
21991 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
21992 | c_parser_consume_token (parser); |
21993 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
21994 | { |
21995 | const char *p |
21996 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
21997 | |
21998 | if (!strcmp (s1: p, s2: "seq_cst" )) |
21999 | mo = MEMMODEL_SEQ_CST; |
22000 | else if (!strcmp (s1: p, s2: "acq_rel" )) |
22001 | mo = MEMMODEL_ACQ_REL; |
22002 | else if (!strcmp (s1: p, s2: "release" )) |
22003 | mo = MEMMODEL_RELEASE; |
22004 | else if (!strcmp (s1: p, s2: "acquire" )) |
22005 | mo = MEMMODEL_ACQUIRE; |
22006 | else |
22007 | error_at (c_parser_peek_token (parser)->location, |
22008 | "expected %<seq_cst%>, %<acq_rel%>, %<release%> or " |
22009 | "%<acquire%>" ); |
22010 | c_parser_consume_token (parser); |
22011 | } |
22012 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
22013 | { |
22014 | if (mo != MEMMODEL_LAST) |
22015 | error_at (c_parser_peek_token (parser)->location, |
22016 | "%<flush%> list specified together with memory order " |
22017 | "clause" ); |
22018 | c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ERROR, NULL); |
22019 | } |
22020 | else if (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
22021 | c_parser_error (parser, gmsgid: "expected %<(%> or end of line" ); |
22022 | c_parser_skip_to_pragma_eol (parser); |
22023 | |
22024 | c_finish_omp_flush (loc, mo); |
22025 | } |
22026 | |
22027 | /* Return true if next tokens contain a standard attribute that contains |
22028 | omp::directive (DIRECTIVE). */ |
22029 | |
22030 | static bool |
22031 | c_parser_omp_section_scan (c_parser *parser, const char *directive, |
22032 | bool tentative) |
22033 | { |
22034 | if (!c_parser_nth_token_starts_std_attributes (parser, n: 1)) |
22035 | return false; |
22036 | unsigned int n = 3; |
22037 | if (!c_parser_check_balanced_raw_token_sequence (parser, n: &n)) |
22038 | return false; |
22039 | c_token *token = c_parser_peek_nth_token_raw (parser, n); |
22040 | if (token->type != CPP_CLOSE_SQUARE) |
22041 | return false; |
22042 | token = c_parser_peek_nth_token_raw (parser, n: n + 1); |
22043 | if (token->type != CPP_CLOSE_SQUARE) |
22044 | return false; |
22045 | if (n < 9) |
22046 | return false; |
22047 | if (c_parser_peek_nth_token_raw (parser, n: 3)->type == CPP_NAME |
22048 | && c_parser_peek_nth_token_raw (parser, n: 4)->type == CPP_OPEN_PAREN |
22049 | && c_parser_peek_nth_token_raw (parser, n: 5)->type == CPP_NAME) |
22050 | { |
22051 | tree first = c_parser_peek_nth_token_raw (parser, n: 3)->value; |
22052 | tree second = c_parser_peek_nth_token_raw (parser, n: 5)->value; |
22053 | if (strcmp (IDENTIFIER_POINTER (first), s2: "directive" ) |
22054 | && strcmp (IDENTIFIER_POINTER (first), s2: "__directive__" )) |
22055 | return false; |
22056 | if (strcmp (IDENTIFIER_POINTER (second), s2: directive)) |
22057 | return false; |
22058 | } |
22059 | if (tentative) |
22060 | return true; |
22061 | location_t first_loc = c_parser_peek_token (parser)->location; |
22062 | location_t last_loc = c_parser_peek_nth_token_raw (parser, n: n + 1)->location; |
22063 | location_t middle_loc = UNKNOWN_LOCATION; |
22064 | tree std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
22065 | bool seen = false; |
22066 | int cnt = 0; |
22067 | for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr)) |
22068 | if (is_attribute_namespace_p (attr_ns: "omp" , attr) |
22069 | && is_attribute_p (attr_name: "directive" , ident: get_attribute_name (attr))) |
22070 | { |
22071 | for (tree a = TREE_VALUE (attr); a; a = TREE_CHAIN (a)) |
22072 | { |
22073 | tree d = TREE_VALUE (a); |
22074 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
22075 | c_token *first = C_TOKEN_VEC_TOKENS (d)->address (); |
22076 | cnt++; |
22077 | if (first->type == CPP_NAME |
22078 | && strcmp (IDENTIFIER_POINTER (first->value), |
22079 | s2: directive) == 0) |
22080 | { |
22081 | seen = true; |
22082 | if (middle_loc == UNKNOWN_LOCATION) |
22083 | middle_loc = first->location; |
22084 | } |
22085 | } |
22086 | } |
22087 | if (!seen) |
22088 | return false; |
22089 | if (cnt != 1 || TREE_CHAIN (std_attrs)) |
22090 | { |
22091 | error_at (make_location (caret: first_loc, start: last_loc, finish: middle_loc), |
22092 | "%<[[omp::directive(%s)]]%> must be the only specified " |
22093 | "attribute on a statement" , directive); |
22094 | return false; |
22095 | } |
22096 | c_parser_handle_statement_omp_attributes (parser, attrs&: std_attrs, NULL); |
22097 | return true; |
22098 | } |
22099 | |
22100 | /* Parse an OpenMP structured block sequence. KIND is the corresponding |
22101 | separating directive. */ |
22102 | |
22103 | static tree |
22104 | c_parser_omp_structured_block_sequence (c_parser *parser, |
22105 | enum pragma_kind kind) |
22106 | { |
22107 | tree stmt = push_stmt_list (); |
22108 | c_parser_statement (parser, NULL); |
22109 | do |
22110 | { |
22111 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
22112 | break; |
22113 | if (c_parser_next_token_is (parser, type: CPP_EOF)) |
22114 | break; |
22115 | |
22116 | if (kind != PRAGMA_NONE |
22117 | && c_parser_peek_token (parser)->pragma_kind == kind) |
22118 | break; |
22119 | |
22120 | if (kind != PRAGMA_NONE |
22121 | && c_parser_omp_section_scan (parser, |
22122 | directive: kind == PRAGMA_OMP_SCAN |
22123 | ? "scan" : "section" , tentative: false)) |
22124 | break; |
22125 | |
22126 | c_parser_statement (parser, NULL); |
22127 | } |
22128 | while (1); |
22129 | return pop_stmt_list (stmt); |
22130 | } |
22131 | |
22132 | /* OpenMP 5.0: |
22133 | |
22134 | scan-loop-body: |
22135 | { structured-block scan-directive structured-block } */ |
22136 | |
22137 | static void |
22138 | c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) |
22139 | { |
22140 | tree substmt; |
22141 | location_t loc; |
22142 | tree clauses = NULL_TREE; |
22143 | bool found_scan = false; |
22144 | |
22145 | loc = c_parser_peek_token (parser)->location; |
22146 | if (!open_brace_parsed |
22147 | && !c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
22148 | { |
22149 | /* Avoid skipping until the end of the block. */ |
22150 | parser->error = false; |
22151 | return; |
22152 | } |
22153 | |
22154 | if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SCAN) |
22155 | substmt = c_parser_omp_structured_block_sequence (parser, kind: PRAGMA_OMP_SCAN); |
22156 | else |
22157 | { |
22158 | warning_at (c_parser_peek_token (parser)->location, OPT_Wopenmp, |
22159 | "%<#pragma omp scan%> with zero preceding executable " |
22160 | "statements" ); |
22161 | substmt = build_empty_stmt (loc); |
22162 | } |
22163 | substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); |
22164 | SET_EXPR_LOCATION (substmt, loc); |
22165 | add_stmt (substmt); |
22166 | |
22167 | loc = c_parser_peek_token (parser)->location; |
22168 | if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SCAN) |
22169 | { |
22170 | enum omp_clause_code clause = OMP_CLAUSE_ERROR; |
22171 | found_scan = true; |
22172 | |
22173 | c_parser_consume_pragma (parser); |
22174 | |
22175 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
22176 | c_parser_consume_token (parser); |
22177 | |
22178 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22179 | { |
22180 | const char *p |
22181 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22182 | if (strcmp (s1: p, s2: "inclusive" ) == 0) |
22183 | clause = OMP_CLAUSE_INCLUSIVE; |
22184 | else if (strcmp (s1: p, s2: "exclusive" ) == 0) |
22185 | clause = OMP_CLAUSE_EXCLUSIVE; |
22186 | } |
22187 | if (clause != OMP_CLAUSE_ERROR) |
22188 | { |
22189 | c_parser_consume_token (parser); |
22190 | clauses = c_parser_omp_var_list_parens (parser, kind: clause, NULL_TREE); |
22191 | } |
22192 | else |
22193 | c_parser_error (parser, gmsgid: "expected %<inclusive%> or " |
22194 | "%<exclusive%> clause" ); |
22195 | c_parser_skip_to_pragma_eol (parser); |
22196 | } |
22197 | else |
22198 | error ("expected %<#pragma omp scan%>" ); |
22199 | |
22200 | clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); |
22201 | if (!c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
22202 | substmt = c_parser_omp_structured_block_sequence (parser, kind: PRAGMA_NONE); |
22203 | else |
22204 | { |
22205 | if (found_scan) |
22206 | warning_at (loc, OPT_Wopenmp, |
22207 | "%<#pragma omp scan%> with zero succeeding executable " |
22208 | "statements" ); |
22209 | substmt = build_empty_stmt (loc); |
22210 | } |
22211 | substmt = build2 (OMP_SCAN, void_type_node, substmt, clauses); |
22212 | SET_EXPR_LOCATION (substmt, loc); |
22213 | add_stmt (substmt); |
22214 | |
22215 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, |
22216 | msgid: "expected %<}%>" ); |
22217 | } |
22218 | |
22219 | |
22220 | /* This function parses a single level of a loop nest, invoking itself |
22221 | recursively if necessary. |
22222 | |
22223 | loop-nest :: for (...) loop-body |
22224 | loop-body :: loop-nest |
22225 | | { [intervening-code] loop-body [intervening-code] } |
22226 | | final-loop-body |
22227 | intervening-code :: structured-block-sequence |
22228 | final-loop-body :: structured-block |
22229 | |
22230 | For a collapsed loop nest, only a single OMP_FOR is built, pulling out |
22231 | all the iterator information from the inner loops into the |
22232 | parser->omp_for_parse_state structure. |
22233 | |
22234 | The iterator decl, init, cond, and incr are stored in vectors. |
22235 | |
22236 | Initialization code for iterator variables is collected into |
22237 | parser->omp_for_parse_state->pre_body and ends up inserted directly |
22238 | into the OMP_FOR structure. */ |
22239 | |
22240 | static tree |
22241 | c_parser_omp_loop_nest (c_parser *parser, bool *if_p) |
22242 | { |
22243 | tree decl, cond, incr, init; |
22244 | tree body = NULL_TREE; |
22245 | matching_parens parens; |
22246 | bool moreloops; |
22247 | unsigned char save_in_statement; |
22248 | tree loop_scope; |
22249 | location_t loc; |
22250 | struct omp_for_parse_data *omp_for_parse_state |
22251 | = parser->omp_for_parse_state; |
22252 | gcc_assert (omp_for_parse_state); |
22253 | int depth = omp_for_parse_state->depth; |
22254 | |
22255 | /* We have already matched the FOR token but not consumed it yet. */ |
22256 | loc = c_parser_peek_token (parser)->location; |
22257 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); |
22258 | c_parser_consume_token (parser); |
22259 | |
22260 | /* Forbid break/continue in the loop initializer, condition, and |
22261 | increment expressions. */ |
22262 | save_in_statement = in_statement; |
22263 | in_statement = IN_OMP_BLOCK; |
22264 | |
22265 | /* We are not in intervening code now. */ |
22266 | omp_for_parse_state->in_intervening_code = false; |
22267 | |
22268 | if (!parens.require_open (parser)) |
22269 | { |
22270 | omp_for_parse_state->fail = true; |
22271 | return NULL_TREE; |
22272 | } |
22273 | |
22274 | /* An implicit scope block surrounds each level of FOR loop, for |
22275 | declarations of iteration variables at this loop depth. */ |
22276 | loop_scope = c_begin_compound_stmt (true); |
22277 | |
22278 | /* Parse the initialization declaration or expression. */ |
22279 | if (c_parser_next_tokens_start_declaration (parser)) |
22280 | { |
22281 | /* This is a declaration, which must be added to the pre_body code. */ |
22282 | tree this_pre_body = push_stmt_list (); |
22283 | c_in_omp_for = true; |
22284 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, start_attr_ok: true); |
22285 | c_in_omp_for = false; |
22286 | this_pre_body = pop_stmt_list (this_pre_body); |
22287 | append_to_statement_list_force (this_pre_body, |
22288 | &(omp_for_parse_state->pre_body)); |
22289 | decl = check_for_loop_decls (omp_for_parse_state->for_loc, flag_isoc99); |
22290 | if (decl == NULL) |
22291 | goto error_init; |
22292 | if (DECL_INITIAL (decl) == error_mark_node) |
22293 | decl = error_mark_node; |
22294 | init = decl; |
22295 | } |
22296 | else if (c_parser_next_token_is (parser, type: CPP_NAME) |
22297 | && c_parser_peek_2nd_token (parser)->type == CPP_EQ) |
22298 | { |
22299 | struct c_expr decl_exp; |
22300 | struct c_expr init_exp; |
22301 | location_t init_loc; |
22302 | |
22303 | decl_exp = c_parser_postfix_expression (parser); |
22304 | decl = decl_exp.value; |
22305 | |
22306 | c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" ); |
22307 | |
22308 | init_loc = c_parser_peek_token (parser)->location; |
22309 | init_exp = c_parser_expr_no_commas (parser, NULL); |
22310 | init_exp = default_function_array_read_conversion (init_loc, |
22311 | init_exp); |
22312 | c_in_omp_for = true; |
22313 | init = build_modify_expr (init_loc, decl, decl_exp.original_type, |
22314 | NOP_EXPR, init_loc, init_exp.value, |
22315 | init_exp.original_type); |
22316 | c_in_omp_for = false; |
22317 | init = c_process_expr_stmt (init_loc, init); |
22318 | |
22319 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
22320 | } |
22321 | else |
22322 | { |
22323 | error_init: |
22324 | c_parser_error (parser, |
22325 | gmsgid: "expected iteration declaration or initialization" ); |
22326 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, |
22327 | msgid: "expected %<)%>" ); |
22328 | omp_for_parse_state->fail = true; |
22329 | goto parse_next; |
22330 | } |
22331 | |
22332 | /* Parse the loop condition. */ |
22333 | cond = NULL_TREE; |
22334 | if (c_parser_next_token_is_not (parser, type: CPP_SEMICOLON)) |
22335 | { |
22336 | location_t cond_loc = c_parser_peek_token (parser)->location; |
22337 | c_in_omp_for = true; |
22338 | struct c_expr cond_expr |
22339 | = c_parser_binary_expression (parser, NULL, NULL_TREE); |
22340 | c_in_omp_for = false; |
22341 | |
22342 | cond = cond_expr.value; |
22343 | cond = c_objc_common_truthvalue_conversion (cond_loc, cond); |
22344 | switch (cond_expr.original_code) |
22345 | { |
22346 | case GT_EXPR: |
22347 | case GE_EXPR: |
22348 | case LT_EXPR: |
22349 | case LE_EXPR: |
22350 | break; |
22351 | case NE_EXPR: |
22352 | if (omp_for_parse_state->code != OACC_LOOP) |
22353 | break; |
22354 | /* FALLTHRU. */ |
22355 | default: |
22356 | /* Can't be cond = error_mark_node, because we want to preserve |
22357 | the location until c_finish_omp_for. */ |
22358 | cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node); |
22359 | break; |
22360 | } |
22361 | protected_set_expr_location (cond, cond_loc); |
22362 | } |
22363 | c_parser_skip_until_found (parser, type: CPP_SEMICOLON, msgid: "expected %<;%>" ); |
22364 | |
22365 | /* Parse the increment expression. */ |
22366 | incr = NULL_TREE; |
22367 | if (c_parser_next_token_is_not (parser, type: CPP_CLOSE_PAREN)) |
22368 | { |
22369 | location_t incr_loc = c_parser_peek_token (parser)->location; |
22370 | |
22371 | incr = c_process_expr_stmt (incr_loc, |
22372 | c_parser_expression (parser).value); |
22373 | } |
22374 | parens.skip_until_found_close (parser); |
22375 | |
22376 | if (decl == NULL || decl == error_mark_node || init == error_mark_node) |
22377 | omp_for_parse_state->fail = true; |
22378 | else |
22379 | { |
22380 | TREE_VEC_ELT (omp_for_parse_state->declv, depth) = decl; |
22381 | TREE_VEC_ELT (omp_for_parse_state->initv, depth) = init; |
22382 | TREE_VEC_ELT (omp_for_parse_state->condv, depth) = cond; |
22383 | TREE_VEC_ELT (omp_for_parse_state->incrv, depth) = incr; |
22384 | } |
22385 | |
22386 | parse_next: |
22387 | moreloops = depth < omp_for_parse_state->count - 1; |
22388 | omp_for_parse_state->want_nested_loop = moreloops; |
22389 | if (moreloops && c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
22390 | { |
22391 | omp_for_parse_state->depth++; |
22392 | body = c_parser_omp_loop_nest (parser, if_p); |
22393 | omp_for_parse_state->depth--; |
22394 | } |
22395 | else if (moreloops && c_parser_next_token_is (parser, type: CPP_OPEN_BRACE)) |
22396 | { |
22397 | /* This is the open brace in the loop-body grammar production. Rather |
22398 | than trying to special-case braces, just parse it as a compound |
22399 | statement and handle the nested loop-body case there. Note that |
22400 | when we see a further open brace inside the compound statement |
22401 | loop-body, we don't know whether it is the start of intervening |
22402 | code that is a compound statement, or a level of braces |
22403 | surrounding a nested loop-body. Use the WANT_NESTED_LOOP state |
22404 | bit to ensure we have only one nested loop at each level. */ |
22405 | omp_for_parse_state->in_intervening_code = true; |
22406 | body = c_parser_compound_statement (parser, NULL); |
22407 | omp_for_parse_state->in_intervening_code = false; |
22408 | if (omp_for_parse_state->want_nested_loop) |
22409 | { |
22410 | /* We have already parsed the whole loop body and not found a |
22411 | nested loop. */ |
22412 | error_at (omp_for_parse_state->for_loc, |
22413 | "not enough nested loops" ); |
22414 | omp_for_parse_state->fail = true; |
22415 | } |
22416 | if_p = NULL; |
22417 | } |
22418 | else |
22419 | { |
22420 | /* This is the final-loop-body case in the grammar: we have |
22421 | something that is not a FOR and not an open brace. */ |
22422 | if (moreloops) |
22423 | { |
22424 | /* If we were expecting a nested loop, give an error and mark |
22425 | that parsing has failed, and try to recover by parsing the |
22426 | body as regular code without further collapsing. */ |
22427 | error_at (omp_for_parse_state->for_loc, |
22428 | "not enough nested loops" ); |
22429 | omp_for_parse_state->fail = true; |
22430 | } |
22431 | in_statement = IN_OMP_FOR; |
22432 | parser->omp_for_parse_state = NULL; |
22433 | body = push_stmt_list (); |
22434 | if (omp_for_parse_state->inscan) |
22435 | c_parser_omp_scan_loop_body (parser, open_brace_parsed: false); |
22436 | else |
22437 | add_stmt (c_parser_c99_block_statement (parser, if_p)); |
22438 | body = pop_stmt_list (body); |
22439 | parser->omp_for_parse_state = omp_for_parse_state; |
22440 | } |
22441 | in_statement = save_in_statement; |
22442 | omp_for_parse_state->want_nested_loop = false; |
22443 | omp_for_parse_state->in_intervening_code = true; |
22444 | |
22445 | /* Pop and return the implicit scope surrounding this level of loop. |
22446 | If the iteration variable at this depth was bound in the for loop, |
22447 | pull out and save the binding. Later in c_parser_omp_for_loop, |
22448 | these bindings will be moved to the scope surrounding the entire |
22449 | OMP_FOR. That keeps the gimplifier happy later on, and meanwhile |
22450 | we have already resolved all references to the iteration variable |
22451 | in its true scope. */ |
22452 | add_stmt (body); |
22453 | body = c_end_compound_stmt (loc, loop_scope, true); |
22454 | if (decl && TREE_CODE (body) == BIND_EXPR) |
22455 | { |
22456 | tree t = BIND_EXPR_VARS (body); |
22457 | tree prev = NULL_TREE, next = NULL_TREE; |
22458 | while (t) |
22459 | { |
22460 | next = DECL_CHAIN (t); |
22461 | if (t == decl) |
22462 | { |
22463 | if (prev) |
22464 | DECL_CHAIN (prev) = next; |
22465 | else |
22466 | { |
22467 | BIND_EXPR_VARS (body) = next; |
22468 | BLOCK_VARS (BIND_EXPR_BLOCK (body)) = next; |
22469 | } |
22470 | DECL_CHAIN (t) = omp_for_parse_state->bindings; |
22471 | omp_for_parse_state->bindings = t; |
22472 | break; |
22473 | } |
22474 | else |
22475 | { |
22476 | prev = t; |
22477 | t = next; |
22478 | } |
22479 | } |
22480 | if (BIND_EXPR_VARS (body) == NULL_TREE) |
22481 | body = BIND_EXPR_BODY (body); |
22482 | } |
22483 | |
22484 | return body; |
22485 | } |
22486 | |
22487 | /* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. |
22488 | The real trick here is to determine the loop control variable early |
22489 | so that we can push a new decl if necessary to make it private. |
22490 | LOC is the location of the "acc" or "omp" in "#pragma acc" or "#pragma omp", |
22491 | respectively. */ |
22492 | |
22493 | static tree |
22494 | c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, |
22495 | tree clauses, tree *cclauses, bool *if_p) |
22496 | { |
22497 | tree body, stmt, cl; |
22498 | tree ret = NULL_TREE; |
22499 | tree ordered_cl = NULL_TREE; |
22500 | int i, collapse = 1, ordered = 0, count; |
22501 | bool tiling = false; |
22502 | bool inscan = false; |
22503 | struct omp_for_parse_data data; |
22504 | struct omp_for_parse_data *save_data = parser->omp_for_parse_state; |
22505 | |
22506 | for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) |
22507 | if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE) |
22508 | collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); |
22509 | else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_TILE) |
22510 | { |
22511 | tiling = true; |
22512 | collapse = list_length (OMP_CLAUSE_TILE_LIST (cl)); |
22513 | } |
22514 | else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED |
22515 | && OMP_CLAUSE_ORDERED_EXPR (cl)) |
22516 | { |
22517 | ordered_cl = cl; |
22518 | ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl)); |
22519 | } |
22520 | else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_REDUCTION |
22521 | && OMP_CLAUSE_REDUCTION_INSCAN (cl) |
22522 | && (code == OMP_SIMD || code == OMP_FOR)) |
22523 | inscan = true; |
22524 | |
22525 | if (ordered && ordered < collapse) |
22526 | { |
22527 | error_at (OMP_CLAUSE_LOCATION (ordered_cl), |
22528 | "%<ordered%> clause parameter is less than %<collapse%>" ); |
22529 | OMP_CLAUSE_ORDERED_EXPR (ordered_cl) |
22530 | = build_int_cst (NULL_TREE, collapse); |
22531 | ordered = collapse; |
22532 | } |
22533 | |
22534 | gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); |
22535 | count = ordered ? ordered : collapse; |
22536 | |
22537 | if (!c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
22538 | { |
22539 | c_parser_error (parser, gmsgid: "for statement expected" ); |
22540 | return NULL; |
22541 | } |
22542 | |
22543 | /* Initialize parse state for recursive descent. */ |
22544 | data.declv = make_tree_vec (count); |
22545 | data.initv = make_tree_vec (count); |
22546 | data.condv = make_tree_vec (count); |
22547 | data.incrv = make_tree_vec (count); |
22548 | data.pre_body = NULL_TREE;; |
22549 | data.bindings = NULL_TREE; |
22550 | data.for_loc = c_parser_peek_token (parser)->location; |
22551 | data.count = count; |
22552 | data.depth = 0; |
22553 | data.want_nested_loop = true; |
22554 | data.ordered = ordered > 0; |
22555 | data.in_intervening_code = false; |
22556 | data.perfect_nesting_fail = false; |
22557 | data.fail = false; |
22558 | data.inscan = inscan; |
22559 | data.saw_intervening_code = false; |
22560 | data.code = code; |
22561 | parser->omp_for_parse_state = &data; |
22562 | |
22563 | body = c_parser_omp_loop_nest (parser, if_p); |
22564 | |
22565 | /* Add saved bindings for iteration variables that were declared in |
22566 | the nested for loop to the scope surrounding the entire loop. */ |
22567 | for (tree t = data.bindings; t; ) |
22568 | { |
22569 | tree n = TREE_CHAIN (t); |
22570 | TREE_CHAIN (t) = NULL_TREE; |
22571 | pushdecl (t); |
22572 | t = n; |
22573 | } |
22574 | |
22575 | /* Only bother calling c_finish_omp_for if we haven't already generated |
22576 | an error from the initialization parsing. */ |
22577 | if (!data.fail) |
22578 | { |
22579 | c_in_omp_for = true; |
22580 | stmt = c_finish_omp_for (loc, code, data.declv, NULL, data.initv, |
22581 | data.condv, data.incrv, |
22582 | body, data.pre_body, true); |
22583 | c_in_omp_for = false; |
22584 | |
22585 | /* Check for iterators appearing in lb, b or incr expressions. */ |
22586 | if (stmt && !c_omp_check_loop_iv (stmt, data.declv, NULL)) |
22587 | stmt = NULL_TREE; |
22588 | |
22589 | /* Check for errors involving lb/ub/incr expressions referencing |
22590 | variables declared in intervening code. */ |
22591 | if (data.saw_intervening_code |
22592 | && !c_omp_check_loop_binding_exprs (stmt, NULL)) |
22593 | stmt = NULL_TREE; |
22594 | |
22595 | if (stmt) |
22596 | { |
22597 | add_stmt (stmt); |
22598 | |
22599 | for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++) |
22600 | { |
22601 | tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i); |
22602 | gcc_assert (TREE_CODE (init) == MODIFY_EXPR); |
22603 | tree decl = TREE_OPERAND (init, 0); |
22604 | tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i); |
22605 | gcc_assert (COMPARISON_CLASS_P (cond)); |
22606 | gcc_assert (TREE_OPERAND (cond, 0) == decl); |
22607 | |
22608 | tree op0 = TREE_OPERAND (init, 1); |
22609 | if (!OMP_FOR_NON_RECTANGULAR (stmt) |
22610 | || TREE_CODE (op0) != TREE_VEC) |
22611 | TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL); |
22612 | else |
22613 | { |
22614 | TREE_VEC_ELT (op0, 1) |
22615 | = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL); |
22616 | TREE_VEC_ELT (op0, 2) |
22617 | = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL); |
22618 | } |
22619 | |
22620 | tree op1 = TREE_OPERAND (cond, 1); |
22621 | if (!OMP_FOR_NON_RECTANGULAR (stmt) |
22622 | || TREE_CODE (op1) != TREE_VEC) |
22623 | TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL); |
22624 | else |
22625 | { |
22626 | TREE_VEC_ELT (op1, 1) |
22627 | = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL); |
22628 | TREE_VEC_ELT (op1, 2) |
22629 | = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL); |
22630 | } |
22631 | } |
22632 | |
22633 | if (cclauses != NULL |
22634 | && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL) |
22635 | { |
22636 | tree *c; |
22637 | for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) |
22638 | if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE |
22639 | && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE) |
22640 | c = &OMP_CLAUSE_CHAIN (*c); |
22641 | else |
22642 | { |
22643 | for (i = 0; i < count; i++) |
22644 | if (TREE_VEC_ELT (data.declv, i) == OMP_CLAUSE_DECL (*c)) |
22645 | break; |
22646 | if (i == count) |
22647 | c = &OMP_CLAUSE_CHAIN (*c); |
22648 | else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE) |
22649 | { |
22650 | error_at (loc, |
22651 | "iteration variable %qD should not be firstprivate" , |
22652 | OMP_CLAUSE_DECL (*c)); |
22653 | *c = OMP_CLAUSE_CHAIN (*c); |
22654 | } |
22655 | else |
22656 | { |
22657 | /* Move lastprivate (decl) clause to |
22658 | OMP_FOR_CLAUSES. */ |
22659 | tree l = *c; |
22660 | *c = OMP_CLAUSE_CHAIN (*c); |
22661 | if (code == OMP_SIMD) |
22662 | { |
22663 | OMP_CLAUSE_CHAIN (l) |
22664 | = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; |
22665 | cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l; |
22666 | } |
22667 | else |
22668 | { |
22669 | OMP_CLAUSE_CHAIN (l) = clauses; |
22670 | clauses = l; |
22671 | } |
22672 | } |
22673 | } |
22674 | } |
22675 | OMP_FOR_CLAUSES (stmt) = clauses; |
22676 | } |
22677 | ret = stmt; |
22678 | } |
22679 | |
22680 | parser->omp_for_parse_state = save_data; |
22681 | return ret; |
22682 | } |
22683 | |
22684 | /* Helper function for OpenMP parsing, split clauses and call |
22685 | finish_omp_clauses on each of the set of clauses afterwards. */ |
22686 | |
22687 | static void |
22688 | omp_split_clauses (location_t loc, enum tree_code code, |
22689 | omp_clause_mask mask, tree clauses, tree *cclauses) |
22690 | { |
22691 | int i; |
22692 | c_omp_split_clauses (loc, code, mask, clauses, cclauses); |
22693 | for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) |
22694 | if (cclauses[i]) |
22695 | cclauses[i] = c_finish_omp_clauses (cclauses[i], |
22696 | i == C_OMP_CLAUSE_SPLIT_TARGET |
22697 | ? C_ORT_OMP_TARGET : C_ORT_OMP); |
22698 | } |
22699 | |
22700 | /* OpenMP 5.0: |
22701 | #pragma omp loop loop-clause[optseq] new-line |
22702 | for-loop |
22703 | |
22704 | LOC is the location of the #pragma token. |
22705 | */ |
22706 | |
22707 | #define OMP_LOOP_CLAUSE_MASK \ |
22708 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22709 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22710 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22711 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
22712 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_BIND) \ |
22713 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
22714 | |
22715 | static tree |
22716 | c_parser_omp_loop (location_t loc, c_parser *parser, |
22717 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22718 | bool *if_p) |
22719 | { |
22720 | tree block, clauses, ret; |
22721 | |
22722 | strcat (dest: p_name, src: " loop" ); |
22723 | mask |= OMP_LOOP_CLAUSE_MASK; |
22724 | |
22725 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22726 | if (cclauses) |
22727 | { |
22728 | omp_split_clauses (loc, code: OMP_LOOP, mask, clauses, cclauses); |
22729 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_LOOP]; |
22730 | } |
22731 | |
22732 | block = c_begin_compound_stmt (true); |
22733 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_LOOP, clauses, cclauses, if_p); |
22734 | block = c_end_compound_stmt (loc, block, true); |
22735 | add_stmt (block); |
22736 | |
22737 | return ret; |
22738 | } |
22739 | |
22740 | /* OpenMP 4.0: |
22741 | #pragma omp simd simd-clause[optseq] new-line |
22742 | for-loop |
22743 | |
22744 | LOC is the location of the #pragma token. |
22745 | */ |
22746 | |
22747 | #define OMP_SIMD_CLAUSE_MASK \ |
22748 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \ |
22749 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ |
22750 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ |
22751 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ |
22752 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22753 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22754 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22755 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
22756 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
22757 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL) \ |
22758 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
22759 | |
22760 | static tree |
22761 | c_parser_omp_simd (location_t loc, c_parser *parser, |
22762 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22763 | bool *if_p) |
22764 | { |
22765 | tree block, clauses, ret; |
22766 | |
22767 | strcat (dest: p_name, src: " simd" ); |
22768 | mask |= OMP_SIMD_CLAUSE_MASK; |
22769 | |
22770 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22771 | if (cclauses) |
22772 | { |
22773 | omp_split_clauses (loc, code: OMP_SIMD, mask, clauses, cclauses); |
22774 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; |
22775 | } |
22776 | |
22777 | block = c_begin_compound_stmt (true); |
22778 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_SIMD, clauses, cclauses, if_p); |
22779 | block = c_end_compound_stmt (loc, block, true); |
22780 | add_stmt (block); |
22781 | |
22782 | return ret; |
22783 | } |
22784 | |
22785 | /* OpenMP 2.5: |
22786 | #pragma omp for for-clause[optseq] new-line |
22787 | for-loop |
22788 | |
22789 | OpenMP 4.0: |
22790 | #pragma omp for simd for-simd-clause[optseq] new-line |
22791 | for-loop |
22792 | |
22793 | LOC is the location of the #pragma token. |
22794 | */ |
22795 | |
22796 | #define OMP_FOR_CLAUSE_MASK \ |
22797 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
22798 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
22799 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
22800 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ |
22801 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
22802 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \ |
22803 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \ |
22804 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
22805 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ |
22806 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
22807 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
22808 | |
22809 | static tree |
22810 | c_parser_omp_for (location_t loc, c_parser *parser, |
22811 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22812 | bool *if_p) |
22813 | { |
22814 | tree block, clauses, ret; |
22815 | |
22816 | strcat (dest: p_name, src: " for" ); |
22817 | mask |= OMP_FOR_CLAUSE_MASK; |
22818 | /* parallel for{, simd} disallows nowait clause, but for |
22819 | target {teams distribute ,}parallel for{, simd} it should be accepted. */ |
22820 | if (cclauses && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) == 0) |
22821 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); |
22822 | /* Composite distribute parallel for{, simd} disallows ordered clause. */ |
22823 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) |
22824 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED); |
22825 | |
22826 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22827 | { |
22828 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22829 | |
22830 | if (strcmp (s1: p, s2: "simd" ) == 0) |
22831 | { |
22832 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22833 | if (cclauses == NULL) |
22834 | cclauses = cclauses_buf; |
22835 | |
22836 | c_parser_consume_token (parser); |
22837 | if (!flag_openmp) /* flag_openmp_simd */ |
22838 | return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
22839 | if_p); |
22840 | block = c_begin_compound_stmt (true); |
22841 | ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); |
22842 | block = c_end_compound_stmt (loc, block, true); |
22843 | if (ret == NULL_TREE) |
22844 | return ret; |
22845 | ret = make_node (OMP_FOR); |
22846 | TREE_TYPE (ret) = void_type_node; |
22847 | OMP_FOR_BODY (ret) = block; |
22848 | OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; |
22849 | SET_EXPR_LOCATION (ret, loc); |
22850 | add_stmt (ret); |
22851 | return ret; |
22852 | } |
22853 | } |
22854 | if (!flag_openmp) /* flag_openmp_simd */ |
22855 | { |
22856 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22857 | return NULL_TREE; |
22858 | } |
22859 | |
22860 | /* Composite distribute parallel for disallows linear clause. */ |
22861 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) |
22862 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR); |
22863 | |
22864 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22865 | if (cclauses) |
22866 | { |
22867 | omp_split_clauses (loc, code: OMP_FOR, mask, clauses, cclauses); |
22868 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; |
22869 | } |
22870 | |
22871 | block = c_begin_compound_stmt (true); |
22872 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_FOR, clauses, cclauses, if_p); |
22873 | block = c_end_compound_stmt (loc, block, true); |
22874 | add_stmt (block); |
22875 | |
22876 | return ret; |
22877 | } |
22878 | |
22879 | static tree c_parser_omp_taskloop (location_t, c_parser *, char *, |
22880 | omp_clause_mask, tree *, bool *); |
22881 | |
22882 | /* OpenMP 2.5: |
22883 | # pragma omp master new-line |
22884 | structured-block |
22885 | |
22886 | LOC is the location of the #pragma token. |
22887 | */ |
22888 | |
22889 | static tree |
22890 | c_parser_omp_master (location_t loc, c_parser *parser, |
22891 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22892 | bool *if_p) |
22893 | { |
22894 | tree block, clauses, ret; |
22895 | |
22896 | strcat (dest: p_name, src: " master" ); |
22897 | |
22898 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22899 | { |
22900 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22901 | |
22902 | if (strcmp (s1: p, s2: "taskloop" ) == 0) |
22903 | { |
22904 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22905 | if (cclauses == NULL) |
22906 | cclauses = cclauses_buf; |
22907 | |
22908 | c_parser_consume_token (parser); |
22909 | if (!flag_openmp) /* flag_openmp_simd */ |
22910 | return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22911 | if_p); |
22912 | block = c_begin_compound_stmt (true); |
22913 | ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22914 | if_p); |
22915 | block = c_end_compound_stmt (loc, block, true); |
22916 | if (ret == NULL_TREE) |
22917 | return ret; |
22918 | ret = c_finish_omp_master (loc, block); |
22919 | OMP_MASTER_COMBINED (ret) = 1; |
22920 | return ret; |
22921 | } |
22922 | } |
22923 | if (!flag_openmp) /* flag_openmp_simd */ |
22924 | { |
22925 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22926 | return NULL_TREE; |
22927 | } |
22928 | |
22929 | if (cclauses) |
22930 | { |
22931 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: false); |
22932 | omp_split_clauses (loc, code: OMP_MASTER, mask, clauses, cclauses); |
22933 | } |
22934 | else |
22935 | c_parser_skip_to_pragma_eol (parser); |
22936 | |
22937 | return c_finish_omp_master (loc, c_parser_omp_structured_block (parser, |
22938 | if_p)); |
22939 | } |
22940 | |
22941 | /* OpenMP 5.1: |
22942 | # pragma omp masked masked-clauses new-line |
22943 | structured-block |
22944 | |
22945 | LOC is the location of the #pragma token. |
22946 | */ |
22947 | |
22948 | #define OMP_MASKED_CLAUSE_MASK \ |
22949 | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) |
22950 | |
22951 | static tree |
22952 | c_parser_omp_masked (location_t loc, c_parser *parser, |
22953 | char *p_name, omp_clause_mask mask, tree *cclauses, |
22954 | bool *if_p) |
22955 | { |
22956 | tree block, clauses, ret; |
22957 | |
22958 | strcat (dest: p_name, src: " masked" ); |
22959 | mask |= OMP_MASKED_CLAUSE_MASK; |
22960 | |
22961 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
22962 | { |
22963 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
22964 | |
22965 | if (strcmp (s1: p, s2: "taskloop" ) == 0) |
22966 | { |
22967 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
22968 | if (cclauses == NULL) |
22969 | cclauses = cclauses_buf; |
22970 | |
22971 | c_parser_consume_token (parser); |
22972 | if (!flag_openmp) /* flag_openmp_simd */ |
22973 | return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22974 | if_p); |
22975 | block = c_begin_compound_stmt (true); |
22976 | ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, |
22977 | if_p); |
22978 | block = c_end_compound_stmt (loc, block, true); |
22979 | if (ret == NULL_TREE) |
22980 | return ret; |
22981 | ret = c_finish_omp_masked (loc, block, |
22982 | cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); |
22983 | OMP_MASKED_COMBINED (ret) = 1; |
22984 | return ret; |
22985 | } |
22986 | } |
22987 | if (!flag_openmp) /* flag_openmp_simd */ |
22988 | { |
22989 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
22990 | return NULL_TREE; |
22991 | } |
22992 | |
22993 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
22994 | if (cclauses) |
22995 | { |
22996 | omp_split_clauses (loc, code: OMP_MASKED, mask, clauses, cclauses); |
22997 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; |
22998 | } |
22999 | |
23000 | return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, |
23001 | if_p), |
23002 | clauses); |
23003 | } |
23004 | |
23005 | /* OpenMP 2.5: |
23006 | # pragma omp ordered new-line |
23007 | structured-block |
23008 | |
23009 | OpenMP 4.5: |
23010 | # pragma omp ordered ordered-clauses new-line |
23011 | structured-block |
23012 | |
23013 | # pragma omp ordered depend-clauses new-line |
23014 | |
23015 | OpenMP 5.2 |
23016 | # pragma omp ordered doacross-clauses new-line */ |
23017 | |
23018 | #define OMP_ORDERED_CLAUSE_MASK \ |
23019 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ |
23020 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) |
23021 | |
23022 | #define OMP_ORDERED_DEPEND_CLAUSE_MASK \ |
23023 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23024 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS)) |
23025 | |
23026 | static bool |
23027 | c_parser_omp_ordered (c_parser *parser, enum pragma_context context, |
23028 | bool *if_p) |
23029 | { |
23030 | location_t loc = c_parser_peek_token (parser)->location; |
23031 | c_parser_consume_pragma (parser); |
23032 | |
23033 | if (context != pragma_stmt && context != pragma_compound) |
23034 | { |
23035 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
23036 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23037 | return false; |
23038 | } |
23039 | |
23040 | int n = 1; |
23041 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
23042 | n = 2; |
23043 | |
23044 | if (c_parser_peek_nth_token (parser, n)->type == CPP_NAME) |
23045 | { |
23046 | const char *p |
23047 | = IDENTIFIER_POINTER (c_parser_peek_nth_token (parser, n)->value); |
23048 | |
23049 | if (!strcmp (s1: "depend" , s2: p) || !strcmp (s1: "doacross" , s2: p)) |
23050 | { |
23051 | if (!flag_openmp) /* flag_openmp_simd */ |
23052 | { |
23053 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23054 | return false; |
23055 | } |
23056 | if (context == pragma_stmt) |
23057 | { |
23058 | error_at (loc, |
23059 | "%<#pragma omp ordered%> with %qs clause may " |
23060 | "only be used in compound statements" , p); |
23061 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23062 | return true; |
23063 | } |
23064 | |
23065 | tree clauses |
23066 | = c_parser_omp_all_clauses (parser, |
23067 | OMP_ORDERED_DEPEND_CLAUSE_MASK, |
23068 | where: "#pragma omp ordered" ); |
23069 | c_finish_omp_ordered (loc, clauses, NULL_TREE); |
23070 | return false; |
23071 | } |
23072 | } |
23073 | |
23074 | tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK, |
23075 | where: "#pragma omp ordered" ); |
23076 | |
23077 | if (!flag_openmp /* flag_openmp_simd */ |
23078 | && omp_find_clause (clauses, kind: OMP_CLAUSE_SIMD) == NULL_TREE) |
23079 | return false; |
23080 | |
23081 | c_finish_omp_ordered (loc, clauses, |
23082 | c_parser_omp_structured_block (parser, if_p)); |
23083 | return true; |
23084 | } |
23085 | |
23086 | /* OpenMP 2.5: |
23087 | |
23088 | section-scope: |
23089 | { section-sequence } |
23090 | |
23091 | section-sequence: |
23092 | section-directive[opt] structured-block |
23093 | section-sequence section-directive structured-block |
23094 | |
23095 | OpenMP 5.1 allows structured-block-sequence instead of structured-block. |
23096 | |
23097 | SECTIONS_LOC is the location of the #pragma omp sections. */ |
23098 | |
23099 | static tree |
23100 | c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser) |
23101 | { |
23102 | tree stmt, substmt; |
23103 | bool error_suppress = false; |
23104 | location_t loc; |
23105 | |
23106 | loc = c_parser_peek_token (parser)->location; |
23107 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
23108 | { |
23109 | /* Avoid skipping until the end of the block. */ |
23110 | parser->error = false; |
23111 | return NULL_TREE; |
23112 | } |
23113 | |
23114 | stmt = push_stmt_list (); |
23115 | |
23116 | if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION |
23117 | && !c_parser_omp_section_scan (parser, directive: "section" , tentative: true)) |
23118 | { |
23119 | substmt = c_parser_omp_structured_block_sequence (parser, |
23120 | kind: PRAGMA_OMP_SECTION); |
23121 | substmt = build1 (OMP_SECTION, void_type_node, substmt); |
23122 | SET_EXPR_LOCATION (substmt, loc); |
23123 | add_stmt (substmt); |
23124 | } |
23125 | |
23126 | while (1) |
23127 | { |
23128 | if (c_parser_next_token_is (parser, type: CPP_CLOSE_BRACE)) |
23129 | break; |
23130 | if (c_parser_next_token_is (parser, type: CPP_EOF)) |
23131 | break; |
23132 | |
23133 | loc = c_parser_peek_token (parser)->location; |
23134 | c_parser_omp_section_scan (parser, directive: "section" , tentative: false); |
23135 | if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION) |
23136 | { |
23137 | c_parser_consume_pragma (parser); |
23138 | c_parser_skip_to_pragma_eol (parser); |
23139 | error_suppress = false; |
23140 | } |
23141 | else if (!error_suppress) |
23142 | { |
23143 | error_at (loc, "expected %<#pragma omp section%> or %<}%>" ); |
23144 | error_suppress = true; |
23145 | } |
23146 | |
23147 | substmt = c_parser_omp_structured_block_sequence (parser, |
23148 | kind: PRAGMA_OMP_SECTION); |
23149 | substmt = build1 (OMP_SECTION, void_type_node, substmt); |
23150 | SET_EXPR_LOCATION (substmt, loc); |
23151 | add_stmt (substmt); |
23152 | } |
23153 | c_parser_skip_until_found (parser, type: CPP_CLOSE_BRACE, |
23154 | msgid: "expected %<#pragma omp section%> or %<}%>" ); |
23155 | |
23156 | substmt = pop_stmt_list (stmt); |
23157 | |
23158 | stmt = make_node (OMP_SECTIONS); |
23159 | SET_EXPR_LOCATION (stmt, sections_loc); |
23160 | TREE_TYPE (stmt) = void_type_node; |
23161 | OMP_SECTIONS_BODY (stmt) = substmt; |
23162 | |
23163 | return add_stmt (stmt); |
23164 | } |
23165 | |
23166 | /* OpenMP 2.5: |
23167 | # pragma omp sections sections-clause[optseq] newline |
23168 | sections-scope |
23169 | |
23170 | LOC is the location of the #pragma token. |
23171 | */ |
23172 | |
23173 | #define OMP_SECTIONS_CLAUSE_MASK \ |
23174 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23175 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23176 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
23177 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
23178 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23179 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23180 | |
23181 | static tree |
23182 | c_parser_omp_sections (location_t loc, c_parser *parser, |
23183 | char *p_name, omp_clause_mask mask, tree *cclauses) |
23184 | { |
23185 | tree block, clauses, ret; |
23186 | |
23187 | strcat (dest: p_name, src: " sections" ); |
23188 | mask |= OMP_SECTIONS_CLAUSE_MASK; |
23189 | if (cclauses) |
23190 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT); |
23191 | |
23192 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
23193 | if (cclauses) |
23194 | { |
23195 | omp_split_clauses (loc, code: OMP_SECTIONS, mask, clauses, cclauses); |
23196 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_SECTIONS]; |
23197 | } |
23198 | |
23199 | block = c_begin_compound_stmt (true); |
23200 | ret = c_parser_omp_sections_scope (sections_loc: loc, parser); |
23201 | if (ret) |
23202 | OMP_SECTIONS_CLAUSES (ret) = clauses; |
23203 | block = c_end_compound_stmt (loc, block, true); |
23204 | add_stmt (block); |
23205 | |
23206 | return ret; |
23207 | } |
23208 | |
23209 | /* OpenMP 2.5: |
23210 | # pragma omp parallel parallel-clause[optseq] new-line |
23211 | structured-block |
23212 | # pragma omp parallel for parallel-for-clause[optseq] new-line |
23213 | structured-block |
23214 | # pragma omp parallel sections parallel-sections-clause[optseq] new-line |
23215 | structured-block |
23216 | |
23217 | OpenMP 4.0: |
23218 | # pragma omp parallel for simd parallel-for-simd-clause[optseq] new-line |
23219 | structured-block |
23220 | |
23221 | LOC is the location of the #pragma token. |
23222 | */ |
23223 | |
23224 | #define OMP_PARALLEL_CLAUSE_MASK \ |
23225 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23226 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23227 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23228 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
23229 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
23230 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \ |
23231 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
23232 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \ |
23233 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23234 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND)) |
23235 | |
23236 | static tree |
23237 | c_parser_omp_parallel (location_t loc, c_parser *parser, |
23238 | char *p_name, omp_clause_mask mask, tree *cclauses, |
23239 | bool *if_p) |
23240 | { |
23241 | tree stmt, clauses, block; |
23242 | |
23243 | strcat (dest: p_name, src: " parallel" ); |
23244 | mask |= OMP_PARALLEL_CLAUSE_MASK; |
23245 | /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */ |
23246 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0 |
23247 | && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) |
23248 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN); |
23249 | |
23250 | if (c_parser_next_token_is_keyword (parser, keyword: RID_FOR)) |
23251 | { |
23252 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23253 | if (cclauses == NULL) |
23254 | cclauses = cclauses_buf; |
23255 | |
23256 | c_parser_consume_token (parser); |
23257 | if (!flag_openmp) /* flag_openmp_simd */ |
23258 | return c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); |
23259 | block = c_begin_omp_parallel (); |
23260 | tree ret = c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p); |
23261 | stmt |
23262 | = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
23263 | block); |
23264 | if (ret == NULL_TREE) |
23265 | return ret; |
23266 | OMP_PARALLEL_COMBINED (stmt) = 1; |
23267 | return stmt; |
23268 | } |
23269 | /* When combined with distribute, parallel has to be followed by for. |
23270 | #pragma omp target parallel is allowed though. */ |
23271 | else if (cclauses |
23272 | && (mask & (OMP_CLAUSE_MASK_1 |
23273 | << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) |
23274 | { |
23275 | error_at (loc, "expected %<for%> after %qs" , p_name); |
23276 | c_parser_skip_to_pragma_eol (parser); |
23277 | return NULL_TREE; |
23278 | } |
23279 | else if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23280 | { |
23281 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23282 | if (cclauses == NULL && strcmp (s1: p, s2: "masked" ) == 0) |
23283 | { |
23284 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23285 | cclauses = cclauses_buf; |
23286 | |
23287 | c_parser_consume_token (parser); |
23288 | if (!flag_openmp) /* flag_openmp_simd */ |
23289 | return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, |
23290 | if_p); |
23291 | block = c_begin_omp_parallel (); |
23292 | tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, |
23293 | if_p); |
23294 | stmt = c_finish_omp_parallel (loc, |
23295 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
23296 | block); |
23297 | if (ret == NULL) |
23298 | return ret; |
23299 | /* masked does have just filter clause, but during gimplification |
23300 | isn't represented by a gimplification omp context, so for |
23301 | #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, |
23302 | so that |
23303 | #pragma omp parallel masked |
23304 | #pragma omp taskloop simd lastprivate (x) |
23305 | isn't confused with |
23306 | #pragma omp parallel masked taskloop simd lastprivate (x) */ |
23307 | if (OMP_MASKED_COMBINED (ret)) |
23308 | OMP_PARALLEL_COMBINED (stmt) = 1; |
23309 | return stmt; |
23310 | } |
23311 | else if (cclauses == NULL && strcmp (s1: p, s2: "master" ) == 0) |
23312 | { |
23313 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23314 | cclauses = cclauses_buf; |
23315 | |
23316 | c_parser_consume_token (parser); |
23317 | if (!flag_openmp) /* flag_openmp_simd */ |
23318 | return c_parser_omp_master (loc, parser, p_name, mask, cclauses, |
23319 | if_p); |
23320 | block = c_begin_omp_parallel (); |
23321 | tree ret = c_parser_omp_master (loc, parser, p_name, mask, cclauses, |
23322 | if_p); |
23323 | stmt = c_finish_omp_parallel (loc, |
23324 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
23325 | block); |
23326 | if (ret == NULL) |
23327 | return ret; |
23328 | /* master doesn't have any clauses and during gimplification |
23329 | isn't represented by a gimplification omp context, so for |
23330 | #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, |
23331 | so that |
23332 | #pragma omp parallel master |
23333 | #pragma omp taskloop simd lastprivate (x) |
23334 | isn't confused with |
23335 | #pragma omp parallel master taskloop simd lastprivate (x) */ |
23336 | if (OMP_MASTER_COMBINED (ret)) |
23337 | OMP_PARALLEL_COMBINED (stmt) = 1; |
23338 | return stmt; |
23339 | } |
23340 | else if (strcmp (s1: p, s2: "loop" ) == 0) |
23341 | { |
23342 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23343 | if (cclauses == NULL) |
23344 | cclauses = cclauses_buf; |
23345 | |
23346 | c_parser_consume_token (parser); |
23347 | if (!flag_openmp) /* flag_openmp_simd */ |
23348 | return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, |
23349 | if_p); |
23350 | block = c_begin_omp_parallel (); |
23351 | tree ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, |
23352 | if_p); |
23353 | stmt |
23354 | = c_finish_omp_parallel (loc, |
23355 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
23356 | block); |
23357 | if (ret == NULL_TREE) |
23358 | return ret; |
23359 | OMP_PARALLEL_COMBINED (stmt) = 1; |
23360 | return stmt; |
23361 | } |
23362 | else if (!flag_openmp) /* flag_openmp_simd */ |
23363 | { |
23364 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23365 | return NULL_TREE; |
23366 | } |
23367 | else if (cclauses == NULL && strcmp (s1: p, s2: "sections" ) == 0) |
23368 | { |
23369 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23370 | cclauses = cclauses_buf; |
23371 | |
23372 | c_parser_consume_token (parser); |
23373 | block = c_begin_omp_parallel (); |
23374 | c_parser_omp_sections (loc, parser, p_name, mask, cclauses); |
23375 | stmt = c_finish_omp_parallel (loc, |
23376 | cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], |
23377 | block); |
23378 | OMP_PARALLEL_COMBINED (stmt) = 1; |
23379 | return stmt; |
23380 | } |
23381 | } |
23382 | else if (!flag_openmp) /* flag_openmp_simd */ |
23383 | { |
23384 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23385 | return NULL_TREE; |
23386 | } |
23387 | |
23388 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
23389 | if (cclauses) |
23390 | { |
23391 | omp_split_clauses (loc, code: OMP_PARALLEL, mask, clauses, cclauses); |
23392 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; |
23393 | } |
23394 | |
23395 | block = c_begin_omp_parallel (); |
23396 | parser->omp_attrs_forbidden_p = true; |
23397 | c_parser_statement (parser, if_p); |
23398 | stmt = c_finish_omp_parallel (loc, clauses, block); |
23399 | |
23400 | return stmt; |
23401 | } |
23402 | |
23403 | /* OpenMP 2.5: |
23404 | # pragma omp single single-clause[optseq] new-line |
23405 | structured-block |
23406 | |
23407 | LOC is the location of the #pragma. |
23408 | */ |
23409 | |
23410 | #define OMP_SINGLE_CLAUSE_MASK \ |
23411 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23412 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23413 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \ |
23414 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23415 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23416 | |
23417 | static tree |
23418 | c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) |
23419 | { |
23420 | tree stmt = make_node (OMP_SINGLE); |
23421 | SET_EXPR_LOCATION (stmt, loc); |
23422 | TREE_TYPE (stmt) = void_type_node; |
23423 | |
23424 | OMP_SINGLE_CLAUSES (stmt) |
23425 | = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK, |
23426 | where: "#pragma omp single" ); |
23427 | OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); |
23428 | |
23429 | return add_stmt (stmt); |
23430 | } |
23431 | |
23432 | /* OpenMP 5.1: |
23433 | # pragma omp scope scope-clause[optseq] new-line |
23434 | structured-block |
23435 | |
23436 | LOC is the location of the #pragma. |
23437 | */ |
23438 | |
23439 | #define OMP_SCOPE_CLAUSE_MASK \ |
23440 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23441 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23442 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
23443 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23444 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23445 | |
23446 | static tree |
23447 | c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) |
23448 | { |
23449 | tree stmt = make_node (OMP_SCOPE); |
23450 | SET_EXPR_LOCATION (stmt, loc); |
23451 | TREE_TYPE (stmt) = void_type_node; |
23452 | |
23453 | OMP_SCOPE_CLAUSES (stmt) |
23454 | = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, |
23455 | where: "#pragma omp scope" ); |
23456 | OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); |
23457 | |
23458 | return add_stmt (stmt); |
23459 | } |
23460 | |
23461 | /* OpenMP 3.0: |
23462 | # pragma omp task task-clause[optseq] new-line |
23463 | |
23464 | LOC is the location of the #pragma. |
23465 | */ |
23466 | |
23467 | #define OMP_TASK_CLAUSE_MASK \ |
23468 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23469 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ |
23470 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
23471 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23472 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23473 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
23474 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ |
23475 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ |
23476 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23477 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ |
23478 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23479 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ |
23480 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ |
23481 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) |
23482 | |
23483 | static tree |
23484 | c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) |
23485 | { |
23486 | tree clauses, block; |
23487 | |
23488 | clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK, |
23489 | where: "#pragma omp task" ); |
23490 | |
23491 | block = c_begin_omp_task (); |
23492 | parser->omp_attrs_forbidden_p = true; |
23493 | c_parser_statement (parser, if_p); |
23494 | return c_finish_omp_task (loc, clauses, block); |
23495 | } |
23496 | |
23497 | /* OpenMP 3.0: |
23498 | # pragma omp taskwait new-line |
23499 | |
23500 | OpenMP 5.0: |
23501 | # pragma omp taskwait taskwait-clause[optseq] new-line |
23502 | */ |
23503 | |
23504 | #define OMP_TASKWAIT_CLAUSE_MASK \ |
23505 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23506 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23507 | |
23508 | static void |
23509 | c_parser_omp_taskwait (c_parser *parser) |
23510 | { |
23511 | location_t loc = c_parser_peek_token (parser)->location; |
23512 | c_parser_consume_pragma (parser); |
23513 | |
23514 | tree clauses |
23515 | = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK, |
23516 | where: "#pragma omp taskwait" ); |
23517 | |
23518 | if (clauses) |
23519 | { |
23520 | tree stmt = make_node (OMP_TASK); |
23521 | TREE_TYPE (stmt) = void_node; |
23522 | OMP_TASK_CLAUSES (stmt) = clauses; |
23523 | OMP_TASK_BODY (stmt) = NULL_TREE; |
23524 | SET_EXPR_LOCATION (stmt, loc); |
23525 | add_stmt (stmt); |
23526 | } |
23527 | else |
23528 | c_finish_omp_taskwait (loc); |
23529 | } |
23530 | |
23531 | /* OpenMP 3.1: |
23532 | # pragma omp taskyield new-line |
23533 | */ |
23534 | |
23535 | static void |
23536 | c_parser_omp_taskyield (c_parser *parser) |
23537 | { |
23538 | location_t loc = c_parser_peek_token (parser)->location; |
23539 | c_parser_consume_pragma (parser); |
23540 | c_parser_skip_to_pragma_eol (parser); |
23541 | |
23542 | c_finish_omp_taskyield (loc); |
23543 | } |
23544 | |
23545 | /* OpenMP 4.0: |
23546 | # pragma omp taskgroup new-line |
23547 | |
23548 | OpenMP 5.0: |
23549 | # pragma omp taskgroup taskgroup-clause[optseq] new-line |
23550 | */ |
23551 | |
23552 | #define OMP_TASKGROUP_CLAUSE_MASK \ |
23553 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23554 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION)) |
23555 | |
23556 | static tree |
23557 | c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p) |
23558 | { |
23559 | tree clauses = c_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK, |
23560 | where: "#pragma omp taskgroup" ); |
23561 | |
23562 | tree body = c_parser_omp_structured_block (parser, if_p); |
23563 | return c_finish_omp_taskgroup (loc, body, clauses); |
23564 | } |
23565 | |
23566 | /* OpenMP 4.0: |
23567 | # pragma omp cancel cancel-clause[optseq] new-line |
23568 | |
23569 | LOC is the location of the #pragma. |
23570 | */ |
23571 | |
23572 | #define OMP_CANCEL_CLAUSE_MASK \ |
23573 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ |
23574 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ |
23575 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ |
23576 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \ |
23577 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)) |
23578 | |
23579 | static void |
23580 | c_parser_omp_cancel (c_parser *parser) |
23581 | { |
23582 | location_t loc = c_parser_peek_token (parser)->location; |
23583 | |
23584 | c_parser_consume_pragma (parser); |
23585 | tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK, |
23586 | where: "#pragma omp cancel" ); |
23587 | |
23588 | c_finish_omp_cancel (loc, clauses); |
23589 | } |
23590 | |
23591 | /* OpenMP 4.0: |
23592 | # pragma omp cancellation point cancelpt-clause[optseq] new-line |
23593 | |
23594 | LOC is the location of the #pragma. |
23595 | */ |
23596 | |
23597 | #define OMP_CANCELLATION_POINT_CLAUSE_MASK \ |
23598 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \ |
23599 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \ |
23600 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ |
23601 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) |
23602 | |
23603 | static bool |
23604 | c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) |
23605 | { |
23606 | location_t loc = c_parser_peek_token (parser)->location; |
23607 | tree clauses; |
23608 | bool point_seen = false; |
23609 | |
23610 | c_parser_consume_pragma (parser); |
23611 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23612 | { |
23613 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23614 | if (strcmp (s1: p, s2: "point" ) == 0) |
23615 | { |
23616 | c_parser_consume_token (parser); |
23617 | point_seen = true; |
23618 | } |
23619 | } |
23620 | if (!point_seen) |
23621 | { |
23622 | c_parser_error (parser, gmsgid: "expected %<point%>" ); |
23623 | c_parser_skip_to_pragma_eol (parser); |
23624 | return false; |
23625 | } |
23626 | |
23627 | if (context != pragma_compound) |
23628 | { |
23629 | if (context == pragma_stmt) |
23630 | error_at (loc, |
23631 | "%<#pragma %s%> may only be used in compound statements" , |
23632 | "omp cancellation point" ); |
23633 | else |
23634 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
23635 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23636 | return true; |
23637 | } |
23638 | |
23639 | clauses |
23640 | = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK, |
23641 | where: "#pragma omp cancellation point" ); |
23642 | |
23643 | c_finish_omp_cancellation_point (loc, clauses); |
23644 | return true; |
23645 | } |
23646 | |
23647 | /* OpenMP 4.0: |
23648 | #pragma omp distribute distribute-clause[optseq] new-line |
23649 | for-loop */ |
23650 | |
23651 | #define OMP_DISTRIBUTE_CLAUSE_MASK \ |
23652 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23653 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23654 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
23655 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ |
23656 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23657 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
23658 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) |
23659 | |
23660 | static tree |
23661 | c_parser_omp_distribute (location_t loc, c_parser *parser, |
23662 | char *p_name, omp_clause_mask mask, tree *cclauses, |
23663 | bool *if_p) |
23664 | { |
23665 | tree clauses, block, ret; |
23666 | |
23667 | strcat (dest: p_name, src: " distribute" ); |
23668 | mask |= OMP_DISTRIBUTE_CLAUSE_MASK; |
23669 | |
23670 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23671 | { |
23672 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23673 | bool simd = false; |
23674 | bool parallel = false; |
23675 | |
23676 | if (strcmp (s1: p, s2: "simd" ) == 0) |
23677 | simd = true; |
23678 | else |
23679 | parallel = strcmp (s1: p, s2: "parallel" ) == 0; |
23680 | if (parallel || simd) |
23681 | { |
23682 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23683 | if (cclauses == NULL) |
23684 | cclauses = cclauses_buf; |
23685 | c_parser_consume_token (parser); |
23686 | if (!flag_openmp) /* flag_openmp_simd */ |
23687 | { |
23688 | if (simd) |
23689 | return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
23690 | if_p); |
23691 | else |
23692 | return c_parser_omp_parallel (loc, parser, p_name, mask, |
23693 | cclauses, if_p); |
23694 | } |
23695 | block = c_begin_compound_stmt (true); |
23696 | if (simd) |
23697 | ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
23698 | if_p); |
23699 | else |
23700 | ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses, |
23701 | if_p); |
23702 | block = c_end_compound_stmt (loc, block, true); |
23703 | if (ret == NULL) |
23704 | return ret; |
23705 | ret = make_node (OMP_DISTRIBUTE); |
23706 | TREE_TYPE (ret) = void_type_node; |
23707 | OMP_FOR_BODY (ret) = block; |
23708 | OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; |
23709 | SET_EXPR_LOCATION (ret, loc); |
23710 | add_stmt (ret); |
23711 | return ret; |
23712 | } |
23713 | } |
23714 | if (!flag_openmp) /* flag_openmp_simd */ |
23715 | { |
23716 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23717 | return NULL_TREE; |
23718 | } |
23719 | |
23720 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
23721 | if (cclauses) |
23722 | { |
23723 | omp_split_clauses (loc, code: OMP_DISTRIBUTE, mask, clauses, cclauses); |
23724 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; |
23725 | } |
23726 | |
23727 | block = c_begin_compound_stmt (true); |
23728 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_DISTRIBUTE, clauses, NULL, |
23729 | if_p); |
23730 | block = c_end_compound_stmt (loc, block, true); |
23731 | add_stmt (block); |
23732 | |
23733 | return ret; |
23734 | } |
23735 | |
23736 | /* OpenMP 4.0: |
23737 | # pragma omp teams teams-clause[optseq] new-line |
23738 | structured-block */ |
23739 | |
23740 | #define OMP_TEAMS_CLAUSE_MASK \ |
23741 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
23742 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
23743 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
23744 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
23745 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \ |
23746 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ |
23747 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
23748 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)) |
23749 | |
23750 | static tree |
23751 | c_parser_omp_teams (location_t loc, c_parser *parser, |
23752 | char *p_name, omp_clause_mask mask, tree *cclauses, |
23753 | bool *if_p) |
23754 | { |
23755 | tree clauses, block, ret; |
23756 | |
23757 | strcat (dest: p_name, src: " teams" ); |
23758 | mask |= OMP_TEAMS_CLAUSE_MASK; |
23759 | |
23760 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23761 | { |
23762 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23763 | if (strcmp (s1: p, s2: "distribute" ) == 0) |
23764 | { |
23765 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23766 | if (cclauses == NULL) |
23767 | cclauses = cclauses_buf; |
23768 | |
23769 | c_parser_consume_token (parser); |
23770 | if (!flag_openmp) /* flag_openmp_simd */ |
23771 | return c_parser_omp_distribute (loc, parser, p_name, mask, |
23772 | cclauses, if_p); |
23773 | block = c_begin_omp_parallel (); |
23774 | ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses, |
23775 | if_p); |
23776 | block = c_end_compound_stmt (loc, block, true); |
23777 | if (ret == NULL) |
23778 | return ret; |
23779 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23780 | ret = make_node (OMP_TEAMS); |
23781 | TREE_TYPE (ret) = void_type_node; |
23782 | OMP_TEAMS_CLAUSES (ret) = clauses; |
23783 | OMP_TEAMS_BODY (ret) = block; |
23784 | OMP_TEAMS_COMBINED (ret) = 1; |
23785 | SET_EXPR_LOCATION (ret, loc); |
23786 | return add_stmt (ret); |
23787 | } |
23788 | else if (strcmp (s1: p, s2: "loop" ) == 0) |
23789 | { |
23790 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
23791 | if (cclauses == NULL) |
23792 | cclauses = cclauses_buf; |
23793 | |
23794 | c_parser_consume_token (parser); |
23795 | if (!flag_openmp) /* flag_openmp_simd */ |
23796 | return c_parser_omp_loop (loc, parser, p_name, mask, cclauses, |
23797 | if_p); |
23798 | block = c_begin_omp_parallel (); |
23799 | ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, if_p); |
23800 | block = c_end_compound_stmt (loc, block, true); |
23801 | if (ret == NULL) |
23802 | return ret; |
23803 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23804 | ret = make_node (OMP_TEAMS); |
23805 | TREE_TYPE (ret) = void_type_node; |
23806 | OMP_TEAMS_CLAUSES (ret) = clauses; |
23807 | OMP_TEAMS_BODY (ret) = block; |
23808 | OMP_TEAMS_COMBINED (ret) = 1; |
23809 | SET_EXPR_LOCATION (ret, loc); |
23810 | return add_stmt (ret); |
23811 | } |
23812 | } |
23813 | if (!flag_openmp) /* flag_openmp_simd */ |
23814 | { |
23815 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23816 | return NULL_TREE; |
23817 | } |
23818 | |
23819 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
23820 | if (cclauses) |
23821 | { |
23822 | omp_split_clauses (loc, code: OMP_TEAMS, mask, clauses, cclauses); |
23823 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
23824 | } |
23825 | |
23826 | tree stmt = make_node (OMP_TEAMS); |
23827 | TREE_TYPE (stmt) = void_type_node; |
23828 | OMP_TEAMS_CLAUSES (stmt) = clauses; |
23829 | block = c_begin_omp_parallel (); |
23830 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
23831 | OMP_TEAMS_BODY (stmt) = c_end_compound_stmt (loc, block, true); |
23832 | SET_EXPR_LOCATION (stmt, loc); |
23833 | |
23834 | return add_stmt (stmt); |
23835 | } |
23836 | |
23837 | /* OpenMP 4.0: |
23838 | # pragma omp target data target-data-clause[optseq] new-line |
23839 | structured-block */ |
23840 | |
23841 | #define OMP_TARGET_DATA_CLAUSE_MASK \ |
23842 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23843 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
23844 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23845 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR) \ |
23846 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR)) |
23847 | |
23848 | static tree |
23849 | c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p) |
23850 | { |
23851 | if (flag_openmp) |
23852 | omp_requires_mask |
23853 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23854 | |
23855 | tree clauses |
23856 | = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK, |
23857 | where: "#pragma omp target data" ); |
23858 | c_omp_adjust_map_clauses (clauses, false); |
23859 | int map_seen = 0; |
23860 | for (tree *pc = &clauses; *pc;) |
23861 | { |
23862 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
23863 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
23864 | { |
23865 | case GOMP_MAP_TO: |
23866 | case GOMP_MAP_ALWAYS_TO: |
23867 | case GOMP_MAP_PRESENT_TO: |
23868 | case GOMP_MAP_ALWAYS_PRESENT_TO: |
23869 | case GOMP_MAP_FROM: |
23870 | case GOMP_MAP_ALWAYS_FROM: |
23871 | case GOMP_MAP_PRESENT_FROM: |
23872 | case GOMP_MAP_ALWAYS_PRESENT_FROM: |
23873 | case GOMP_MAP_TOFROM: |
23874 | case GOMP_MAP_ALWAYS_TOFROM: |
23875 | case GOMP_MAP_PRESENT_TOFROM: |
23876 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
23877 | case GOMP_MAP_ALLOC: |
23878 | case GOMP_MAP_PRESENT_ALLOC: |
23879 | map_seen = 3; |
23880 | break; |
23881 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
23882 | case GOMP_MAP_ALWAYS_POINTER: |
23883 | case GOMP_MAP_ATTACH_DETACH: |
23884 | case GOMP_MAP_ATTACH: |
23885 | break; |
23886 | default: |
23887 | map_seen |= 1; |
23888 | error_at (OMP_CLAUSE_LOCATION (*pc), |
23889 | "%<#pragma omp target data%> with map-type other " |
23890 | "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> " |
23891 | "on %<map%> clause" ); |
23892 | *pc = OMP_CLAUSE_CHAIN (*pc); |
23893 | continue; |
23894 | } |
23895 | else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR |
23896 | || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR) |
23897 | map_seen = 3; |
23898 | pc = &OMP_CLAUSE_CHAIN (*pc); |
23899 | } |
23900 | |
23901 | if (map_seen != 3) |
23902 | { |
23903 | if (map_seen == 0) |
23904 | error_at (loc, |
23905 | "%<#pragma omp target data%> must contain at least " |
23906 | "one %<map%>, %<use_device_ptr%> or %<use_device_addr%> " |
23907 | "clause" ); |
23908 | return NULL_TREE; |
23909 | } |
23910 | |
23911 | tree stmt = make_node (OMP_TARGET_DATA); |
23912 | TREE_TYPE (stmt) = void_type_node; |
23913 | OMP_TARGET_DATA_CLAUSES (stmt) = clauses; |
23914 | keep_next_level (); |
23915 | tree block = c_begin_compound_stmt (true); |
23916 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
23917 | OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true); |
23918 | |
23919 | SET_EXPR_LOCATION (stmt, loc); |
23920 | return add_stmt (stmt); |
23921 | } |
23922 | |
23923 | /* OpenMP 4.0: |
23924 | # pragma omp target update target-update-clause[optseq] new-line */ |
23925 | |
23926 | #define OMP_TARGET_UPDATE_CLAUSE_MASK \ |
23927 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \ |
23928 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ |
23929 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23930 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23931 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23932 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23933 | |
23934 | static bool |
23935 | c_parser_omp_target_update (location_t loc, c_parser *parser, |
23936 | enum pragma_context context) |
23937 | { |
23938 | if (context == pragma_stmt) |
23939 | { |
23940 | error_at (loc, "%<#pragma %s%> may only be used in compound statements" , |
23941 | "omp target update" ); |
23942 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
23943 | return true; |
23944 | } |
23945 | |
23946 | tree clauses |
23947 | = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK, |
23948 | where: "#pragma omp target update" ); |
23949 | if (omp_find_clause (clauses, kind: OMP_CLAUSE_TO) == NULL_TREE |
23950 | && omp_find_clause (clauses, kind: OMP_CLAUSE_FROM) == NULL_TREE) |
23951 | { |
23952 | error_at (loc, |
23953 | "%<#pragma omp target update%> must contain at least one " |
23954 | "%<from%> or %<to%> clauses" ); |
23955 | return false; |
23956 | } |
23957 | |
23958 | if (flag_openmp) |
23959 | omp_requires_mask |
23960 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
23961 | |
23962 | tree stmt = make_node (OMP_TARGET_UPDATE); |
23963 | TREE_TYPE (stmt) = void_type_node; |
23964 | OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; |
23965 | SET_EXPR_LOCATION (stmt, loc); |
23966 | add_stmt (stmt); |
23967 | return false; |
23968 | } |
23969 | |
23970 | /* OpenMP 4.5: |
23971 | # pragma omp target enter data target-data-clause[optseq] new-line */ |
23972 | |
23973 | #define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \ |
23974 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
23975 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
23976 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
23977 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
23978 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
23979 | |
23980 | static bool |
23981 | c_parser_omp_target_enter_data (location_t loc, c_parser *parser, |
23982 | enum pragma_context context) |
23983 | { |
23984 | bool data_seen = false; |
23985 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
23986 | { |
23987 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
23988 | if (strcmp (s1: p, s2: "data" ) == 0) |
23989 | { |
23990 | c_parser_consume_token (parser); |
23991 | data_seen = true; |
23992 | } |
23993 | } |
23994 | if (!data_seen) |
23995 | { |
23996 | c_parser_error (parser, gmsgid: "expected %<data%>" ); |
23997 | c_parser_skip_to_pragma_eol (parser); |
23998 | return false; |
23999 | } |
24000 | |
24001 | if (context == pragma_stmt) |
24002 | { |
24003 | error_at (loc, "%<#pragma %s%> may only be used in compound statements" , |
24004 | "omp target enter data" ); |
24005 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
24006 | return true; |
24007 | } |
24008 | |
24009 | if (flag_openmp) |
24010 | omp_requires_mask |
24011 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
24012 | |
24013 | tree clauses |
24014 | = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK, |
24015 | where: "#pragma omp target enter data" ); |
24016 | c_omp_adjust_map_clauses (clauses, false); |
24017 | int map_seen = 0; |
24018 | for (tree *pc = &clauses; *pc;) |
24019 | { |
24020 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
24021 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
24022 | { |
24023 | case GOMP_MAP_TO: |
24024 | case GOMP_MAP_ALWAYS_TO: |
24025 | case GOMP_MAP_PRESENT_TO: |
24026 | case GOMP_MAP_ALWAYS_PRESENT_TO: |
24027 | case GOMP_MAP_ALLOC: |
24028 | case GOMP_MAP_PRESENT_ALLOC: |
24029 | map_seen = 3; |
24030 | break; |
24031 | case GOMP_MAP_TOFROM: |
24032 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_TO); |
24033 | map_seen = 3; |
24034 | break; |
24035 | case GOMP_MAP_ALWAYS_TOFROM: |
24036 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_TO); |
24037 | map_seen = 3; |
24038 | break; |
24039 | case GOMP_MAP_PRESENT_TOFROM: |
24040 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_TO); |
24041 | map_seen = 3; |
24042 | break; |
24043 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
24044 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_TO); |
24045 | map_seen = 3; |
24046 | break; |
24047 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
24048 | case GOMP_MAP_ALWAYS_POINTER: |
24049 | case GOMP_MAP_ATTACH_DETACH: |
24050 | case GOMP_MAP_ATTACH: |
24051 | break; |
24052 | default: |
24053 | map_seen |= 1; |
24054 | error_at (OMP_CLAUSE_LOCATION (*pc), |
24055 | "%<#pragma omp target enter data%> with map-type other " |
24056 | "than %<to%>, %<tofrom%> or %<alloc%> on %<map%> clause" ); |
24057 | *pc = OMP_CLAUSE_CHAIN (*pc); |
24058 | continue; |
24059 | } |
24060 | pc = &OMP_CLAUSE_CHAIN (*pc); |
24061 | } |
24062 | |
24063 | if (map_seen != 3) |
24064 | { |
24065 | if (map_seen == 0) |
24066 | error_at (loc, |
24067 | "%<#pragma omp target enter data%> must contain at least " |
24068 | "one %<map%> clause" ); |
24069 | return true; |
24070 | } |
24071 | |
24072 | tree stmt = make_node (OMP_TARGET_ENTER_DATA); |
24073 | TREE_TYPE (stmt) = void_type_node; |
24074 | OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; |
24075 | SET_EXPR_LOCATION (stmt, loc); |
24076 | add_stmt (stmt); |
24077 | return true; |
24078 | } |
24079 | |
24080 | /* OpenMP 4.5: |
24081 | # pragma omp target exit data target-data-clause[optseq] new-line */ |
24082 | |
24083 | #define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \ |
24084 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
24085 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
24086 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
24087 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
24088 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) |
24089 | |
24090 | static bool |
24091 | c_parser_omp_target_exit_data (location_t loc, c_parser *parser, |
24092 | enum pragma_context context) |
24093 | { |
24094 | bool data_seen = false; |
24095 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24096 | { |
24097 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24098 | if (strcmp (s1: p, s2: "data" ) == 0) |
24099 | { |
24100 | c_parser_consume_token (parser); |
24101 | data_seen = true; |
24102 | } |
24103 | } |
24104 | if (!data_seen) |
24105 | { |
24106 | c_parser_error (parser, gmsgid: "expected %<data%>" ); |
24107 | c_parser_skip_to_pragma_eol (parser); |
24108 | return false; |
24109 | } |
24110 | |
24111 | if (context == pragma_stmt) |
24112 | { |
24113 | error_at (loc, "%<#pragma %s%> may only be used in compound statements" , |
24114 | "omp target exit data" ); |
24115 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
24116 | return true; |
24117 | } |
24118 | |
24119 | if (flag_openmp) |
24120 | omp_requires_mask |
24121 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
24122 | |
24123 | tree clauses |
24124 | = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK, |
24125 | where: "#pragma omp target exit data" , finish_p: false); |
24126 | clauses = c_finish_omp_clauses (clauses, C_ORT_OMP_EXIT_DATA); |
24127 | c_omp_adjust_map_clauses (clauses, false); |
24128 | int map_seen = 0; |
24129 | for (tree *pc = &clauses; *pc;) |
24130 | { |
24131 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
24132 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
24133 | { |
24134 | case GOMP_MAP_FROM: |
24135 | case GOMP_MAP_ALWAYS_FROM: |
24136 | case GOMP_MAP_PRESENT_FROM: |
24137 | case GOMP_MAP_ALWAYS_PRESENT_FROM: |
24138 | case GOMP_MAP_RELEASE: |
24139 | case GOMP_MAP_DELETE: |
24140 | map_seen = 3; |
24141 | break; |
24142 | case GOMP_MAP_TOFROM: |
24143 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_FROM); |
24144 | map_seen = 3; |
24145 | break; |
24146 | case GOMP_MAP_ALWAYS_TOFROM: |
24147 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_FROM); |
24148 | map_seen = 3; |
24149 | break; |
24150 | case GOMP_MAP_PRESENT_TOFROM: |
24151 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_FROM); |
24152 | map_seen = 3; |
24153 | break; |
24154 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
24155 | OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_FROM); |
24156 | map_seen = 3; |
24157 | break; |
24158 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
24159 | case GOMP_MAP_ALWAYS_POINTER: |
24160 | case GOMP_MAP_ATTACH_DETACH: |
24161 | case GOMP_MAP_DETACH: |
24162 | break; |
24163 | default: |
24164 | map_seen |= 1; |
24165 | error_at (OMP_CLAUSE_LOCATION (*pc), |
24166 | "%<#pragma omp target exit data%> with map-type other " |
24167 | "than %<from%>, %<tofrom%>, %<release%> or %<delete%> " |
24168 | "on %<map%> clause" ); |
24169 | *pc = OMP_CLAUSE_CHAIN (*pc); |
24170 | continue; |
24171 | } |
24172 | pc = &OMP_CLAUSE_CHAIN (*pc); |
24173 | } |
24174 | |
24175 | if (map_seen != 3) |
24176 | { |
24177 | if (map_seen == 0) |
24178 | error_at (loc, |
24179 | "%<#pragma omp target exit data%> must contain at least one " |
24180 | "%<map%> clause" ); |
24181 | return true; |
24182 | } |
24183 | |
24184 | tree stmt = make_node (OMP_TARGET_EXIT_DATA); |
24185 | TREE_TYPE (stmt) = void_type_node; |
24186 | OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; |
24187 | SET_EXPR_LOCATION (stmt, loc); |
24188 | add_stmt (stmt); |
24189 | return true; |
24190 | } |
24191 | |
24192 | /* OpenMP 4.0: |
24193 | # pragma omp target target-clause[optseq] new-line |
24194 | structured-block */ |
24195 | |
24196 | #define OMP_TARGET_CLAUSE_MASK \ |
24197 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ |
24198 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \ |
24199 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
24200 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ |
24201 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \ |
24202 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
24203 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
24204 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
24205 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ |
24206 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ |
24207 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \ |
24208 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)\ |
24209 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR)) |
24210 | |
24211 | static bool |
24212 | c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) |
24213 | { |
24214 | location_t loc = c_parser_peek_token (parser)->location; |
24215 | c_parser_consume_pragma (parser); |
24216 | tree *pc = NULL, stmt, block; |
24217 | |
24218 | if (context != pragma_stmt && context != pragma_compound) |
24219 | { |
24220 | c_parser_error (parser, gmsgid: "expected declaration specifiers" ); |
24221 | c_parser_skip_to_pragma_eol (parser); |
24222 | return false; |
24223 | } |
24224 | |
24225 | if (flag_openmp) |
24226 | omp_requires_mask |
24227 | = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED); |
24228 | |
24229 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24230 | { |
24231 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24232 | enum tree_code ccode = ERROR_MARK; |
24233 | |
24234 | if (strcmp (s1: p, s2: "teams" ) == 0) |
24235 | ccode = OMP_TEAMS; |
24236 | else if (strcmp (s1: p, s2: "parallel" ) == 0) |
24237 | ccode = OMP_PARALLEL; |
24238 | else if (strcmp (s1: p, s2: "simd" ) == 0) |
24239 | ccode = OMP_SIMD; |
24240 | if (ccode != ERROR_MARK) |
24241 | { |
24242 | tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT]; |
24243 | char p_name[sizeof ("#pragma omp target teams distribute " |
24244 | "parallel for simd" )]; |
24245 | |
24246 | c_parser_consume_token (parser); |
24247 | strcpy (dest: p_name, src: "#pragma omp target" ); |
24248 | if (!flag_openmp) /* flag_openmp_simd */ |
24249 | { |
24250 | tree stmt; |
24251 | switch (ccode) |
24252 | { |
24253 | case OMP_TEAMS: |
24254 | stmt = c_parser_omp_teams (loc, parser, p_name, |
24255 | OMP_TARGET_CLAUSE_MASK, |
24256 | cclauses, if_p); |
24257 | break; |
24258 | case OMP_PARALLEL: |
24259 | stmt = c_parser_omp_parallel (loc, parser, p_name, |
24260 | OMP_TARGET_CLAUSE_MASK, |
24261 | cclauses, if_p); |
24262 | break; |
24263 | case OMP_SIMD: |
24264 | stmt = c_parser_omp_simd (loc, parser, p_name, |
24265 | OMP_TARGET_CLAUSE_MASK, |
24266 | cclauses, if_p); |
24267 | break; |
24268 | default: |
24269 | gcc_unreachable (); |
24270 | } |
24271 | return stmt != NULL_TREE; |
24272 | } |
24273 | keep_next_level (); |
24274 | tree block = c_begin_compound_stmt (true), ret; |
24275 | switch (ccode) |
24276 | { |
24277 | case OMP_TEAMS: |
24278 | ret = c_parser_omp_teams (loc, parser, p_name, |
24279 | OMP_TARGET_CLAUSE_MASK, cclauses, |
24280 | if_p); |
24281 | break; |
24282 | case OMP_PARALLEL: |
24283 | ret = c_parser_omp_parallel (loc, parser, p_name, |
24284 | OMP_TARGET_CLAUSE_MASK, cclauses, |
24285 | if_p); |
24286 | break; |
24287 | case OMP_SIMD: |
24288 | ret = c_parser_omp_simd (loc, parser, p_name, |
24289 | OMP_TARGET_CLAUSE_MASK, cclauses, |
24290 | if_p); |
24291 | break; |
24292 | default: |
24293 | gcc_unreachable (); |
24294 | } |
24295 | block = c_end_compound_stmt (loc, block, true); |
24296 | if (ret == NULL_TREE) |
24297 | return false; |
24298 | if (ccode == OMP_TEAMS) |
24299 | /* For combined target teams, ensure the num_teams and |
24300 | thread_limit clause expressions are evaluated on the host, |
24301 | before entering the target construct. */ |
24302 | for (tree c = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS]; |
24303 | c; c = OMP_CLAUSE_CHAIN (c)) |
24304 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS |
24305 | || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT) |
24306 | for (int i = 0; |
24307 | i <= (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS); ++i) |
24308 | if (OMP_CLAUSE_OPERAND (c, i) |
24309 | && TREE_CODE (OMP_CLAUSE_OPERAND (c, i)) != INTEGER_CST) |
24310 | { |
24311 | tree expr = OMP_CLAUSE_OPERAND (c, i); |
24312 | tree tmp = create_tmp_var_raw (TREE_TYPE (expr)); |
24313 | expr = build4 (TARGET_EXPR, TREE_TYPE (expr), tmp, |
24314 | expr, NULL_TREE, NULL_TREE); |
24315 | add_stmt (expr); |
24316 | OMP_CLAUSE_OPERAND (c, i) = expr; |
24317 | tree tc = build_omp_clause (OMP_CLAUSE_LOCATION (c), |
24318 | OMP_CLAUSE_FIRSTPRIVATE); |
24319 | OMP_CLAUSE_DECL (tc) = tmp; |
24320 | OMP_CLAUSE_CHAIN (tc) |
24321 | = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; |
24322 | cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = tc; |
24323 | } |
24324 | tree stmt = make_node (OMP_TARGET); |
24325 | TREE_TYPE (stmt) = void_type_node; |
24326 | OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; |
24327 | c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); |
24328 | OMP_TARGET_BODY (stmt) = block; |
24329 | OMP_TARGET_COMBINED (stmt) = 1; |
24330 | SET_EXPR_LOCATION (stmt, loc); |
24331 | add_stmt (stmt); |
24332 | pc = &OMP_TARGET_CLAUSES (stmt); |
24333 | goto check_clauses; |
24334 | } |
24335 | else if (!flag_openmp) /* flag_openmp_simd */ |
24336 | { |
24337 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
24338 | return false; |
24339 | } |
24340 | else if (strcmp (s1: p, s2: "data" ) == 0) |
24341 | { |
24342 | c_parser_consume_token (parser); |
24343 | c_parser_omp_target_data (loc, parser, if_p); |
24344 | return true; |
24345 | } |
24346 | else if (strcmp (s1: p, s2: "enter" ) == 0) |
24347 | { |
24348 | c_parser_consume_token (parser); |
24349 | return c_parser_omp_target_enter_data (loc, parser, context); |
24350 | } |
24351 | else if (strcmp (s1: p, s2: "exit" ) == 0) |
24352 | { |
24353 | c_parser_consume_token (parser); |
24354 | return c_parser_omp_target_exit_data (loc, parser, context); |
24355 | } |
24356 | else if (strcmp (s1: p, s2: "update" ) == 0) |
24357 | { |
24358 | c_parser_consume_token (parser); |
24359 | return c_parser_omp_target_update (loc, parser, context); |
24360 | } |
24361 | } |
24362 | if (!flag_openmp) /* flag_openmp_simd */ |
24363 | { |
24364 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
24365 | return false; |
24366 | } |
24367 | |
24368 | stmt = make_node (OMP_TARGET); |
24369 | TREE_TYPE (stmt) = void_type_node; |
24370 | |
24371 | OMP_TARGET_CLAUSES (stmt) |
24372 | = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, |
24373 | where: "#pragma omp target" , finish_p: false); |
24374 | for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) |
24375 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) |
24376 | { |
24377 | tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); |
24378 | OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); |
24379 | OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); |
24380 | OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); |
24381 | OMP_CLAUSE_CHAIN (c) = nc; |
24382 | } |
24383 | OMP_TARGET_CLAUSES (stmt) |
24384 | = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); |
24385 | c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); |
24386 | |
24387 | pc = &OMP_TARGET_CLAUSES (stmt); |
24388 | keep_next_level (); |
24389 | block = c_begin_compound_stmt (true); |
24390 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
24391 | OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true); |
24392 | |
24393 | SET_EXPR_LOCATION (stmt, loc); |
24394 | add_stmt (stmt); |
24395 | |
24396 | check_clauses: |
24397 | while (*pc) |
24398 | { |
24399 | if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP) |
24400 | switch (OMP_CLAUSE_MAP_KIND (*pc)) |
24401 | { |
24402 | case GOMP_MAP_TO: |
24403 | case GOMP_MAP_ALWAYS_TO: |
24404 | case GOMP_MAP_PRESENT_TO: |
24405 | case GOMP_MAP_ALWAYS_PRESENT_TO: |
24406 | case GOMP_MAP_FROM: |
24407 | case GOMP_MAP_ALWAYS_FROM: |
24408 | case GOMP_MAP_PRESENT_FROM: |
24409 | case GOMP_MAP_ALWAYS_PRESENT_FROM: |
24410 | case GOMP_MAP_TOFROM: |
24411 | case GOMP_MAP_ALWAYS_TOFROM: |
24412 | case GOMP_MAP_PRESENT_TOFROM: |
24413 | case GOMP_MAP_ALWAYS_PRESENT_TOFROM: |
24414 | case GOMP_MAP_ALLOC: |
24415 | case GOMP_MAP_PRESENT_ALLOC: |
24416 | case GOMP_MAP_FIRSTPRIVATE_POINTER: |
24417 | case GOMP_MAP_ALWAYS_POINTER: |
24418 | case GOMP_MAP_POINTER: |
24419 | case GOMP_MAP_ATTACH_DETACH: |
24420 | case GOMP_MAP_ATTACH: |
24421 | break; |
24422 | default: |
24423 | error_at (OMP_CLAUSE_LOCATION (*pc), |
24424 | "%<#pragma omp target%> with map-type other " |
24425 | "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> " |
24426 | "on %<map%> clause" ); |
24427 | *pc = OMP_CLAUSE_CHAIN (*pc); |
24428 | continue; |
24429 | } |
24430 | pc = &OMP_CLAUSE_CHAIN (*pc); |
24431 | } |
24432 | cfun->has_omp_target = true; |
24433 | return true; |
24434 | } |
24435 | |
24436 | /* OpenMP 4.0: |
24437 | # pragma omp declare simd declare-simd-clauses[optseq] new-line |
24438 | |
24439 | OpenMP 5.0: |
24440 | # pragma omp declare variant (identifier) match(context-selector) new-line |
24441 | */ |
24442 | |
24443 | #define OMP_DECLARE_SIMD_CLAUSE_MASK \ |
24444 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \ |
24445 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \ |
24446 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \ |
24447 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \ |
24448 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \ |
24449 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH)) |
24450 | |
24451 | static void |
24452 | c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) |
24453 | { |
24454 | c_token *token = c_parser_peek_token (parser); |
24455 | gcc_assert (token->type == CPP_NAME); |
24456 | tree kind = token->value; |
24457 | gcc_assert (strcmp (IDENTIFIER_POINTER (kind), "simd" ) == 0 |
24458 | || strcmp (IDENTIFIER_POINTER (kind), "variant" ) == 0); |
24459 | |
24460 | auto_vec<c_token> clauses; |
24461 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
24462 | { |
24463 | c_token *token = c_parser_peek_token (parser); |
24464 | if (token->type == CPP_EOF) |
24465 | { |
24466 | c_parser_skip_to_pragma_eol (parser); |
24467 | return; |
24468 | } |
24469 | clauses.safe_push (obj: *token); |
24470 | c_parser_consume_token (parser); |
24471 | } |
24472 | clauses.safe_push (obj: *c_parser_peek_token (parser)); |
24473 | c_parser_skip_to_pragma_eol (parser); |
24474 | |
24475 | while (c_parser_next_token_is (parser, type: CPP_PRAGMA)) |
24476 | { |
24477 | if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_DECLARE |
24478 | || c_parser_peek_2nd_token (parser)->type != CPP_NAME |
24479 | || c_parser_peek_2nd_token (parser)->value != kind) |
24480 | { |
24481 | error ("%<#pragma omp declare %s%> must be followed by " |
24482 | "function declaration or definition or another " |
24483 | "%<#pragma omp declare %s%>" , |
24484 | IDENTIFIER_POINTER (kind), IDENTIFIER_POINTER (kind)); |
24485 | return; |
24486 | } |
24487 | c_parser_consume_pragma (parser); |
24488 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
24489 | { |
24490 | c_token *token = c_parser_peek_token (parser); |
24491 | if (token->type == CPP_EOF) |
24492 | { |
24493 | c_parser_skip_to_pragma_eol (parser); |
24494 | return; |
24495 | } |
24496 | clauses.safe_push (obj: *token); |
24497 | c_parser_consume_token (parser); |
24498 | } |
24499 | clauses.safe_push (obj: *c_parser_peek_token (parser)); |
24500 | c_parser_skip_to_pragma_eol (parser); |
24501 | } |
24502 | |
24503 | /* Make sure nothing tries to read past the end of the tokens. */ |
24504 | c_token eof_token; |
24505 | memset (s: &eof_token, c: 0, n: sizeof (eof_token)); |
24506 | eof_token.type = CPP_EOF; |
24507 | clauses.safe_push (obj: eof_token); |
24508 | clauses.safe_push (obj: eof_token); |
24509 | |
24510 | switch (context) |
24511 | { |
24512 | case pragma_external: |
24513 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24514 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION) |
24515 | { |
24516 | int ext = disable_extension_diagnostics (); |
24517 | do |
24518 | c_parser_consume_token (parser); |
24519 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24520 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION); |
24521 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
24522 | NULL, omp_declare_simd_clauses: &clauses); |
24523 | restore_extension_diagnostics (flags: ext); |
24524 | } |
24525 | else |
24526 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: false, start_attr_ok: true, |
24527 | NULL, omp_declare_simd_clauses: &clauses); |
24528 | break; |
24529 | case pragma_struct: |
24530 | case pragma_param: |
24531 | case pragma_stmt: |
24532 | error ("%<#pragma omp declare %s%> must be followed by " |
24533 | "function declaration or definition" , |
24534 | IDENTIFIER_POINTER (kind)); |
24535 | break; |
24536 | case pragma_compound: |
24537 | bool have_std_attrs; |
24538 | tree std_attrs; |
24539 | have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, n: 1); |
24540 | if (have_std_attrs) |
24541 | std_attrs = c_parser_std_attribute_specifier_sequence (parser); |
24542 | else |
24543 | std_attrs = NULL_TREE; |
24544 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24545 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION) |
24546 | { |
24547 | int ext = disable_extension_diagnostics (); |
24548 | do |
24549 | c_parser_consume_token (parser); |
24550 | while (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24551 | && c_parser_peek_token (parser)->keyword == RID_EXTENSION); |
24552 | if (c_parser_next_tokens_start_declaration (parser) |
24553 | || c_parser_nth_token_starts_std_attributes (parser, n: 1)) |
24554 | { |
24555 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, |
24556 | start_attr_ok: true, NULL, omp_declare_simd_clauses: &clauses, |
24557 | have_attrs: have_std_attrs, attrs: std_attrs); |
24558 | restore_extension_diagnostics (flags: ext); |
24559 | break; |
24560 | } |
24561 | restore_extension_diagnostics (flags: ext); |
24562 | } |
24563 | else if (c_parser_next_tokens_start_declaration (parser)) |
24564 | { |
24565 | c_parser_declaration_or_fndef (parser, fndef_ok: true, static_assert_ok: true, empty_ok: true, nested: true, start_attr_ok: true, |
24566 | NULL, omp_declare_simd_clauses: &clauses, have_attrs: have_std_attrs, |
24567 | attrs: std_attrs); |
24568 | break; |
24569 | } |
24570 | error ("%<#pragma omp declare %s%> must be followed by " |
24571 | "function declaration or definition" , |
24572 | IDENTIFIER_POINTER (kind)); |
24573 | break; |
24574 | default: |
24575 | gcc_unreachable (); |
24576 | } |
24577 | } |
24578 | |
24579 | /* OpenMP 5.0: |
24580 | |
24581 | trait-selector: |
24582 | trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])] |
24583 | |
24584 | trait-score: |
24585 | score(score-expression) |
24586 | |
24587 | Note that this function returns a list of trait selectors for the |
24588 | trait-selector-set SET. */ |
24589 | |
24590 | static tree |
24591 | c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set, |
24592 | tree parms) |
24593 | { |
24594 | tree ret = NULL_TREE; |
24595 | do |
24596 | { |
24597 | tree selector; |
24598 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24599 | || c_parser_next_token_is (parser, type: CPP_NAME)) |
24600 | selector = c_parser_peek_token (parser)->value; |
24601 | else |
24602 | { |
24603 | c_parser_error (parser, gmsgid: "expected trait selector name" ); |
24604 | return error_mark_node; |
24605 | } |
24606 | enum omp_ts_code sel |
24607 | = omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector)); |
24608 | |
24609 | if (sel == OMP_TRAIT_INVALID) |
24610 | { |
24611 | /* Per the spec, "Implementations can ignore specified selectors |
24612 | that are not those described in this section"; however, we |
24613 | must record such selectors because they cause match failures. */ |
24614 | warning_at (c_parser_peek_token (parser)->location, OPT_Wopenmp, |
24615 | "unknown selector %qs for context selector set %qs" , |
24616 | IDENTIFIER_POINTER (selector), omp_tss_map[set]); |
24617 | c_parser_consume_token (parser); |
24618 | ret = make_trait_selector (sel, NULL_TREE, NULL_TREE, ret); |
24619 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
24620 | c_parser_balanced_token_sequence (parser); |
24621 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24622 | { |
24623 | c_parser_consume_token (parser); |
24624 | continue; |
24625 | } |
24626 | else |
24627 | break; |
24628 | } |
24629 | |
24630 | c_parser_consume_token (parser); |
24631 | |
24632 | tree properties = NULL_TREE; |
24633 | tree scoreval = NULL_TREE; |
24634 | enum omp_tp_type property_kind = omp_ts_map[sel].tp_type; |
24635 | bool allow_score = omp_ts_map[sel].allow_score; |
24636 | tree t; |
24637 | |
24638 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
24639 | { |
24640 | if (property_kind == OMP_TRAIT_PROPERTY_NONE) |
24641 | { |
24642 | error_at (c_parser_peek_token (parser)->location, |
24643 | "selector %qs does not accept any properties" , |
24644 | IDENTIFIER_POINTER (selector)); |
24645 | return error_mark_node; |
24646 | } |
24647 | |
24648 | matching_parens parens; |
24649 | parens.require_open (parser); |
24650 | |
24651 | c_token *token = c_parser_peek_token (parser); |
24652 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
24653 | && strcmp (IDENTIFIER_POINTER (token->value), s2: "score" ) == 0 |
24654 | && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) |
24655 | { |
24656 | c_parser_consume_token (parser); |
24657 | |
24658 | matching_parens parens2; |
24659 | parens2.require_open (parser); |
24660 | tree score = c_parser_expr_no_commas (parser, NULL).value; |
24661 | parens2.skip_until_found_close (parser); |
24662 | c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" ); |
24663 | if (!allow_score) |
24664 | error_at (token->location, |
24665 | "%<score%> cannot be specified in traits " |
24666 | "in the %qs trait-selector-set" , |
24667 | omp_tss_map[set]); |
24668 | else if (score != error_mark_node) |
24669 | { |
24670 | mark_exp_read (score); |
24671 | score = c_fully_fold (score, false, NULL); |
24672 | if (!INTEGRAL_TYPE_P (TREE_TYPE (score)) |
24673 | || TREE_CODE (score) != INTEGER_CST) |
24674 | error_at (token->location, "%<score%> argument must " |
24675 | "be constant integer expression" ); |
24676 | else if (tree_int_cst_sgn (score) < 0) |
24677 | error_at (token->location, "%<score%> argument must " |
24678 | "be non-negative" ); |
24679 | else |
24680 | scoreval = score; |
24681 | } |
24682 | token = c_parser_peek_token (parser); |
24683 | } |
24684 | |
24685 | switch (property_kind) |
24686 | { |
24687 | case OMP_TRAIT_PROPERTY_ID: |
24688 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24689 | || c_parser_next_token_is (parser, type: CPP_NAME)) |
24690 | { |
24691 | tree prop = c_parser_peek_token (parser)->value; |
24692 | c_parser_consume_token (parser); |
24693 | properties = make_trait_property (prop, NULL_TREE, |
24694 | properties); |
24695 | } |
24696 | else |
24697 | { |
24698 | c_parser_error (parser, gmsgid: "expected identifier" ); |
24699 | return error_mark_node; |
24700 | } |
24701 | break; |
24702 | case OMP_TRAIT_PROPERTY_NAME_LIST: |
24703 | do |
24704 | { |
24705 | tree prop = OMP_TP_NAMELIST_NODE; |
24706 | tree value = NULL_TREE; |
24707 | if (c_parser_next_token_is (parser, type: CPP_KEYWORD) |
24708 | || c_parser_next_token_is (parser, type: CPP_NAME)) |
24709 | { |
24710 | value = c_parser_peek_token (parser)->value; |
24711 | c_parser_consume_token (parser); |
24712 | } |
24713 | else if (c_parser_next_token_is (parser, type: CPP_STRING)) |
24714 | value = c_parser_string_literal (parser, translate: false, |
24715 | wide_ok: false).value; |
24716 | else |
24717 | { |
24718 | c_parser_error (parser, gmsgid: "expected identifier or " |
24719 | "string literal" ); |
24720 | return error_mark_node; |
24721 | } |
24722 | |
24723 | properties = make_trait_property (prop, value, properties); |
24724 | |
24725 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24726 | c_parser_consume_token (parser); |
24727 | else |
24728 | break; |
24729 | } |
24730 | while (1); |
24731 | break; |
24732 | case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: |
24733 | case OMP_TRAIT_PROPERTY_BOOL_EXPR: |
24734 | t = c_parser_expr_no_commas (parser, NULL).value; |
24735 | if (t != error_mark_node) |
24736 | { |
24737 | mark_exp_read (t); |
24738 | t = c_fully_fold (t, false, NULL); |
24739 | /* FIXME: this is bogus, both device_num and |
24740 | condition selectors allow arbitrary expressions. */ |
24741 | if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) |
24742 | || !tree_fits_shwi_p (t)) |
24743 | error_at (token->location, "property must be " |
24744 | "constant integer expression" ); |
24745 | else |
24746 | properties = make_trait_property (NULL_TREE, t, |
24747 | properties); |
24748 | } |
24749 | else |
24750 | return error_mark_node; |
24751 | break; |
24752 | case OMP_TRAIT_PROPERTY_CLAUSE_LIST: |
24753 | if (sel == OMP_TRAIT_CONSTRUCT_SIMD) |
24754 | { |
24755 | if (parms == NULL_TREE) |
24756 | { |
24757 | error_at (token->location, "properties for %<simd%> " |
24758 | "selector may not be specified in " |
24759 | "%<metadirective%>" ); |
24760 | return error_mark_node; |
24761 | } |
24762 | tree c; |
24763 | c = c_parser_omp_all_clauses (parser, |
24764 | OMP_DECLARE_SIMD_CLAUSE_MASK, |
24765 | where: "simd" , finish_p: true, nested: 2); |
24766 | c = c_omp_declare_simd_clauses_to_numbers (parms |
24767 | == error_mark_node |
24768 | ? NULL_TREE : parms, |
24769 | c); |
24770 | properties = c; |
24771 | } |
24772 | else if (sel == OMP_TRAIT_IMPLEMENTATION_REQUIRES) |
24773 | { |
24774 | /* FIXME: The "requires" selector was added in OpenMP 5.1. |
24775 | Currently only the now-deprecated syntax |
24776 | from OpenMP 5.0 is supported. */ |
24777 | sorry_at (token->location, |
24778 | "%<requires%> selector is not supported yet" ); |
24779 | return error_mark_node; |
24780 | } |
24781 | else |
24782 | gcc_unreachable (); |
24783 | break; |
24784 | default: |
24785 | gcc_unreachable (); |
24786 | } |
24787 | |
24788 | parens.skip_until_found_close (parser); |
24789 | properties = nreverse (properties); |
24790 | } |
24791 | else if (property_kind != OMP_TRAIT_PROPERTY_NONE |
24792 | && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST |
24793 | && property_kind != OMP_TRAIT_PROPERTY_EXTENSION) |
24794 | { |
24795 | c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" ); |
24796 | return error_mark_node; |
24797 | } |
24798 | |
24799 | ret = make_trait_selector (sel, scoreval, properties, ret); |
24800 | |
24801 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24802 | c_parser_consume_token (parser); |
24803 | else |
24804 | break; |
24805 | } |
24806 | while (1); |
24807 | |
24808 | return nreverse (ret); |
24809 | } |
24810 | |
24811 | /* OpenMP 5.0: |
24812 | |
24813 | trait-set-selector[,trait-set-selector[,...]] |
24814 | |
24815 | trait-set-selector: |
24816 | trait-set-selector-name = { trait-selector[, trait-selector[, ...]] } |
24817 | |
24818 | trait-set-selector-name: |
24819 | constructor |
24820 | device |
24821 | implementation |
24822 | user */ |
24823 | |
24824 | static tree |
24825 | c_parser_omp_context_selector_specification (c_parser *parser, tree parms) |
24826 | { |
24827 | tree ret = NULL_TREE; |
24828 | do |
24829 | { |
24830 | const char *setp = "" ; |
24831 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24832 | setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24833 | enum omp_tss_code set = omp_lookup_tss_code (setp); |
24834 | |
24835 | if (set == OMP_TRAIT_SET_INVALID) |
24836 | { |
24837 | c_parser_error (parser, gmsgid: "expected context selector set name" ); |
24838 | return error_mark_node; |
24839 | } |
24840 | |
24841 | c_parser_consume_token (parser); |
24842 | |
24843 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
24844 | return error_mark_node; |
24845 | |
24846 | matching_braces braces; |
24847 | if (!braces.require_open (parser)) |
24848 | return error_mark_node; |
24849 | |
24850 | tree selectors = c_parser_omp_context_selector (parser, set, parms); |
24851 | if (selectors == error_mark_node) |
24852 | ret = error_mark_node; |
24853 | else if (ret != error_mark_node) |
24854 | ret = make_trait_set_selector (set, selectors, ret); |
24855 | |
24856 | braces.skip_until_found_close (parser); |
24857 | |
24858 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
24859 | c_parser_consume_token (parser); |
24860 | else |
24861 | break; |
24862 | } |
24863 | while (1); |
24864 | |
24865 | if (ret == error_mark_node) |
24866 | return ret; |
24867 | return nreverse (ret); |
24868 | } |
24869 | |
24870 | /* Finalize #pragma omp declare variant after FNDECL has been parsed, and put |
24871 | that into "omp declare variant base" attribute. */ |
24872 | |
24873 | static void |
24874 | c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms) |
24875 | { |
24876 | matching_parens parens; |
24877 | if (!parens.require_open (parser)) |
24878 | { |
24879 | fail: |
24880 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
24881 | return; |
24882 | } |
24883 | |
24884 | if (c_parser_next_token_is_not (parser, type: CPP_NAME) |
24885 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
24886 | { |
24887 | c_parser_error (parser, gmsgid: "expected identifier" ); |
24888 | goto fail; |
24889 | } |
24890 | |
24891 | c_token *token = c_parser_peek_token (parser); |
24892 | tree variant = lookup_name (token->value); |
24893 | |
24894 | if (variant == NULL_TREE) |
24895 | { |
24896 | undeclared_variable (token->location, token->value); |
24897 | variant = error_mark_node; |
24898 | } |
24899 | |
24900 | c_parser_consume_token (parser); |
24901 | |
24902 | parens.require_close (parser); |
24903 | |
24904 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
24905 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
24906 | c_parser_consume_token (parser); |
24907 | |
24908 | const char *clause = "" ; |
24909 | location_t match_loc = c_parser_peek_token (parser)->location; |
24910 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
24911 | clause = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
24912 | if (strcmp (s1: clause, s2: "match" )) |
24913 | { |
24914 | c_parser_error (parser, gmsgid: "expected %<match%>" ); |
24915 | goto fail; |
24916 | } |
24917 | |
24918 | c_parser_consume_token (parser); |
24919 | |
24920 | if (!parens.require_open (parser)) |
24921 | goto fail; |
24922 | |
24923 | if (parms == NULL_TREE) |
24924 | parms = error_mark_node; |
24925 | |
24926 | tree ctx = c_parser_omp_context_selector_specification (parser, parms); |
24927 | if (ctx == error_mark_node) |
24928 | goto fail; |
24929 | ctx = omp_check_context_selector (loc: match_loc, ctx); |
24930 | if (ctx != error_mark_node && variant != error_mark_node) |
24931 | { |
24932 | if (TREE_CODE (variant) != FUNCTION_DECL) |
24933 | { |
24934 | error_at (token->location, "variant %qD is not a function" , variant); |
24935 | variant = error_mark_node; |
24936 | } |
24937 | else if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, |
24938 | OMP_TRAIT_CONSTRUCT_SIMD) |
24939 | && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant))) |
24940 | { |
24941 | error_at (token->location, "variant %qD and base %qD have " |
24942 | "incompatible types" , variant, fndecl); |
24943 | variant = error_mark_node; |
24944 | } |
24945 | else if (fndecl_built_in_p (node: variant) |
24946 | && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), |
24947 | s2: "__builtin_" , n: strlen (s: "__builtin_" )) == 0 |
24948 | || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), |
24949 | s2: "__sync_" , n: strlen (s: "__sync_" )) == 0 |
24950 | || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)), |
24951 | s2: "__atomic_" , n: strlen (s: "__atomic_" )) == 0)) |
24952 | { |
24953 | error_at (token->location, "variant %qD is a built-in" , variant); |
24954 | variant = error_mark_node; |
24955 | } |
24956 | if (variant != error_mark_node) |
24957 | { |
24958 | C_DECL_USED (variant) = 1; |
24959 | tree construct |
24960 | = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT); |
24961 | omp_mark_declare_variant (loc: match_loc, variant, construct); |
24962 | if (omp_context_selector_matches (ctx)) |
24963 | { |
24964 | tree attr |
24965 | = tree_cons (get_identifier ("omp declare variant base" ), |
24966 | build_tree_list (variant, ctx), |
24967 | DECL_ATTRIBUTES (fndecl)); |
24968 | DECL_ATTRIBUTES (fndecl) = attr; |
24969 | } |
24970 | } |
24971 | } |
24972 | |
24973 | parens.require_close (parser); |
24974 | c_parser_skip_to_pragma_eol (parser); |
24975 | } |
24976 | |
24977 | /* Finalize #pragma omp declare simd or #pragma omp declare variant |
24978 | clauses after FNDECL has been parsed, and put that into "omp declare simd" |
24979 | or "omp declare variant base" attribute. */ |
24980 | |
24981 | static void |
24982 | c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, |
24983 | vec<c_token> *pclauses) |
24984 | { |
24985 | vec<c_token> &clauses = *pclauses; |
24986 | |
24987 | /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there |
24988 | indicates error has been reported and CPP_PRAGMA that |
24989 | c_finish_omp_declare_simd has already processed the tokens. */ |
24990 | if (clauses.exists () && clauses[0].type == CPP_EOF) |
24991 | return; |
24992 | const char *kind = "simd" ; |
24993 | if (clauses.exists () |
24994 | && (clauses[0].type == CPP_NAME || clauses[0].type == CPP_PRAGMA)) |
24995 | kind = IDENTIFIER_POINTER (clauses[0].value); |
24996 | gcc_assert (strcmp (kind, "simd" ) == 0 || strcmp (kind, "variant" ) == 0); |
24997 | if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL) |
24998 | { |
24999 | error ("%<#pragma omp declare %s%> not immediately followed by " |
25000 | "a function declaration or definition" , kind); |
25001 | clauses[0].type = CPP_EOF; |
25002 | return; |
25003 | } |
25004 | if (clauses.exists () && clauses[0].type != CPP_NAME) |
25005 | { |
25006 | error_at (DECL_SOURCE_LOCATION (fndecl), |
25007 | "%<#pragma omp declare %s%> not immediately followed by " |
25008 | "a single function declaration or definition" , kind); |
25009 | clauses[0].type = CPP_EOF; |
25010 | return; |
25011 | } |
25012 | |
25013 | if (parms == NULL_TREE) |
25014 | parms = DECL_ARGUMENTS (fndecl); |
25015 | |
25016 | unsigned int tokens_avail = parser->tokens_avail; |
25017 | gcc_assert (parser->tokens == &parser->tokens_buf[0]); |
25018 | |
25019 | parser->tokens = clauses.address (); |
25020 | parser->tokens_avail = clauses.length (); |
25021 | |
25022 | /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */ |
25023 | while (parser->tokens_avail > 3) |
25024 | { |
25025 | c_token *token = c_parser_peek_token (parser); |
25026 | gcc_assert (token->type == CPP_NAME); |
25027 | kind = IDENTIFIER_POINTER (token->value); |
25028 | c_parser_consume_token (parser); |
25029 | parser->in_pragma = true; |
25030 | |
25031 | if (strcmp (s1: kind, s2: "simd" ) == 0) |
25032 | { |
25033 | tree c; |
25034 | c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, |
25035 | where: "#pragma omp declare simd" ); |
25036 | c = c_omp_declare_simd_clauses_to_numbers (parms, c); |
25037 | if (c != NULL_TREE) |
25038 | c = tree_cons (NULL_TREE, c, NULL_TREE); |
25039 | c = build_tree_list (get_identifier ("omp declare simd" ), c); |
25040 | TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl); |
25041 | DECL_ATTRIBUTES (fndecl) = c; |
25042 | } |
25043 | else |
25044 | { |
25045 | gcc_assert (strcmp (kind, "variant" ) == 0); |
25046 | c_finish_omp_declare_variant (parser, fndecl, parms); |
25047 | } |
25048 | } |
25049 | |
25050 | parser->tokens = &parser->tokens_buf[0]; |
25051 | parser->tokens_avail = tokens_avail; |
25052 | if (clauses.exists ()) |
25053 | clauses[0].type = CPP_PRAGMA; |
25054 | } |
25055 | |
25056 | /* D should be C_TOKEN_VEC from omp::decl attribute. If it contains |
25057 | a threadprivate, groupprivate, allocate or declare target directive, |
25058 | return true and parse it for DECL. */ |
25059 | |
25060 | bool |
25061 | c_maybe_parse_omp_decl (tree decl, tree d) |
25062 | { |
25063 | gcc_assert (TREE_CODE (d) == C_TOKEN_VEC); |
25064 | vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d); |
25065 | c_token *first = toks->address (); |
25066 | c_token *last = first + toks->length (); |
25067 | const char *directive[3] = {}; |
25068 | for (int j = 0; j < 3; j++) |
25069 | { |
25070 | tree id = NULL_TREE; |
25071 | if (first + j == last) |
25072 | break; |
25073 | if (first[j].type == CPP_NAME) |
25074 | id = first[j].value; |
25075 | else if (first[j].type == CPP_KEYWORD) |
25076 | id = ridpointers[(int) first[j].keyword]; |
25077 | else |
25078 | break; |
25079 | directive[j] = IDENTIFIER_POINTER (id); |
25080 | } |
25081 | const c_omp_directive *dir = NULL; |
25082 | if (directive[0]) |
25083 | dir = c_omp_categorize_directive (directive[0], directive[1], |
25084 | directive[2]); |
25085 | if (dir == NULL) |
25086 | { |
25087 | error_at (first->location, |
25088 | "unknown OpenMP directive name in " |
25089 | "%qs attribute argument" , "omp::decl" ); |
25090 | return false; |
25091 | } |
25092 | if (dir->id != PRAGMA_OMP_THREADPRIVATE |
25093 | /* && dir->id != PRAGMA_OMP_GROUPPRIVATE */ |
25094 | && dir->id != PRAGMA_OMP_ALLOCATE |
25095 | && (dir->id != PRAGMA_OMP_DECLARE |
25096 | || strcmp (s1: directive[1], s2: "target" ) != 0)) |
25097 | return false; |
25098 | |
25099 | if (!flag_openmp && !dir->simd) |
25100 | return true; |
25101 | |
25102 | c_parser *parser = the_parser; |
25103 | unsigned int tokens_avail = parser->tokens_avail; |
25104 | gcc_assert (parser->tokens == &parser->tokens_buf[0]); |
25105 | toks = NULL; |
25106 | vec_safe_reserve (v&: toks, nelems: last - first + 2, exact: true); |
25107 | c_token tok = {}; |
25108 | tok.type = CPP_PRAGMA; |
25109 | tok.keyword = RID_MAX; |
25110 | tok.pragma_kind = pragma_kind (dir->id); |
25111 | tok.location = first->location; |
25112 | toks->quick_push (obj: tok); |
25113 | while (++first < last) |
25114 | toks->quick_push (obj: *first); |
25115 | tok = {}; |
25116 | tok.type = CPP_PRAGMA_EOL; |
25117 | tok.keyword = RID_MAX; |
25118 | tok.location = last[-1].location; |
25119 | toks->quick_push (obj: tok); |
25120 | tok = {}; |
25121 | tok.type = CPP_EOF; |
25122 | tok.keyword = RID_MAX; |
25123 | tok.location = last[-1].location; |
25124 | tok.flags = tokens_avail; |
25125 | toks->quick_push (obj: tok); |
25126 | parser->in_omp_decl_attribute = decl; |
25127 | parser->tokens = toks->address (); |
25128 | parser->tokens_avail = toks->length (); |
25129 | parser->in_omp_attribute_pragma = toks; |
25130 | c_parser_pragma (parser, context: pragma_external, NULL); |
25131 | parser->in_omp_decl_attribute = NULL_TREE; |
25132 | return true; |
25133 | } |
25134 | |
25135 | /* OpenMP 4.0: |
25136 | # pragma omp declare target new-line |
25137 | declarations and definitions |
25138 | # pragma omp end declare target new-line |
25139 | |
25140 | OpenMP 4.5: |
25141 | # pragma omp declare target ( extended-list ) new-line |
25142 | |
25143 | # pragma omp declare target declare-target-clauses[seq] new-line */ |
25144 | |
25145 | #define OMP_DECLARE_TARGET_CLAUSE_MASK \ |
25146 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ |
25147 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ENTER) \ |
25148 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \ |
25149 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE) \ |
25150 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INDIRECT)) |
25151 | |
25152 | static void |
25153 | c_parser_omp_declare_target (c_parser *parser) |
25154 | { |
25155 | tree clauses = NULL_TREE; |
25156 | int device_type = 0; |
25157 | bool indirect = false; |
25158 | bool only_device_type_or_indirect = true; |
25159 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
25160 | || (c_parser_next_token_is (parser, type: CPP_COMMA) |
25161 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME)) |
25162 | clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, |
25163 | where: "#pragma omp declare target" ); |
25164 | else if (parser->in_omp_decl_attribute |
25165 | || c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
25166 | { |
25167 | clauses = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ENTER, |
25168 | list: clauses); |
25169 | clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); |
25170 | c_parser_skip_to_pragma_eol (parser); |
25171 | } |
25172 | else |
25173 | { |
25174 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
25175 | c_parser_skip_to_pragma_eol (parser); |
25176 | c_omp_declare_target_attr attr = { .attr_syntax: attr_syntax, .device_type: -1, .indirect: 0 }; |
25177 | vec_safe_push (v&: current_omp_declare_target_attribute, obj: attr); |
25178 | return; |
25179 | } |
25180 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
25181 | { |
25182 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) |
25183 | device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c); |
25184 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_INDIRECT) |
25185 | indirect |= !integer_zerop (OMP_CLAUSE_INDIRECT_EXPR (c)); |
25186 | } |
25187 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
25188 | { |
25189 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE |
25190 | || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_INDIRECT) |
25191 | continue; |
25192 | tree t = OMP_CLAUSE_DECL (c), id; |
25193 | tree at1 = lookup_attribute (attr_name: "omp declare target" , DECL_ATTRIBUTES (t)); |
25194 | tree at2 = lookup_attribute (attr_name: "omp declare target link" , |
25195 | DECL_ATTRIBUTES (t)); |
25196 | only_device_type_or_indirect = false; |
25197 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) |
25198 | { |
25199 | id = get_identifier ("omp declare target link" ); |
25200 | std::swap (a&: at1, b&: at2); |
25201 | } |
25202 | else |
25203 | id = get_identifier ("omp declare target" ); |
25204 | if (at2) |
25205 | { |
25206 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) |
25207 | error_at (OMP_CLAUSE_LOCATION (c), |
25208 | "%qD specified both in declare target %<link%> and %qs" |
25209 | " clauses" , t, OMP_CLAUSE_ENTER_TO (c) ? "to" : "enter" ); |
25210 | else |
25211 | error_at (OMP_CLAUSE_LOCATION (c), |
25212 | "%qD specified both in declare target %<link%> and " |
25213 | "%<to%> or %<enter%> clauses" , t); |
25214 | continue; |
25215 | } |
25216 | if (!at1) |
25217 | { |
25218 | DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
25219 | if (TREE_CODE (t) != FUNCTION_DECL && !is_global_var (t)) |
25220 | continue; |
25221 | |
25222 | symtab_node *node = symtab_node::get (decl: t); |
25223 | if (node != NULL) |
25224 | { |
25225 | node->offloadable = 1; |
25226 | if (ENABLE_OFFLOADING) |
25227 | { |
25228 | g->have_offload = true; |
25229 | if (is_a <varpool_node *> (p: node)) |
25230 | vec_safe_push (v&: offload_vars, obj: t); |
25231 | } |
25232 | } |
25233 | } |
25234 | if (TREE_CODE (t) != FUNCTION_DECL) |
25235 | continue; |
25236 | if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0) |
25237 | { |
25238 | tree at3 = lookup_attribute (attr_name: "omp declare target host" , |
25239 | DECL_ATTRIBUTES (t)); |
25240 | if (at3 == NULL_TREE) |
25241 | { |
25242 | id = get_identifier ("omp declare target host" ); |
25243 | DECL_ATTRIBUTES (t) |
25244 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
25245 | } |
25246 | } |
25247 | if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0) |
25248 | { |
25249 | tree at3 = lookup_attribute (attr_name: "omp declare target nohost" , |
25250 | DECL_ATTRIBUTES (t)); |
25251 | if (at3 == NULL_TREE) |
25252 | { |
25253 | id = get_identifier ("omp declare target nohost" ); |
25254 | DECL_ATTRIBUTES (t) |
25255 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
25256 | } |
25257 | } |
25258 | if (indirect) |
25259 | { |
25260 | tree at4 = lookup_attribute (attr_name: "omp declare target indirect" , |
25261 | DECL_ATTRIBUTES (t)); |
25262 | if (at4 == NULL_TREE) |
25263 | { |
25264 | id = get_identifier ("omp declare target indirect" ); |
25265 | DECL_ATTRIBUTES (t) |
25266 | = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); |
25267 | } |
25268 | } |
25269 | } |
25270 | if ((device_type || indirect) && only_device_type_or_indirect) |
25271 | error_at (OMP_CLAUSE_LOCATION (clauses), |
25272 | "directive with only %<device_type%> or %<indirect%> clauses" ); |
25273 | if (indirect && device_type && device_type != OMP_CLAUSE_DEVICE_TYPE_ANY) |
25274 | error_at (OMP_CLAUSE_LOCATION (clauses), |
25275 | "%<device_type%> clause must specify 'any' when used with " |
25276 | "an %<indirect%> clause" ); |
25277 | } |
25278 | |
25279 | /* OpenMP 5.1 |
25280 | #pragma omp begin assumes clauses[optseq] new-line |
25281 | |
25282 | #pragma omp begin declare target clauses[optseq] new-line */ |
25283 | |
25284 | #define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK \ |
25285 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE) \ |
25286 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INDIRECT)) |
25287 | |
25288 | static void |
25289 | c_parser_omp_begin (c_parser *parser) |
25290 | { |
25291 | const char *p = "" ; |
25292 | c_parser_consume_pragma (parser); |
25293 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25294 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25295 | if (strcmp (s1: p, s2: "declare" ) == 0) |
25296 | { |
25297 | c_parser_consume_token (parser); |
25298 | p = "" ; |
25299 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25300 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25301 | if (strcmp (s1: p, s2: "target" ) == 0) |
25302 | { |
25303 | c_parser_consume_token (parser); |
25304 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
25305 | tree clauses |
25306 | = c_parser_omp_all_clauses (parser, |
25307 | OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK, |
25308 | where: "#pragma omp begin declare target" ); |
25309 | int device_type = 0; |
25310 | int indirect = 0; |
25311 | for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) |
25312 | { |
25313 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE) |
25314 | device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c); |
25315 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_INDIRECT) |
25316 | indirect |= !integer_zerop (OMP_CLAUSE_INDIRECT_EXPR (c)); |
25317 | } |
25318 | c_omp_declare_target_attr attr = { .attr_syntax: attr_syntax, .device_type: device_type, |
25319 | .indirect: indirect }; |
25320 | vec_safe_push (v&: current_omp_declare_target_attribute, obj: attr); |
25321 | } |
25322 | else |
25323 | { |
25324 | c_parser_error (parser, gmsgid: "expected %<target%>" ); |
25325 | c_parser_skip_to_pragma_eol (parser); |
25326 | } |
25327 | } |
25328 | else if (strcmp (s1: p, s2: "assumes" ) == 0) |
25329 | { |
25330 | c_parser_consume_token (parser); |
25331 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
25332 | c_parser_omp_assumption_clauses (parser, false); |
25333 | struct c_omp_begin_assumes_data a = { .attr_syntax: attr_syntax }; |
25334 | vec_safe_push (v&: current_omp_begin_assumes, obj: a); |
25335 | } |
25336 | else |
25337 | { |
25338 | c_parser_error (parser, gmsgid: "expected %<declare target%> or %<assumes%>" ); |
25339 | c_parser_skip_to_pragma_eol (parser); |
25340 | } |
25341 | } |
25342 | |
25343 | /* OpenMP 4.0 |
25344 | #pragma omp end declare target |
25345 | |
25346 | OpenMP 5.1 |
25347 | #pragma omp end assumes */ |
25348 | |
25349 | static void |
25350 | c_parser_omp_end (c_parser *parser) |
25351 | { |
25352 | location_t loc = c_parser_peek_token (parser)->location; |
25353 | const char *p = "" ; |
25354 | c_parser_consume_pragma (parser); |
25355 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25356 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25357 | if (strcmp (s1: p, s2: "declare" ) == 0) |
25358 | { |
25359 | c_parser_consume_token (parser); |
25360 | if (c_parser_next_token_is (parser, type: CPP_NAME) |
25361 | && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), |
25362 | s2: "target" ) == 0) |
25363 | c_parser_consume_token (parser); |
25364 | else |
25365 | { |
25366 | c_parser_error (parser, gmsgid: "expected %<target%>" ); |
25367 | c_parser_skip_to_pragma_eol (parser); |
25368 | return; |
25369 | } |
25370 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
25371 | c_parser_skip_to_pragma_eol (parser); |
25372 | if (!vec_safe_length (v: current_omp_declare_target_attribute)) |
25373 | error_at (loc, "%<#pragma omp end declare target%> without " |
25374 | "corresponding %<#pragma omp declare target%> or " |
25375 | "%<#pragma omp begin declare target%>" ); |
25376 | else |
25377 | { |
25378 | c_omp_declare_target_attr |
25379 | a = current_omp_declare_target_attribute->pop (); |
25380 | if (a.attr_syntax != attr_syntax) |
25381 | { |
25382 | if (a.attr_syntax) |
25383 | error_at (loc, |
25384 | "%qs in attribute syntax terminated " |
25385 | "with %qs in pragma syntax" , |
25386 | a.device_type >= 0 ? "begin declare target" |
25387 | : "declare target" , |
25388 | "end declare target" ); |
25389 | else |
25390 | error_at (loc, |
25391 | "%qs in pragma syntax terminated " |
25392 | "with %qs in attribute syntax" , |
25393 | a.device_type >= 0 ? "begin declare target" |
25394 | : "declare target" , |
25395 | "end declare target" ); |
25396 | } |
25397 | } |
25398 | } |
25399 | else if (strcmp (s1: p, s2: "assumes" ) == 0) |
25400 | { |
25401 | c_parser_consume_token (parser); |
25402 | bool attr_syntax = parser->in_omp_attribute_pragma != NULL; |
25403 | c_parser_skip_to_pragma_eol (parser); |
25404 | if (!vec_safe_length (v: current_omp_begin_assumes)) |
25405 | error_at (loc, "%qs without corresponding %qs" , |
25406 | "#pragma omp end assumes" , "#pragma omp begin assumes" ); |
25407 | else |
25408 | { |
25409 | c_omp_begin_assumes_data |
25410 | a = current_omp_begin_assumes->pop (); |
25411 | if (a.attr_syntax != attr_syntax) |
25412 | { |
25413 | if (a.attr_syntax) |
25414 | error_at (loc, |
25415 | "%qs in attribute syntax terminated " |
25416 | "with %qs in pragma syntax" , |
25417 | "begin assumes" , "end assumes" ); |
25418 | else |
25419 | error_at (loc, |
25420 | "%qs in pragma syntax terminated " |
25421 | "with %qs in attribute syntax" , |
25422 | "begin assumes" , "end assumes" ); |
25423 | } |
25424 | } |
25425 | } |
25426 | else |
25427 | { |
25428 | c_parser_error (parser, gmsgid: "expected %<declare%> or %<assumes%>" ); |
25429 | c_parser_skip_to_pragma_eol (parser); |
25430 | } |
25431 | } |
25432 | |
25433 | /* OpenMP 4.0 |
25434 | #pragma omp declare reduction (reduction-id : typename-list : expression) \ |
25435 | initializer-clause[opt] new-line |
25436 | |
25437 | initializer-clause: |
25438 | initializer (omp_priv = initializer) |
25439 | initializer (function-name (argument-list)) */ |
25440 | |
25441 | static void |
25442 | c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) |
25443 | { |
25444 | unsigned int tokens_avail = 0, i; |
25445 | c_token *saved_tokens = NULL; |
25446 | vec<tree> types = vNULL; |
25447 | vec<c_token> clauses = vNULL; |
25448 | enum tree_code reduc_code = ERROR_MARK; |
25449 | tree reduc_id = NULL_TREE; |
25450 | tree type; |
25451 | location_t rloc = c_parser_peek_token (parser)->location; |
25452 | |
25453 | if (context == pragma_struct || context == pragma_param) |
25454 | { |
25455 | error ("%<#pragma omp declare reduction%> not at file or block scope" ); |
25456 | goto fail; |
25457 | } |
25458 | |
25459 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
25460 | goto fail; |
25461 | |
25462 | switch (c_parser_peek_token (parser)->type) |
25463 | { |
25464 | case CPP_PLUS: |
25465 | reduc_code = PLUS_EXPR; |
25466 | break; |
25467 | case CPP_MULT: |
25468 | reduc_code = MULT_EXPR; |
25469 | break; |
25470 | case CPP_MINUS: |
25471 | reduc_code = MINUS_EXPR; |
25472 | break; |
25473 | case CPP_AND: |
25474 | reduc_code = BIT_AND_EXPR; |
25475 | break; |
25476 | case CPP_XOR: |
25477 | reduc_code = BIT_XOR_EXPR; |
25478 | break; |
25479 | case CPP_OR: |
25480 | reduc_code = BIT_IOR_EXPR; |
25481 | break; |
25482 | case CPP_AND_AND: |
25483 | reduc_code = TRUTH_ANDIF_EXPR; |
25484 | break; |
25485 | case CPP_OR_OR: |
25486 | reduc_code = TRUTH_ORIF_EXPR; |
25487 | break; |
25488 | case CPP_NAME: |
25489 | const char *p; |
25490 | p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25491 | if (strcmp (s1: p, s2: "min" ) == 0) |
25492 | { |
25493 | reduc_code = MIN_EXPR; |
25494 | break; |
25495 | } |
25496 | if (strcmp (s1: p, s2: "max" ) == 0) |
25497 | { |
25498 | reduc_code = MAX_EXPR; |
25499 | break; |
25500 | } |
25501 | reduc_id = c_parser_peek_token (parser)->value; |
25502 | break; |
25503 | default: |
25504 | c_parser_error (parser, |
25505 | gmsgid: "expected %<+%>, %<*%>, %<-%>, %<&%>, " |
25506 | "%<^%>, %<|%>, %<&&%>, %<||%> or identifier" ); |
25507 | goto fail; |
25508 | } |
25509 | |
25510 | tree orig_reduc_id, reduc_decl; |
25511 | orig_reduc_id = reduc_id; |
25512 | reduc_id = c_omp_reduction_id (reduc_code, reduc_id); |
25513 | reduc_decl = c_omp_reduction_decl (reduc_id); |
25514 | c_parser_consume_token (parser); |
25515 | |
25516 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" )) |
25517 | goto fail; |
25518 | |
25519 | while (true) |
25520 | { |
25521 | location_t loc = c_parser_peek_token (parser)->location; |
25522 | struct c_type_name *ctype = c_parser_type_name (parser); |
25523 | if (ctype != NULL) |
25524 | { |
25525 | type = groktypename (ctype, NULL, NULL); |
25526 | if (type == error_mark_node) |
25527 | ; |
25528 | else if ((INTEGRAL_TYPE_P (type) |
25529 | || SCALAR_FLOAT_TYPE_P (type) |
25530 | || TREE_CODE (type) == COMPLEX_TYPE) |
25531 | && orig_reduc_id == NULL_TREE) |
25532 | error_at (loc, "predeclared arithmetic type in " |
25533 | "%<#pragma omp declare reduction%>" ); |
25534 | else if (TREE_CODE (type) == FUNCTION_TYPE |
25535 | || TREE_CODE (type) == ARRAY_TYPE) |
25536 | error_at (loc, "function or array type in " |
25537 | "%<#pragma omp declare reduction%>" ); |
25538 | else if (TYPE_ATOMIC (type)) |
25539 | error_at (loc, "%<_Atomic%> qualified type in " |
25540 | "%<#pragma omp declare reduction%>" ); |
25541 | else if (TYPE_QUALS_NO_ADDR_SPACE (type)) |
25542 | error_at (loc, "const, volatile or restrict qualified type in " |
25543 | "%<#pragma omp declare reduction%>" ); |
25544 | else |
25545 | { |
25546 | tree t; |
25547 | for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t)) |
25548 | if (comptypes (TREE_PURPOSE (t), type)) |
25549 | { |
25550 | error_at (loc, "redeclaration of %qs " |
25551 | "%<#pragma omp declare reduction%> for " |
25552 | "type %qT" , |
25553 | IDENTIFIER_POINTER (reduc_id) |
25554 | + sizeof ("omp declare reduction " ) - 1, |
25555 | type); |
25556 | location_t ploc |
25557 | = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t), |
25558 | 0)); |
25559 | error_at (ploc, "previous %<#pragma omp declare " |
25560 | "reduction%>" ); |
25561 | break; |
25562 | } |
25563 | if (t == NULL_TREE) |
25564 | types.safe_push (obj: type); |
25565 | } |
25566 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
25567 | c_parser_consume_token (parser); |
25568 | else |
25569 | break; |
25570 | } |
25571 | else |
25572 | break; |
25573 | } |
25574 | |
25575 | if (!c_parser_require (parser, type: CPP_COLON, msgid: "expected %<:%>" ) |
25576 | || types.is_empty ()) |
25577 | { |
25578 | fail: |
25579 | clauses.release (); |
25580 | types.release (); |
25581 | while (true) |
25582 | { |
25583 | c_token *token = c_parser_peek_token (parser); |
25584 | if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL) |
25585 | break; |
25586 | c_parser_consume_token (parser); |
25587 | } |
25588 | c_parser_skip_to_pragma_eol (parser); |
25589 | return; |
25590 | } |
25591 | |
25592 | if (types.length () > 1) |
25593 | { |
25594 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
25595 | { |
25596 | c_token *token = c_parser_peek_token (parser); |
25597 | if (token->type == CPP_EOF) |
25598 | goto fail; |
25599 | clauses.safe_push (obj: *token); |
25600 | c_parser_consume_token (parser); |
25601 | } |
25602 | clauses.safe_push (obj: *c_parser_peek_token (parser)); |
25603 | c_parser_skip_to_pragma_eol (parser); |
25604 | |
25605 | /* Make sure nothing tries to read past the end of the tokens. */ |
25606 | c_token eof_token; |
25607 | memset (s: &eof_token, c: 0, n: sizeof (eof_token)); |
25608 | eof_token.type = CPP_EOF; |
25609 | clauses.safe_push (obj: eof_token); |
25610 | clauses.safe_push (obj: eof_token); |
25611 | } |
25612 | |
25613 | int errs = errorcount; |
25614 | FOR_EACH_VEC_ELT (types, i, type) |
25615 | { |
25616 | saved_tokens = parser->tokens; |
25617 | tokens_avail = parser->tokens_avail; |
25618 | if (!clauses.is_empty ()) |
25619 | { |
25620 | parser->tokens = clauses.address (); |
25621 | parser->tokens_avail = clauses.length (); |
25622 | parser->in_pragma = true; |
25623 | } |
25624 | |
25625 | bool nested = current_function_decl != NULL_TREE; |
25626 | if (nested) |
25627 | c_push_function_context (); |
25628 | tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, |
25629 | reduc_id, default_function_type); |
25630 | current_function_decl = fndecl; |
25631 | allocate_struct_function (fndecl, true); |
25632 | push_scope (); |
25633 | tree stmt = push_stmt_list (); |
25634 | /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't |
25635 | warn about these. */ |
25636 | tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25637 | get_identifier ("omp_out" ), type); |
25638 | DECL_ARTIFICIAL (omp_out) = 1; |
25639 | DECL_CONTEXT (omp_out) = fndecl; |
25640 | pushdecl (omp_out); |
25641 | tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25642 | get_identifier ("omp_in" ), type); |
25643 | DECL_ARTIFICIAL (omp_in) = 1; |
25644 | DECL_CONTEXT (omp_in) = fndecl; |
25645 | pushdecl (omp_in); |
25646 | struct c_expr combiner = c_parser_expression (parser); |
25647 | struct c_expr initializer; |
25648 | tree omp_priv = NULL_TREE, omp_orig = NULL_TREE; |
25649 | bool bad = false; |
25650 | initializer.set_error (); |
25651 | if (!c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
25652 | bad = true; |
25653 | else if (c_parser_next_token_is (parser, type: CPP_COMMA) |
25654 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
25655 | c_parser_consume_token (parser); |
25656 | if (!bad |
25657 | && (c_parser_next_token_is (parser, type: CPP_NAME) |
25658 | && strcmp (IDENTIFIER_POINTER |
25659 | (c_parser_peek_token (parser)->value), |
25660 | s2: "initializer" ) == 0)) |
25661 | { |
25662 | c_parser_consume_token (parser); |
25663 | pop_scope (); |
25664 | push_scope (); |
25665 | omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25666 | get_identifier ("omp_priv" ), type); |
25667 | DECL_ARTIFICIAL (omp_priv) = 1; |
25668 | DECL_INITIAL (omp_priv) = error_mark_node; |
25669 | DECL_CONTEXT (omp_priv) = fndecl; |
25670 | pushdecl (omp_priv); |
25671 | omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL, |
25672 | get_identifier ("omp_orig" ), type); |
25673 | DECL_ARTIFICIAL (omp_orig) = 1; |
25674 | DECL_CONTEXT (omp_orig) = fndecl; |
25675 | pushdecl (omp_orig); |
25676 | if (!c_parser_require (parser, type: CPP_OPEN_PAREN, msgid: "expected %<(%>" )) |
25677 | bad = true; |
25678 | else if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
25679 | { |
25680 | c_parser_error (parser, gmsgid: "expected %<omp_priv%> or " |
25681 | "function-name" ); |
25682 | bad = true; |
25683 | } |
25684 | else if (strcmp (IDENTIFIER_POINTER |
25685 | (c_parser_peek_token (parser)->value), |
25686 | s2: "omp_priv" ) != 0) |
25687 | { |
25688 | if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN |
25689 | || c_parser_peek_token (parser)->id_kind != C_ID_ID) |
25690 | { |
25691 | c_parser_error (parser, gmsgid: "expected function-name %<(%>" ); |
25692 | bad = true; |
25693 | } |
25694 | else |
25695 | initializer = c_parser_postfix_expression (parser); |
25696 | if (initializer.value |
25697 | && TREE_CODE (initializer.value) == CALL_EXPR) |
25698 | { |
25699 | int j; |
25700 | tree c = initializer.value; |
25701 | for (j = 0; j < call_expr_nargs (c); j++) |
25702 | { |
25703 | tree a = CALL_EXPR_ARG (c, j); |
25704 | STRIP_NOPS (a); |
25705 | if (TREE_CODE (a) == ADDR_EXPR |
25706 | && TREE_OPERAND (a, 0) == omp_priv) |
25707 | break; |
25708 | } |
25709 | if (j == call_expr_nargs (c)) |
25710 | error ("one of the initializer call arguments should be " |
25711 | "%<&omp_priv%>" ); |
25712 | } |
25713 | } |
25714 | else |
25715 | { |
25716 | c_parser_consume_token (parser); |
25717 | if (!c_parser_require (parser, type: CPP_EQ, msgid: "expected %<=%>" )) |
25718 | bad = true; |
25719 | else |
25720 | { |
25721 | tree st = push_stmt_list (); |
25722 | location_t loc = c_parser_peek_token (parser)->location; |
25723 | rich_location richloc (line_table, loc); |
25724 | start_init (omp_priv, NULL_TREE, false, false, &richloc); |
25725 | struct c_expr init = c_parser_initializer (parser, decl: omp_priv); |
25726 | finish_init (); |
25727 | finish_decl (omp_priv, loc, init.value, |
25728 | init.original_type, NULL_TREE); |
25729 | pop_stmt_list (st); |
25730 | } |
25731 | } |
25732 | if (!bad |
25733 | && !c_parser_require (parser, type: CPP_CLOSE_PAREN, msgid: "expected %<)%>" )) |
25734 | bad = true; |
25735 | } |
25736 | |
25737 | if (!bad) |
25738 | { |
25739 | c_parser_skip_to_pragma_eol (parser); |
25740 | |
25741 | tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3), |
25742 | DECL_INITIAL (reduc_decl)); |
25743 | DECL_INITIAL (reduc_decl) = t; |
25744 | DECL_SOURCE_LOCATION (omp_out) = rloc; |
25745 | TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out; |
25746 | TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in; |
25747 | TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value; |
25748 | walk_tree (&combiner.value, c_check_omp_declare_reduction_r, |
25749 | &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL); |
25750 | if (omp_priv) |
25751 | { |
25752 | DECL_SOURCE_LOCATION (omp_priv) = rloc; |
25753 | TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv; |
25754 | TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig; |
25755 | TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value; |
25756 | walk_tree (&initializer.value, c_check_omp_declare_reduction_r, |
25757 | &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); |
25758 | walk_tree (&DECL_INITIAL (omp_priv), |
25759 | c_check_omp_declare_reduction_r, |
25760 | &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL); |
25761 | } |
25762 | } |
25763 | |
25764 | pop_stmt_list (stmt); |
25765 | pop_scope (); |
25766 | if (cfun->language != NULL) |
25767 | { |
25768 | ggc_free (cfun->language); |
25769 | cfun->language = NULL; |
25770 | } |
25771 | set_cfun (NULL); |
25772 | current_function_decl = NULL_TREE; |
25773 | if (nested) |
25774 | c_pop_function_context (); |
25775 | |
25776 | if (!clauses.is_empty ()) |
25777 | { |
25778 | parser->tokens = saved_tokens; |
25779 | parser->tokens_avail = tokens_avail; |
25780 | } |
25781 | if (bad) |
25782 | goto fail; |
25783 | if (errs != errorcount) |
25784 | break; |
25785 | } |
25786 | |
25787 | clauses.release (); |
25788 | types.release (); |
25789 | } |
25790 | |
25791 | |
25792 | /* OpenMP 4.0 |
25793 | #pragma omp declare simd declare-simd-clauses[optseq] new-line |
25794 | #pragma omp declare reduction (reduction-id : typename-list : expression) \ |
25795 | initializer-clause[opt] new-line |
25796 | #pragma omp declare target new-line |
25797 | |
25798 | OpenMP 5.0 |
25799 | #pragma omp declare variant (identifier) match (context-selector) */ |
25800 | |
25801 | static bool |
25802 | c_parser_omp_declare (c_parser *parser, enum pragma_context context) |
25803 | { |
25804 | c_parser_consume_pragma (parser); |
25805 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25806 | { |
25807 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25808 | if (strcmp (s1: p, s2: "simd" ) == 0) |
25809 | { |
25810 | /* c_parser_consume_token (parser); done in |
25811 | c_parser_omp_declare_simd. */ |
25812 | c_parser_omp_declare_simd (parser, context); |
25813 | return true; |
25814 | } |
25815 | if (strcmp (s1: p, s2: "reduction" ) == 0) |
25816 | { |
25817 | c_parser_consume_token (parser); |
25818 | c_parser_omp_declare_reduction (parser, context); |
25819 | return false; |
25820 | } |
25821 | if (!flag_openmp) /* flag_openmp_simd */ |
25822 | { |
25823 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25824 | return false; |
25825 | } |
25826 | if (strcmp (s1: p, s2: "target" ) == 0) |
25827 | { |
25828 | c_parser_consume_token (parser); |
25829 | c_parser_omp_declare_target (parser); |
25830 | return false; |
25831 | } |
25832 | if (strcmp (s1: p, s2: "variant" ) == 0) |
25833 | { |
25834 | /* c_parser_consume_token (parser); done in |
25835 | c_parser_omp_declare_simd. */ |
25836 | c_parser_omp_declare_simd (parser, context); |
25837 | return true; |
25838 | } |
25839 | } |
25840 | |
25841 | c_parser_error (parser, gmsgid: "expected %<simd%>, %<reduction%>, " |
25842 | "%<target%> or %<variant%>" ); |
25843 | c_parser_skip_to_pragma_eol (parser); |
25844 | return false; |
25845 | } |
25846 | |
25847 | /* OpenMP 5.0 |
25848 | #pragma omp requires clauses[optseq] new-line */ |
25849 | |
25850 | static void |
25851 | c_parser_omp_requires (c_parser *parser) |
25852 | { |
25853 | enum omp_requires new_req = (enum omp_requires) 0; |
25854 | |
25855 | c_parser_consume_pragma (parser); |
25856 | |
25857 | location_t loc = c_parser_peek_token (parser)->location; |
25858 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
25859 | { |
25860 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
25861 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
25862 | c_parser_consume_token (parser); |
25863 | |
25864 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25865 | { |
25866 | const char *p |
25867 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
25868 | location_t cloc = c_parser_peek_token (parser)->location; |
25869 | enum omp_requires this_req = (enum omp_requires) 0; |
25870 | |
25871 | if (!strcmp (s1: p, s2: "unified_address" )) |
25872 | this_req = OMP_REQUIRES_UNIFIED_ADDRESS; |
25873 | else if (!strcmp (s1: p, s2: "unified_shared_memory" )) |
25874 | this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY; |
25875 | else if (!strcmp (s1: p, s2: "dynamic_allocators" )) |
25876 | this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS; |
25877 | else if (!strcmp (s1: p, s2: "reverse_offload" )) |
25878 | this_req = OMP_REQUIRES_REVERSE_OFFLOAD; |
25879 | else if (!strcmp (s1: p, s2: "atomic_default_mem_order" )) |
25880 | { |
25881 | c_parser_consume_token (parser); |
25882 | |
25883 | matching_parens parens; |
25884 | if (parens.require_open (parser)) |
25885 | { |
25886 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
25887 | { |
25888 | tree v = c_parser_peek_token (parser)->value; |
25889 | p = IDENTIFIER_POINTER (v); |
25890 | |
25891 | if (!strcmp (s1: p, s2: "seq_cst" )) |
25892 | this_req |
25893 | = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST; |
25894 | else if (!strcmp (s1: p, s2: "relaxed" )) |
25895 | this_req |
25896 | = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED; |
25897 | else if (!strcmp (s1: p, s2: "release" )) |
25898 | this_req |
25899 | = (enum omp_requires) OMP_MEMORY_ORDER_RELEASE; |
25900 | else if (!strcmp (s1: p, s2: "acq_rel" )) |
25901 | this_req |
25902 | = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL; |
25903 | else if (!strcmp (s1: p, s2: "acquire" )) |
25904 | this_req |
25905 | = (enum omp_requires) OMP_MEMORY_ORDER_ACQUIRE; |
25906 | } |
25907 | if (this_req == 0) |
25908 | { |
25909 | error_at (c_parser_peek_token (parser)->location, |
25910 | "expected %<acq_rel%>, %<acquire%>, " |
25911 | "%<relaxed%>, %<release%> or %<seq_cst%>" ); |
25912 | switch (c_parser_peek_token (parser)->type) |
25913 | { |
25914 | case CPP_EOF: |
25915 | case CPP_PRAGMA_EOL: |
25916 | case CPP_CLOSE_PAREN: |
25917 | break; |
25918 | default: |
25919 | if (c_parser_peek_2nd_token (parser)->type |
25920 | == CPP_CLOSE_PAREN) |
25921 | c_parser_consume_token (parser); |
25922 | break; |
25923 | } |
25924 | } |
25925 | else |
25926 | c_parser_consume_token (parser); |
25927 | |
25928 | parens.skip_until_found_close (parser); |
25929 | if (this_req == 0) |
25930 | { |
25931 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25932 | return; |
25933 | } |
25934 | } |
25935 | p = NULL; |
25936 | } |
25937 | else |
25938 | { |
25939 | error_at (cloc, "expected %<unified_address%>, " |
25940 | "%<unified_shared_memory%>, " |
25941 | "%<dynamic_allocators%>, " |
25942 | "%<reverse_offload%> " |
25943 | "or %<atomic_default_mem_order%> clause" ); |
25944 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
25945 | return; |
25946 | } |
25947 | if (p) |
25948 | c_parser_consume_token (parser); |
25949 | if (this_req) |
25950 | { |
25951 | if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) |
25952 | { |
25953 | if ((this_req & new_req) != 0) |
25954 | error_at (cloc, "too many %qs clauses" , p); |
25955 | if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS |
25956 | && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0) |
25957 | error_at (cloc, "%qs clause used lexically after first " |
25958 | "target construct or offloading API" , p); |
25959 | } |
25960 | else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) |
25961 | { |
25962 | error_at (cloc, "too many %qs clauses" , |
25963 | "atomic_default_mem_order" ); |
25964 | this_req = (enum omp_requires) 0; |
25965 | } |
25966 | else if ((omp_requires_mask |
25967 | & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0) |
25968 | { |
25969 | error_at (cloc, "more than one %<atomic_default_mem_order%>" |
25970 | " clause in a single compilation unit" ); |
25971 | this_req |
25972 | = (enum omp_requires) |
25973 | (omp_requires_mask |
25974 | & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER); |
25975 | } |
25976 | else if ((omp_requires_mask |
25977 | & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0) |
25978 | error_at (cloc, "%<atomic_default_mem_order%> clause used " |
25979 | "lexically after first %<atomic%> construct " |
25980 | "without memory order clause" ); |
25981 | new_req = (enum omp_requires) (new_req | this_req); |
25982 | omp_requires_mask |
25983 | = (enum omp_requires) (omp_requires_mask | this_req); |
25984 | continue; |
25985 | } |
25986 | } |
25987 | break; |
25988 | } |
25989 | c_parser_skip_to_pragma_eol (parser); |
25990 | |
25991 | if (new_req == 0) |
25992 | error_at (loc, "%<pragma omp requires%> requires at least one clause" ); |
25993 | } |
25994 | |
25995 | /* Helper function for c_parser_omp_taskloop. |
25996 | Disallow zero sized or potentially zero sized task reductions. */ |
25997 | |
25998 | static tree |
25999 | c_finish_taskloop_clauses (tree clauses) |
26000 | { |
26001 | tree *pc = &clauses; |
26002 | for (tree c = clauses; c; c = *pc) |
26003 | { |
26004 | bool remove = false; |
26005 | if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) |
26006 | { |
26007 | tree type = strip_array_types (TREE_TYPE (OMP_CLAUSE_DECL (c))); |
26008 | if (integer_zerop (TYPE_SIZE_UNIT (type))) |
26009 | { |
26010 | error_at (OMP_CLAUSE_LOCATION (c), |
26011 | "zero sized type %qT in %<reduction%> clause" , type); |
26012 | remove = true; |
26013 | } |
26014 | else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) |
26015 | { |
26016 | error_at (OMP_CLAUSE_LOCATION (c), |
26017 | "variable sized type %qT in %<reduction%> clause" , |
26018 | type); |
26019 | remove = true; |
26020 | } |
26021 | } |
26022 | if (remove) |
26023 | *pc = OMP_CLAUSE_CHAIN (c); |
26024 | else |
26025 | pc = &OMP_CLAUSE_CHAIN (c); |
26026 | } |
26027 | return clauses; |
26028 | } |
26029 | |
26030 | /* OpenMP 4.5: |
26031 | #pragma omp taskloop taskloop-clause[optseq] new-line |
26032 | for-loop |
26033 | |
26034 | #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line |
26035 | for-loop */ |
26036 | |
26037 | #define OMP_TASKLOOP_CLAUSE_MASK \ |
26038 | ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \ |
26039 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ |
26040 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ |
26041 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ |
26042 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \ |
26043 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \ |
26044 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \ |
26045 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ |
26046 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \ |
26047 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \ |
26048 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \ |
26049 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \ |
26050 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \ |
26051 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ |
26052 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ |
26053 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ |
26054 | | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)) |
26055 | |
26056 | static tree |
26057 | c_parser_omp_taskloop (location_t loc, c_parser *parser, |
26058 | char *p_name, omp_clause_mask mask, tree *cclauses, |
26059 | bool *if_p) |
26060 | { |
26061 | tree clauses, block, ret; |
26062 | |
26063 | strcat (dest: p_name, src: " taskloop" ); |
26064 | mask |= OMP_TASKLOOP_CLAUSE_MASK; |
26065 | /* #pragma omp parallel master taskloop{, simd} disallow in_reduction |
26066 | clause. */ |
26067 | if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0) |
26068 | mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION); |
26069 | |
26070 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
26071 | { |
26072 | const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
26073 | |
26074 | if (strcmp (s1: p, s2: "simd" ) == 0) |
26075 | { |
26076 | tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; |
26077 | if (cclauses == NULL) |
26078 | cclauses = cclauses_buf; |
26079 | c_parser_consume_token (parser); |
26080 | if (!flag_openmp) /* flag_openmp_simd */ |
26081 | return c_parser_omp_simd (loc, parser, p_name, mask, cclauses, |
26082 | if_p); |
26083 | block = c_begin_compound_stmt (true); |
26084 | ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p); |
26085 | block = c_end_compound_stmt (loc, block, true); |
26086 | if (ret == NULL) |
26087 | return ret; |
26088 | ret = make_node (OMP_TASKLOOP); |
26089 | TREE_TYPE (ret) = void_type_node; |
26090 | OMP_FOR_BODY (ret) = block; |
26091 | OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; |
26092 | OMP_FOR_CLAUSES (ret) |
26093 | = c_finish_taskloop_clauses (OMP_FOR_CLAUSES (ret)); |
26094 | SET_EXPR_LOCATION (ret, loc); |
26095 | add_stmt (ret); |
26096 | return ret; |
26097 | } |
26098 | } |
26099 | if (!flag_openmp) /* flag_openmp_simd */ |
26100 | { |
26101 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
26102 | return NULL_TREE; |
26103 | } |
26104 | |
26105 | clauses = c_parser_omp_all_clauses (parser, mask, where: p_name, finish_p: cclauses == NULL); |
26106 | if (cclauses) |
26107 | { |
26108 | omp_split_clauses (loc, code: OMP_TASKLOOP, mask, clauses, cclauses); |
26109 | clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP]; |
26110 | } |
26111 | |
26112 | clauses = c_finish_taskloop_clauses (clauses); |
26113 | block = c_begin_compound_stmt (true); |
26114 | ret = c_parser_omp_for_loop (loc, parser, code: OMP_TASKLOOP, clauses, NULL, if_p); |
26115 | block = c_end_compound_stmt (loc, block, true); |
26116 | add_stmt (block); |
26117 | |
26118 | return ret; |
26119 | } |
26120 | |
26121 | /* OpenMP 5.1 |
26122 | #pragma omp nothing new-line */ |
26123 | |
26124 | static void |
26125 | c_parser_omp_nothing (c_parser *parser) |
26126 | { |
26127 | c_parser_consume_pragma (parser); |
26128 | c_parser_skip_to_pragma_eol (parser); |
26129 | } |
26130 | |
26131 | /* OpenMP 5.1 |
26132 | #pragma omp error clauses[optseq] new-line */ |
26133 | |
26134 | static bool |
26135 | c_parser_omp_error (c_parser *parser, enum pragma_context context) |
26136 | { |
26137 | int at_compilation = -1; |
26138 | int severity_fatal = -1; |
26139 | tree message = NULL_TREE; |
26140 | bool bad = false; |
26141 | location_t loc = c_parser_peek_token (parser)->location; |
26142 | |
26143 | c_parser_consume_pragma (parser); |
26144 | |
26145 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
26146 | { |
26147 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
26148 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
26149 | c_parser_consume_token (parser); |
26150 | |
26151 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
26152 | break; |
26153 | |
26154 | const char *p |
26155 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
26156 | location_t cloc = c_parser_peek_token (parser)->location; |
26157 | static const char *args[] = { |
26158 | "execution" , "compilation" , "warning" , "fatal" |
26159 | }; |
26160 | int *v = NULL; |
26161 | int idx = 0, n = -1; |
26162 | tree m = NULL_TREE; |
26163 | |
26164 | if (!strcmp (s1: p, s2: "at" )) |
26165 | v = &at_compilation; |
26166 | else if (!strcmp (s1: p, s2: "severity" )) |
26167 | { |
26168 | v = &severity_fatal; |
26169 | idx += 2; |
26170 | } |
26171 | else if (strcmp (s1: p, s2: "message" )) |
26172 | { |
26173 | error_at (cloc, |
26174 | "expected %<at%>, %<severity%> or %<message%> clause" ); |
26175 | c_parser_skip_to_pragma_eol (parser, error_if_not_eol: false); |
26176 | return false; |
26177 | } |
26178 | |
26179 | c_parser_consume_token (parser); |
26180 | |
26181 | matching_parens parens; |
26182 | if (parens.require_open (parser)) |
26183 | { |
26184 | if (v == NULL) |
26185 | { |
26186 | location_t expr_loc = c_parser_peek_token (parser)->location; |
26187 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
26188 | expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true); |
26189 | m = convert (const_string_type_node, expr.value); |
26190 | m = c_fully_fold (m, false, NULL); |
26191 | } |
26192 | else |
26193 | { |
26194 | if (c_parser_next_token_is (parser, type: CPP_NAME)) |
26195 | { |
26196 | tree val = c_parser_peek_token (parser)->value; |
26197 | const char *q = IDENTIFIER_POINTER (val); |
26198 | |
26199 | if (!strcmp (s1: q, s2: args[idx])) |
26200 | n = 0; |
26201 | else if (!strcmp (s1: q, s2: args[idx + 1])) |
26202 | n = 1; |
26203 | } |
26204 | if (n == -1) |
26205 | { |
26206 | error_at (c_parser_peek_token (parser)->location, |
26207 | "expected %qs or %qs" , args[idx], args[idx + 1]); |
26208 | bad = true; |
26209 | switch (c_parser_peek_token (parser)->type) |
26210 | { |
26211 | case CPP_EOF: |
26212 | case CPP_PRAGMA_EOL: |
26213 | case CPP_CLOSE_PAREN: |
26214 | break; |
26215 | default: |
26216 | if (c_parser_peek_2nd_token (parser)->type |
26217 | == CPP_CLOSE_PAREN) |
26218 | c_parser_consume_token (parser); |
26219 | break; |
26220 | } |
26221 | } |
26222 | else |
26223 | c_parser_consume_token (parser); |
26224 | } |
26225 | |
26226 | parens.skip_until_found_close (parser); |
26227 | |
26228 | if (v == NULL) |
26229 | { |
26230 | if (message) |
26231 | { |
26232 | error_at (cloc, "too many %qs clauses" , p); |
26233 | bad = true; |
26234 | } |
26235 | else |
26236 | message = m; |
26237 | } |
26238 | else if (n != -1) |
26239 | { |
26240 | if (*v != -1) |
26241 | { |
26242 | error_at (cloc, "too many %qs clauses" , p); |
26243 | bad = true; |
26244 | } |
26245 | else |
26246 | *v = n; |
26247 | } |
26248 | } |
26249 | else |
26250 | bad = true; |
26251 | } |
26252 | c_parser_skip_to_pragma_eol (parser); |
26253 | if (bad) |
26254 | return true; |
26255 | |
26256 | if (at_compilation == -1) |
26257 | at_compilation = 1; |
26258 | if (severity_fatal == -1) |
26259 | severity_fatal = 1; |
26260 | if (!at_compilation) |
26261 | { |
26262 | if (context != pragma_compound) |
26263 | { |
26264 | error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause " |
26265 | "may only be used in compound statements" ); |
26266 | return true; |
26267 | } |
26268 | tree fndecl |
26269 | = builtin_decl_explicit (fncode: severity_fatal ? BUILT_IN_GOMP_ERROR |
26270 | : BUILT_IN_GOMP_WARNING); |
26271 | if (!message) |
26272 | message = build_zero_cst (const_string_type_node); |
26273 | tree stmt = build_call_expr_loc (loc, fndecl, 2, message, |
26274 | build_all_ones_cst (size_type_node)); |
26275 | add_stmt (stmt); |
26276 | return true; |
26277 | } |
26278 | const char *msg = NULL; |
26279 | if (message) |
26280 | { |
26281 | msg = c_getstr (message); |
26282 | if (msg == NULL) |
26283 | msg = _("<message unknown at compile time>" ); |
26284 | } |
26285 | if (msg) |
26286 | emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, |
26287 | "%<pragma omp error%> encountered: %s" , msg); |
26288 | else |
26289 | emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, |
26290 | "%<pragma omp error%> encountered" ); |
26291 | return false; |
26292 | } |
26293 | |
26294 | /* Assumption clauses: |
26295 | OpenMP 5.1 |
26296 | absent (directive-name-list) |
26297 | contains (directive-name-list) |
26298 | holds (expression) |
26299 | no_openmp |
26300 | no_openmp_routines |
26301 | no_parallelism */ |
26302 | |
26303 | static void |
26304 | c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume) |
26305 | { |
26306 | bool no_openmp = false; |
26307 | bool no_openmp_routines = false; |
26308 | bool no_parallelism = false; |
26309 | bitmap_head absent_head, contains_head; |
26310 | |
26311 | bitmap_obstack_initialize (NULL); |
26312 | bitmap_initialize (head: &absent_head, obstack: &bitmap_default_obstack); |
26313 | bitmap_initialize (head: &contains_head, obstack: &bitmap_default_obstack); |
26314 | |
26315 | if (c_parser_next_token_is (parser, type: CPP_PRAGMA_EOL)) |
26316 | error_at (c_parser_peek_token (parser)->location, |
26317 | "expected at least one assumption clause" ); |
26318 | |
26319 | while (c_parser_next_token_is_not (parser, type: CPP_PRAGMA_EOL)) |
26320 | { |
26321 | if (c_parser_next_token_is (parser, type: CPP_COMMA) |
26322 | && c_parser_peek_2nd_token (parser)->type == CPP_NAME) |
26323 | c_parser_consume_token (parser); |
26324 | |
26325 | if (!c_parser_next_token_is (parser, type: CPP_NAME)) |
26326 | break; |
26327 | |
26328 | const char *p |
26329 | = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); |
26330 | location_t cloc = c_parser_peek_token (parser)->location; |
26331 | |
26332 | if (!strcmp (s1: p, s2: "no_openmp" )) |
26333 | { |
26334 | c_parser_consume_token (parser); |
26335 | if (no_openmp) |
26336 | error_at (cloc, "too many %qs clauses" , "no_openmp" ); |
26337 | no_openmp = true; |
26338 | } |
26339 | else if (!strcmp (s1: p, s2: "no_openmp_routines" )) |
26340 | { |
26341 | c_parser_consume_token (parser); |
26342 | if (no_openmp_routines) |
26343 | error_at (cloc, "too many %qs clauses" , "no_openmp_routines" ); |
26344 | no_openmp_routines = true; |
26345 | } |
26346 | else if (!strcmp (s1: p, s2: "no_parallelism" )) |
26347 | { |
26348 | c_parser_consume_token (parser); |
26349 | if (no_parallelism) |
26350 | error_at (cloc, "too many %qs clauses" , "no_parallelism" ); |
26351 | no_parallelism = true; |
26352 | } |
26353 | else if (!strcmp (s1: p, s2: "holds" )) |
26354 | { |
26355 | c_parser_consume_token (parser); |
26356 | matching_parens parens; |
26357 | if (parens.require_open (parser)) |
26358 | { |
26359 | location_t eloc = c_parser_peek_token (parser)->location; |
26360 | c_expr expr = c_parser_expr_no_commas (parser, NULL); |
26361 | tree t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; |
26362 | t = c_objc_common_truthvalue_conversion (eloc, t); |
26363 | t = c_fully_fold (t, false, NULL); |
26364 | if (is_assume && t != error_mark_node) |
26365 | { |
26366 | tree fn = build_call_expr_internal_loc (eloc, IFN_ASSUME, |
26367 | void_type_node, 1, |
26368 | t); |
26369 | add_stmt (fn); |
26370 | } |
26371 | parens.skip_until_found_close (parser); |
26372 | } |
26373 | } |
26374 | else if (!strcmp (s1: p, s2: "absent" ) || !strcmp (s1: p, s2: "contains" )) |
26375 | { |
26376 | c_parser_consume_token (parser); |
26377 | matching_parens parens; |
26378 | if (parens.require_open (parser)) |
26379 | { |
26380 | do |
26381 | { |
26382 | const char *directive[3] = {}; |
26383 | int i; |
26384 | location_t dloc = c_parser_peek_token (parser)->location; |
26385 | for (i = 0; i < 3; i++) |
26386 | { |
26387 | tree id; |
26388 | if (c_parser_peek_nth_token (parser, n: i + 1)->type |
26389 | == CPP_NAME) |
26390 | id = c_parser_peek_nth_token (parser, n: i + 1)->value; |
26391 | else if (c_parser_peek_nth_token (parser, n: i + 1)->keyword |
26392 | != RID_MAX) |
26393 | { |
26394 | enum rid rid |
26395 | = c_parser_peek_nth_token (parser, n: i + 1)->keyword; |
26396 | id = ridpointers[rid]; |
26397 | } |
26398 | else |
26399 | break; |
26400 | directive[i] = IDENTIFIER_POINTER (id); |
26401 | } |
26402 | if (i == 0) |
26403 | error_at (dloc, "expected directive name" ); |
26404 | else |
26405 | { |
26406 | const struct c_omp_directive *dir |
26407 | = c_omp_categorize_directive (directive[0], |
26408 | directive[1], |
26409 | directive[2]); |
26410 | if (dir == NULL |
26411 | || dir->kind == C_OMP_DIR_DECLARATIVE |
26412 | || dir->kind == C_OMP_DIR_INFORMATIONAL |
26413 | || dir->id == PRAGMA_OMP_END |
26414 | || (!dir->second && directive[1]) |
26415 | || (!dir->third && directive[2])) |
26416 | error_at (dloc, "unknown OpenMP directive name in " |
26417 | "%qs clause argument" , p); |
26418 | else |
26419 | { |
26420 | int id = dir - c_omp_directives; |
26421 | if (bitmap_bit_p (p[0] == 'a' ? &contains_head |
26422 | : &absent_head, id)) |
26423 | error_at (dloc, "%<%s%s%s%s%s%> directive " |
26424 | "mentioned in both %<absent%> and " |
26425 | "%<contains%> clauses" , |
26426 | directive[0], |
26427 | directive[1] ? " " : "" , |
26428 | directive[1] ? directive[1] : "" , |
26429 | directive[2] ? " " : "" , |
26430 | directive[2] ? directive[2] : "" ); |
26431 | else if (!bitmap_set_bit (p[0] == 'a' |
26432 | ? &absent_head |
26433 | : &contains_head, id)) |
26434 | error_at (dloc, "%<%s%s%s%s%s%> directive " |
26435 | "mentioned multiple times in %qs " |
26436 | "clauses" , |
26437 | directive[0], |
26438 | directive[1] ? " " : "" , |
26439 | directive[1] ? directive[1] : "" , |
26440 | directive[2] ? " " : "" , |
26441 | directive[2] ? directive[2] : "" , p); |
26442 | } |
26443 | for (; i; --i) |
26444 | c_parser_consume_token (parser); |
26445 | } |
26446 | if (c_parser_next_token_is (parser, type: CPP_COMMA)) |
26447 | c_parser_consume_token (parser); |
26448 | else |
26449 | break; |
26450 | } |
26451 | while (1); |
26452 | parens.skip_until_found_close (parser); |
26453 | } |
26454 | } |
26455 | else if (startswith (str: p, prefix: "ext_" )) |
26456 | { |
26457 | warning_at (cloc, OPT_Wopenmp, "unknown assumption clause %qs" , p); |
26458 | c_parser_consume_token (parser); |
26459 | if (c_parser_next_token_is (parser, type: CPP_OPEN_PAREN)) |
26460 | { |
26461 | matching_parens parens; |
26462 | parens.consume_open (parser); |
26463 | c_parser_balanced_token_sequence (parser); |
26464 | parens.require_close (parser); |
26465 | } |
26466 | } |
26467 | else |
26468 | { |
26469 | c_parser_consume_token (parser); |
26470 | error_at (cloc, "expected assumption clause" ); |
26471 | break; |
26472 | } |
26473 | } |
26474 | c_parser_skip_to_pragma_eol (parser); |
26475 | } |
26476 | |
26477 | /* OpenMP 5.1 |
26478 | #pragma omp assume clauses[optseq] new-line */ |
26479 | |
26480 | static void |
26481 | c_parser_omp_assume (c_parser *parser, bool *if_p) |
26482 | { |
26483 | c_parser_omp_assumption_clauses (parser, is_assume: true); |
26484 | add_stmt (c_parser_omp_structured_block (parser, if_p)); |
26485 | } |
26486 | |
26487 | /* OpenMP 5.1 |
26488 | #pragma omp assumes clauses[optseq] new-line */ |
26489 | |
26490 | static void |
26491 | c_parser_omp_assumes (c_parser *parser) |
26492 | { |
26493 | c_parser_consume_pragma (parser); |
26494 | c_parser_omp_assumption_clauses (parser, is_assume: false); |
26495 | } |
26496 | |
26497 | /* Main entry point to parsing most OpenMP pragmas. */ |
26498 | |
26499 | static void |
26500 | c_parser_omp_construct (c_parser *parser, bool *if_p) |
26501 | { |
26502 | enum pragma_kind p_kind; |
26503 | location_t loc; |
26504 | tree stmt; |
26505 | char p_name[sizeof "#pragma omp teams distribute parallel for simd" ]; |
26506 | omp_clause_mask mask (0); |
26507 | |
26508 | loc = c_parser_peek_token (parser)->location; |
26509 | p_kind = c_parser_peek_token (parser)->pragma_kind; |
26510 | c_parser_consume_pragma (parser); |
26511 | |
26512 | switch (p_kind) |
26513 | { |
26514 | case PRAGMA_OACC_ATOMIC: |
26515 | c_parser_omp_atomic (loc, parser, openacc: true); |
26516 | return; |
26517 | case PRAGMA_OACC_CACHE: |
26518 | strcpy (dest: p_name, src: "#pragma acc" ); |
26519 | stmt = c_parser_oacc_cache (loc, parser); |
26520 | break; |
26521 | case PRAGMA_OACC_DATA: |
26522 | stmt = c_parser_oacc_data (loc, parser, if_p); |
26523 | break; |
26524 | case PRAGMA_OACC_HOST_DATA: |
26525 | stmt = c_parser_oacc_host_data (loc, parser, if_p); |
26526 | break; |
26527 | case PRAGMA_OACC_KERNELS: |
26528 | case PRAGMA_OACC_PARALLEL: |
26529 | case PRAGMA_OACC_SERIAL: |
26530 | strcpy (dest: p_name, src: "#pragma acc" ); |
26531 | stmt = c_parser_oacc_compute (loc, parser, p_kind, p_name, if_p); |
26532 | break; |
26533 | case PRAGMA_OACC_LOOP: |
26534 | strcpy (dest: p_name, src: "#pragma acc" ); |
26535 | stmt = c_parser_oacc_loop (loc, parser, p_name, mask, NULL, if_p); |
26536 | break; |
26537 | case PRAGMA_OACC_WAIT: |
26538 | strcpy (dest: p_name, src: "#pragma wait" ); |
26539 | stmt = c_parser_oacc_wait (loc, parser, p_name); |
26540 | break; |
26541 | case PRAGMA_OMP_ATOMIC: |
26542 | c_parser_omp_atomic (loc, parser, openacc: false); |
26543 | return; |
26544 | case PRAGMA_OMP_CRITICAL: |
26545 | stmt = c_parser_omp_critical (loc, parser, if_p); |
26546 | break; |
26547 | case PRAGMA_OMP_DISTRIBUTE: |
26548 | strcpy (dest: p_name, src: "#pragma omp" ); |
26549 | stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL, if_p); |
26550 | break; |
26551 | case PRAGMA_OMP_FOR: |
26552 | strcpy (dest: p_name, src: "#pragma omp" ); |
26553 | stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL, if_p); |
26554 | break; |
26555 | case PRAGMA_OMP_LOOP: |
26556 | strcpy (dest: p_name, src: "#pragma omp" ); |
26557 | stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); |
26558 | break; |
26559 | case PRAGMA_OMP_MASKED: |
26560 | strcpy (dest: p_name, src: "#pragma omp" ); |
26561 | stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); |
26562 | break; |
26563 | case PRAGMA_OMP_MASTER: |
26564 | strcpy (dest: p_name, src: "#pragma omp" ); |
26565 | stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); |
26566 | break; |
26567 | case PRAGMA_OMP_PARALLEL: |
26568 | strcpy (dest: p_name, src: "#pragma omp" ); |
26569 | stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); |
26570 | break; |
26571 | case PRAGMA_OMP_SCOPE: |
26572 | stmt = c_parser_omp_scope (loc, parser, if_p); |
26573 | break; |
26574 | case PRAGMA_OMP_SECTIONS: |
26575 | strcpy (dest: p_name, src: "#pragma omp" ); |
26576 | stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); |
26577 | break; |
26578 | case PRAGMA_OMP_SIMD: |
26579 | strcpy (dest: p_name, src: "#pragma omp" ); |
26580 | stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL, if_p); |
26581 | break; |
26582 | case PRAGMA_OMP_SINGLE: |
26583 | stmt = c_parser_omp_single (loc, parser, if_p); |
26584 | break; |
26585 | case PRAGMA_OMP_TASK: |
26586 | stmt = c_parser_omp_task (loc, parser, if_p); |
26587 | break; |
26588 | case PRAGMA_OMP_TASKGROUP: |
26589 | stmt = c_parser_omp_taskgroup (loc, parser, if_p); |
26590 | break; |
26591 | case PRAGMA_OMP_TASKLOOP: |
26592 | strcpy (dest: p_name, src: "#pragma omp" ); |
26593 | stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL, if_p); |
26594 | break; |
26595 | case PRAGMA_OMP_TEAMS: |
26596 | strcpy (dest: p_name, src: "#pragma omp" ); |
26597 | stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p); |
26598 | break; |
26599 | case PRAGMA_OMP_ASSUME: |
26600 | c_parser_omp_assume (parser, if_p); |
26601 | return; |
26602 | default: |
26603 | gcc_unreachable (); |
26604 | } |
26605 | |
26606 | if (stmt && stmt != error_mark_node) |
26607 | gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION); |
26608 | } |
26609 | |
26610 | |
26611 | /* OpenMP 2.5: |
26612 | # pragma omp threadprivate (variable-list) */ |
26613 | |
26614 | static void |
26615 | c_parser_omp_threadprivate (c_parser *parser) |
26616 | { |
26617 | tree vars, t; |
26618 | location_t loc; |
26619 | |
26620 | c_parser_consume_pragma (parser); |
26621 | loc = c_parser_peek_token (parser)->location; |
26622 | vars = c_parser_omp_var_list_parens (parser, kind: OMP_CLAUSE_ERROR, NULL); |
26623 | |
26624 | /* Mark every variable in VARS to be assigned thread local storage. */ |
26625 | for (t = vars; t; t = TREE_CHAIN (t)) |
26626 | { |
26627 | tree v = TREE_PURPOSE (t); |
26628 | |
26629 | /* FIXME diagnostics: Ideally we should keep individual |
26630 | locations for all the variables in the var list to make the |
26631 | following errors more precise. Perhaps |
26632 | c_parser_omp_var_list_parens() should construct a list of |
26633 | locations to go along with the var list. */ |
26634 | |
26635 | /* If V had already been marked threadprivate, it doesn't matter |
26636 | whether it had been used prior to this point. */ |
26637 | if (!VAR_P (v)) |
26638 | error_at (loc, "%qD is not a variable" , v); |
26639 | else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v)) |
26640 | error_at (loc, "%qE declared %<threadprivate%> after first use" , v); |
26641 | else if (! is_global_var (t: v)) |
26642 | error_at (loc, "automatic variable %qE cannot be %<threadprivate%>" , v); |
26643 | else if (TREE_TYPE (v) == error_mark_node) |
26644 | ; |
26645 | else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) |
26646 | error_at (loc, "%<threadprivate%> %qE has incomplete type" , v); |
26647 | else |
26648 | { |
26649 | if (! DECL_THREAD_LOCAL_P (v)) |
26650 | { |
26651 | set_decl_tls_model (v, decl_default_tls_model (v)); |
26652 | /* If rtl has been already set for this var, call |
26653 | make_decl_rtl once again, so that encode_section_info |
26654 | has a chance to look at the new decl flags. */ |
26655 | if (DECL_RTL_SET_P (v)) |
26656 | make_decl_rtl (v); |
26657 | } |
26658 | C_DECL_THREADPRIVATE_P (v) = 1; |
26659 | } |
26660 | } |
26661 | |
26662 | c_parser_skip_to_pragma_eol (parser); |
26663 | } |
26664 | |
26665 | /* Parse a transaction attribute (GCC Extension). |
26666 | |
26667 | transaction-attribute: |
26668 | gnu-attributes |
26669 | attribute-specifier |
26670 | */ |
26671 | |
26672 | static tree |
26673 | c_parser_transaction_attributes (c_parser *parser) |
26674 | { |
26675 | if (c_parser_next_token_is_keyword (parser, keyword: RID_ATTRIBUTE)) |
26676 | return c_parser_gnu_attributes (parser); |
26677 | |
26678 | if (!c_parser_next_token_is (parser, type: CPP_OPEN_SQUARE)) |
26679 | return NULL_TREE; |
26680 | return c_parser_std_attribute_specifier (parser, for_tm: true); |
26681 | } |
26682 | |
26683 | /* Parse a __transaction_atomic or __transaction_relaxed statement |
26684 | (GCC Extension). |
26685 | |
26686 | transaction-statement: |
26687 | __transaction_atomic transaction-attribute[opt] compound-statement |
26688 | __transaction_relaxed compound-statement |
26689 | |
26690 | Note that the only valid attribute is: "outer". |
26691 | */ |
26692 | |
26693 | static tree |
26694 | c_parser_transaction (c_parser *parser, enum rid keyword) |
26695 | { |
26696 | unsigned int old_in = parser->in_transaction; |
26697 | unsigned int this_in = 1, new_in; |
26698 | location_t loc = c_parser_peek_token (parser)->location; |
26699 | tree stmt, attrs; |
26700 | |
26701 | gcc_assert ((keyword == RID_TRANSACTION_ATOMIC |
26702 | || keyword == RID_TRANSACTION_RELAXED) |
26703 | && c_parser_next_token_is_keyword (parser, keyword)); |
26704 | c_parser_consume_token (parser); |
26705 | |
26706 | if (keyword == RID_TRANSACTION_RELAXED) |
26707 | this_in |= TM_STMT_ATTR_RELAXED; |
26708 | else |
26709 | { |
26710 | attrs = c_parser_transaction_attributes (parser); |
26711 | if (attrs) |
26712 | this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); |
26713 | } |
26714 | |
26715 | /* Keep track if we're in the lexical scope of an outer transaction. */ |
26716 | new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); |
26717 | |
26718 | parser->in_transaction = new_in; |
26719 | stmt = c_parser_compound_statement (parser); |
26720 | parser->in_transaction = old_in; |
26721 | |
26722 | if (flag_tm) |
26723 | stmt = c_finish_transaction (loc, stmt, this_in); |
26724 | else |
26725 | error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? |
26726 | "%<__transaction_atomic%> without transactional memory support enabled" |
26727 | : "%<__transaction_relaxed %> " |
26728 | "without transactional memory support enabled" )); |
26729 | |
26730 | return stmt; |
26731 | } |
26732 | |
26733 | /* Parse a __transaction_atomic or __transaction_relaxed expression |
26734 | (GCC Extension). |
26735 | |
26736 | transaction-expression: |
26737 | __transaction_atomic ( expression ) |
26738 | __transaction_relaxed ( expression ) |
26739 | */ |
26740 | |
26741 | static struct c_expr |
26742 | c_parser_transaction_expression (c_parser *parser, enum rid keyword) |
26743 | { |
26744 | struct c_expr ret; |
26745 | unsigned int old_in = parser->in_transaction; |
26746 | unsigned int this_in = 1; |
26747 | location_t loc = c_parser_peek_token (parser)->location; |
26748 | tree attrs; |
26749 | |
26750 | gcc_assert ((keyword == RID_TRANSACTION_ATOMIC |
26751 | || keyword == RID_TRANSACTION_RELAXED) |
26752 | && c_parser_next_token_is_keyword (parser, keyword)); |
26753 | c_parser_consume_token (parser); |
26754 | |
26755 | if (keyword == RID_TRANSACTION_RELAXED) |
26756 | this_in |= TM_STMT_ATTR_RELAXED; |
26757 | else |
26758 | { |
26759 | attrs = c_parser_transaction_attributes (parser); |
26760 | if (attrs) |
26761 | this_in |= parse_tm_stmt_attr (attrs, 0); |
26762 | } |
26763 | |
26764 | parser->in_transaction = this_in; |
26765 | matching_parens parens; |
26766 | if (parens.require_open (parser)) |
26767 | { |
26768 | tree expr = c_parser_expression (parser).value; |
26769 | ret.original_type = TREE_TYPE (expr); |
26770 | ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); |
26771 | if (this_in & TM_STMT_ATTR_RELAXED) |
26772 | TRANSACTION_EXPR_RELAXED (ret.value) = 1; |
26773 | SET_EXPR_LOCATION (ret.value, loc); |
26774 | ret.original_code = TRANSACTION_EXPR; |
26775 | ret.m_decimal = 0; |
26776 | if (!parens.require_close (parser)) |
26777 | { |
26778 | c_parser_skip_until_found (parser, type: CPP_CLOSE_PAREN, NULL); |
26779 | goto error; |
26780 | } |
26781 | } |
26782 | else |
26783 | { |
26784 | error: |
26785 | ret.set_error (); |
26786 | ret.original_code = ERROR_MARK; |
26787 | ret.original_type = NULL; |
26788 | } |
26789 | parser->in_transaction = old_in; |
26790 | |
26791 | if (!flag_tm) |
26792 | error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ? |
26793 | "%<__transaction_atomic%> without transactional memory support enabled" |
26794 | : "%<__transaction_relaxed %> " |
26795 | "without transactional memory support enabled" )); |
26796 | |
26797 | set_c_expr_source_range (expr: &ret, start: loc, finish: loc); |
26798 | |
26799 | return ret; |
26800 | } |
26801 | |
26802 | /* Parse a __transaction_cancel statement (GCC Extension). |
26803 | |
26804 | transaction-cancel-statement: |
26805 | __transaction_cancel transaction-attribute[opt] ; |
26806 | |
26807 | Note that the only valid attribute is "outer". |
26808 | */ |
26809 | |
26810 | static tree |
26811 | c_parser_transaction_cancel (c_parser *parser) |
26812 | { |
26813 | location_t loc = c_parser_peek_token (parser)->location; |
26814 | tree attrs; |
26815 | bool is_outer = false; |
26816 | |
26817 | gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL)); |
26818 | c_parser_consume_token (parser); |
26819 | |
26820 | attrs = c_parser_transaction_attributes (parser); |
26821 | if (attrs) |
26822 | is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); |
26823 | |
26824 | if (!flag_tm) |
26825 | { |
26826 | error_at (loc, "%<__transaction_cancel%> without " |
26827 | "transactional memory support enabled" ); |
26828 | goto ret_error; |
26829 | } |
26830 | else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) |
26831 | { |
26832 | error_at (loc, "%<__transaction_cancel%> within a " |
26833 | "%<__transaction_relaxed%>" ); |
26834 | goto ret_error; |
26835 | } |
26836 | else if (is_outer) |
26837 | { |
26838 | if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 |
26839 | && !is_tm_may_cancel_outer (current_function_decl)) |
26840 | { |
26841 | error_at (loc, "outer %<__transaction_cancel%> not " |
26842 | "within outer %<__transaction_atomic%> or " |
26843 | "a %<transaction_may_cancel_outer%> function" ); |
26844 | goto ret_error; |
26845 | } |
26846 | } |
26847 | else if (parser->in_transaction == 0) |
26848 | { |
26849 | error_at (loc, "%<__transaction_cancel%> not within " |
26850 | "%<__transaction_atomic%>" ); |
26851 | goto ret_error; |
26852 | } |
26853 | |
26854 | return add_stmt (build_tm_abort_call (loc, is_outer)); |
26855 | |
26856 | ret_error: |
26857 | return build1 (NOP_EXPR, void_type_node, error_mark_node); |
26858 | } |
26859 | |
26860 | /* Parse a single source file. */ |
26861 | |
26862 | void |
26863 | c_parse_file (void) |
26864 | { |
26865 | /* Use local storage to begin. If the first token is a pragma, parse it. |
26866 | If it is #pragma GCC pch_preprocess, then this will load a PCH file |
26867 | which will cause garbage collection. */ |
26868 | c_parser tparser; |
26869 | |
26870 | memset (s: &tparser, c: 0, n: sizeof tparser); |
26871 | tparser.translate_strings_p = true; |
26872 | tparser.tokens = &tparser.tokens_buf[0]; |
26873 | the_parser = &tparser; |
26874 | |
26875 | if (c_parser_peek_token (parser: &tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS) |
26876 | c_parser_pragma_pch_preprocess (parser: &tparser); |
26877 | else |
26878 | c_common_no_more_pch (); |
26879 | |
26880 | the_parser = ggc_alloc<c_parser> (); |
26881 | *the_parser = tparser; |
26882 | if (tparser.tokens == &tparser.tokens_buf[0]) |
26883 | the_parser->tokens = &the_parser->tokens_buf[0]; |
26884 | |
26885 | /* Initialize EH, if we've been told to do so. */ |
26886 | if (flag_exceptions) |
26887 | using_eh_for_cleanups (); |
26888 | |
26889 | c_parser_translation_unit (parser: the_parser); |
26890 | the_parser = NULL; |
26891 | } |
26892 | |
26893 | void |
26894 | c_init_preprocess (void) |
26895 | { |
26896 | /* Create a parser for use by pragma_lex during preprocessing. */ |
26897 | the_parser = ggc_alloc<c_parser> (); |
26898 | memset (s: the_parser, c: 0, n: sizeof (c_parser)); |
26899 | the_parser->tokens = &the_parser->tokens_buf[0]; |
26900 | } |
26901 | |
26902 | /* Parse the body of a function declaration marked with "__RTL". |
26903 | |
26904 | The RTL parser works on the level of characters read from a |
26905 | FILE *, whereas c_parser works at the level of tokens. |
26906 | Square this circle by consuming all of the tokens up to and |
26907 | including the closing brace, recording the start/end of the RTL |
26908 | fragment, and reopening the file and re-reading the relevant |
26909 | lines within the RTL parser. |
26910 | |
26911 | This requires the opening and closing braces of the C function |
26912 | to be on separate lines from the RTL they wrap. |
26913 | |
26914 | Take ownership of START_WITH_PASS, if non-NULL. */ |
26915 | |
26916 | location_t |
26917 | c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) |
26918 | { |
26919 | if (!c_parser_require (parser, type: CPP_OPEN_BRACE, msgid: "expected %<{%>" )) |
26920 | { |
26921 | free (ptr: start_with_pass); |
26922 | return c_parser_peek_token (parser)->location; |
26923 | } |
26924 | |
26925 | location_t start_loc = c_parser_peek_token (parser)->location; |
26926 | |
26927 | /* Consume all tokens, up to the closing brace, handling |
26928 | matching pairs of braces in the rtl dump. */ |
26929 | int num_open_braces = 1; |
26930 | while (1) |
26931 | { |
26932 | switch (c_parser_peek_token (parser)->type) |
26933 | { |
26934 | case CPP_OPEN_BRACE: |
26935 | num_open_braces++; |
26936 | break; |
26937 | case CPP_CLOSE_BRACE: |
26938 | if (--num_open_braces == 0) |
26939 | goto found_closing_brace; |
26940 | break; |
26941 | case CPP_EOF: |
26942 | error_at (start_loc, "no closing brace" ); |
26943 | free (ptr: start_with_pass); |
26944 | return c_parser_peek_token (parser)->location; |
26945 | default: |
26946 | break; |
26947 | } |
26948 | c_parser_consume_token (parser); |
26949 | } |
26950 | |
26951 | found_closing_brace: |
26952 | /* At the closing brace; record its location. */ |
26953 | location_t end_loc = c_parser_peek_token (parser)->location; |
26954 | |
26955 | /* Consume the closing brace. */ |
26956 | c_parser_consume_token (parser); |
26957 | |
26958 | /* Invoke the RTL parser. */ |
26959 | if (!read_rtl_function_body_from_file_range (start_loc, end_loc)) |
26960 | { |
26961 | free (ptr: start_with_pass); |
26962 | return end_loc; |
26963 | } |
26964 | |
26965 | /* Run the backend on the cfun created above, transferring ownership of |
26966 | START_WITH_PASS. */ |
26967 | run_rtl_passes (initial_pass_name: start_with_pass); |
26968 | return end_loc; |
26969 | } |
26970 | |
26971 | #include "gt-c-c-parser.h" |
26972 | |