aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/util/TimeZone.java
blob: 6d4493001f6634ee3efcb73e4a959af359812ce8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
/* java.util.TimeZone
   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package java.util;
import java.text.DateFormatSymbols;
import gnu.classpath.Configuration;

/**
 * This class represents a time zone offset and handles daylight savings.
 * 
 * You can get the default time zone with <code>getDefault</code>.
 * This represents the time zone where program is running.
 *
 * Another way to create a time zone is <code>getTimeZone</code>, where
 * you can give an identifier as parameter.  For instance, the identifier
 * of the Central European Time zone is "CET".
 *
 * With the <code>getAvailableIDs</code> method, you can get all the
 * supported time zone identifiers.
 *
 * @see Calendar
 * @see SimpleTimeZone
 * @author Jochen Hoenicke
 */
public abstract class TimeZone implements java.io.Serializable, Cloneable
{

  /**
   * Constant used to indicate that a short timezone abbreviation should
   * be returned, such as "EST"
   */
  public static final int SHORT = 0;

  /**
   * Constant used to indicate that a long timezone name should be
   * returned, such as "Eastern Standard Time".
   */
  public static final int LONG = 1;

  /**
   * The time zone identifier, e.g. PST.
   */
  private String ID;

  /**
   * The default time zone, as returned by getDefault.
   */
  private static TimeZone defaultZone;

  private static final long serialVersionUID = 3581463369166924961L;

  /**
   * Hashtable for timezones by ID.  
   */
  private static final Hashtable timezones = new Hashtable();

  static
  {
    TimeZone tz;
    // Automatically generated by scripts/timezones.pl
    // XXX - Should we read this data from a file?
    tz = new SimpleTimeZone(-11000 * 3600, "MIT");
    timezones.put("MIT", tz);
    timezones.put("Pacific/Apia", tz);
    timezones.put("Pacific/Midway", tz);
    timezones.put("Pacific/Niue", tz);
    timezones.put("Pacific/Pago_Pago", tz);
    tz = new SimpleTimeZone
      (-10000 * 3600, "America/Adak",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("America/Adak", tz);
    tz = new SimpleTimeZone(-10000 * 3600, "HST");
    timezones.put("HST", tz);
    timezones.put("Pacific/Fakaofo", tz);
    timezones.put("Pacific/Honolulu", tz);
    timezones.put("Pacific/Johnston", tz);
    timezones.put("Pacific/Rarotonga", tz);
    timezones.put("Pacific/Tahiti", tz);
    tz = new SimpleTimeZone(-9500 * 3600, "Pacific/Marquesas");
    timezones.put("Pacific/Marquesas", tz);
    tz = new SimpleTimeZone
      (-9000 * 3600, "AST",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("AST", tz);
    timezones.put("America/Anchorage", tz);
    timezones.put("America/Juneau", tz);
    timezones.put("America/Nome", tz);
    timezones.put("America/Yakutat", tz);
    tz = new SimpleTimeZone(-9000 * 3600, "Pacific/Gambier");
    timezones.put("Pacific/Gambier", tz);
    tz = new SimpleTimeZone
      (-8000 * 3600, "PST",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("PST", tz);
    timezones.put("PST8PDT", tz);
    timezones.put("America/Dawson", tz);
    timezones.put("America/Los_Angeles", tz);
    timezones.put("America/Tijuana", tz);
    timezones.put("America/Vancouver", tz);
    timezones.put("America/Whitehorse", tz);
    timezones.put("US/Pacific-New", tz);
    tz = new SimpleTimeZone(-8000 * 3600, "Pacific/Pitcairn");
    timezones.put("Pacific/Pitcairn", tz);
    tz = new SimpleTimeZone
      (-7000 * 3600, "MST",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("MST", tz);
    timezones.put("MST7MDT", tz);
    timezones.put("America/Boise", tz);
    timezones.put("America/Chihuahua", tz);
    timezones.put("America/Denver", tz);
    timezones.put("America/Edmonton", tz);
    timezones.put("America/Inuvik", tz);
    timezones.put("America/Mazatlan", tz);
    timezones.put("America/Shiprock", tz);
    timezones.put("America/Yellowknife", tz);
    tz = new SimpleTimeZone(-7000 * 3600, "MST7");
    timezones.put("MST7", tz);
    timezones.put("PNT", tz);
    timezones.put("America/Dawson_Creek", tz);
    timezones.put("America/Hermosillo", tz);
    timezones.put("America/Phoenix", tz);
    tz = new SimpleTimeZone
      (-6000 * 3600, "CST",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("CST", tz);
    timezones.put("CST6CDT", tz);
    timezones.put("America/Cambridge_Bay", tz);
    timezones.put("America/Cancun", tz);
    timezones.put("America/Chicago", tz);
    timezones.put("America/Menominee", tz);
    timezones.put("America/Merida", tz);
    timezones.put("America/Mexico_City", tz);
    timezones.put("America/Monterrey", tz);
    timezones.put("America/Rainy_River", tz);
    timezones.put("America/Winnipeg", tz);
    tz = new SimpleTimeZone(-6000 * 3600, "America/Belize");
    timezones.put("America/Belize", tz);
    timezones.put("America/Costa_Rica", tz);
    timezones.put("America/El_Salvador", tz);
    timezones.put("America/Guatemala", tz);
    timezones.put("America/Managua", tz);
    timezones.put("America/Regina", tz);
    timezones.put("America/Swift_Current", tz);
    timezones.put("America/Tegucigalpa", tz);
    timezones.put("Pacific/Galapagos", tz);
    tz = new SimpleTimeZone
      (-6000 * 3600, "Pacific/Easter",
       Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600,
       Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600);
    timezones.put("Pacific/Easter", tz);
    tz = new SimpleTimeZone
      (-5000 * 3600, "America/Grand_Turk",
       Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("America/Grand_Turk", tz);
    timezones.put("America/Havana", tz);
    tz = new SimpleTimeZone(-5000 * 3600, "EST5");
    timezones.put("EST5", tz);
    timezones.put("IET", tz);
    timezones.put("America/Bogota", tz);
    timezones.put("America/Cayman", tz);
    timezones.put("America/Eirunepe", tz);
    timezones.put("America/Guayaquil", tz);
    timezones.put("America/Indiana/Indianapolis", tz);
    timezones.put("America/Indiana/Knox", tz);
    timezones.put("America/Indiana/Marengo", tz);
    timezones.put("America/Indiana/Vevay", tz);
    timezones.put("America/Indianapolis", tz);
    timezones.put("America/Iqaluit", tz);
    timezones.put("America/Jamaica", tz);
    timezones.put("America/Lima", tz);
    timezones.put("America/Panama", tz);
    timezones.put("America/Pangnirtung", tz);
    timezones.put("America/Port-au-Prince", tz);
    timezones.put("America/Porto_Acre", tz);
    timezones.put("America/Rankin_Inlet", tz);
    tz = new SimpleTimeZone
      (-5000 * 3600, "EST",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("EST", tz);
    timezones.put("EST5EDT", tz);
    timezones.put("America/Detroit", tz);
    timezones.put("America/Kentucky/Louisville", tz);
    timezones.put("America/Kentucky/Monticello", tz);
    timezones.put("America/Louisville", tz);
    timezones.put("America/Montreal", tz);
    timezones.put("America/Nassau", tz);
    timezones.put("America/New_York", tz);
    timezones.put("America/Nipigon", tz);
    timezones.put("America/Thunder_Bay", tz);
    tz = new SimpleTimeZone(-4000 * 3600, "PRT");
    timezones.put("PRT", tz);
    timezones.put("America/Anguilla", tz);
    timezones.put("America/Antigua", tz);
    timezones.put("America/Aruba", tz);
    timezones.put("America/Barbados", tz);
    timezones.put("America/Boa_Vista", tz);
    timezones.put("America/Caracas", tz);
    timezones.put("America/Curacao", tz);
    timezones.put("America/Dominica", tz);
    timezones.put("America/Grenada", tz);
    timezones.put("America/Guadeloupe", tz);
    timezones.put("America/Guyana", tz);
    timezones.put("America/La_Paz", tz);
    timezones.put("America/Manaus", tz);
    timezones.put("America/Martinique", tz);
    timezones.put("America/Montserrat", tz);
    timezones.put("America/Port_of_Spain", tz);
    timezones.put("America/Porto_Velho", tz);
    timezones.put("America/Puerto_Rico", tz);
    timezones.put("America/Santo_Domingo", tz);
    timezones.put("America/St_Kitts", tz);
    timezones.put("America/St_Lucia", tz);
    timezones.put("America/St_Thomas", tz);
    timezones.put("America/St_Vincent", tz);
    timezones.put("America/Tortola", tz);
    tz = new SimpleTimeZone
      (-4000 * 3600, "America/Asuncion",
       Calendar.OCTOBER, 1, Calendar.SUNDAY, 0 * 3600,
       Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("America/Asuncion", tz);
    tz = new SimpleTimeZone
      (-4000 * 3600, "America/Cuiaba",
       Calendar.OCTOBER, 2, Calendar.SUNDAY, 0 * 3600,
       Calendar.FEBRUARY, 3, Calendar.SUNDAY, 0 * 3600);
    timezones.put("America/Cuiaba", tz);
    tz = new SimpleTimeZone
      (-4000 * 3600, "America/Goose_Bay",
       Calendar.APRIL, 1, Calendar.SUNDAY, 60000,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000);
    timezones.put("America/Goose_Bay", tz);
    tz = new SimpleTimeZone
      (-4000 * 3600, "America/Glace_Bay",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("America/Glace_Bay", tz);
    timezones.put("America/Halifax", tz);
    timezones.put("America/Thule", tz);
    timezones.put("Atlantic/Bermuda", tz);
    tz = new SimpleTimeZone
      (-4000 * 3600, "America/Santiago",
       Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600,
       Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600);
    timezones.put("America/Santiago", tz);
    timezones.put("Antarctica/Palmer", tz);
    tz = new SimpleTimeZone
      (-4000 * 3600, "Atlantic/Stanley",
       Calendar.SEPTEMBER, 2, Calendar.SUNDAY, 0 * 3600,
       Calendar.APRIL, 16, -Calendar.SUNDAY, 0 * 3600);
    timezones.put("Atlantic/Stanley", tz);
    tz = new SimpleTimeZone
      (-3500 * 3600, "CNT",
       Calendar.APRIL, 1, Calendar.SUNDAY, 60000,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000);
    timezones.put("CNT", tz);
    timezones.put("America/St_Johns", tz);
    tz = new SimpleTimeZone
      (-3000 * 3600, "America/Araguaina",
       Calendar.OCTOBER, 2, Calendar.SUNDAY, 0 * 3600,
       Calendar.FEBRUARY, 3, Calendar.SUNDAY, 0 * 3600);
    timezones.put("America/Araguaina", tz);
    timezones.put("America/Sao_Paulo", tz);
    tz = new SimpleTimeZone(-3000 * 3600, "AGT");
    timezones.put("AGT", tz);
    timezones.put("America/Belem", tz);
    timezones.put("America/Buenos_Aires", tz);
    timezones.put("America/Catamarca", tz);
    timezones.put("America/Cayenne", tz);
    timezones.put("America/Cordoba", tz);
    timezones.put("America/Fortaleza", tz);
    timezones.put("America/Jujuy", tz);
    timezones.put("America/Maceio", tz);
    timezones.put("America/Mendoza", tz);
    timezones.put("America/Montevideo", tz);
    timezones.put("America/Paramaribo", tz);
    timezones.put("America/Recife", tz);
    timezones.put("America/Rosario", tz);
    tz = new SimpleTimeZone
      (-3000 * 3600, "America/Godthab",
       Calendar.MARCH, 30, -Calendar.SATURDAY, 22000 * 3600,
       Calendar.OCTOBER, 30, -Calendar.SATURDAY, 22000 * 3600);
    timezones.put("America/Godthab", tz);
    tz = new SimpleTimeZone
      (-3000 * 3600, "America/Miquelon",
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("America/Miquelon", tz);
    tz = new SimpleTimeZone(-2000 * 3600, "America/Noronha");
    timezones.put("America/Noronha", tz);
    timezones.put("Atlantic/South_Georgia", tz);
    tz = new SimpleTimeZone
      (-1000 * 3600, "America/Scoresbysund",
       Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("America/Scoresbysund", tz);
    timezones.put("Atlantic/Azores", tz);
    tz = new SimpleTimeZone(-1000 * 3600, "Atlantic/Cape_Verde");
    timezones.put("Atlantic/Cape_Verde", tz);
    timezones.put("Atlantic/Jan_Mayen", tz);
    tz = new SimpleTimeZone(0 * 3600, "GMT");
    timezones.put("GMT", tz);
    timezones.put("UTC", tz);
    timezones.put("Africa/Abidjan", tz);
    timezones.put("Africa/Accra", tz);
    timezones.put("Africa/Bamako", tz);
    timezones.put("Africa/Banjul", tz);
    timezones.put("Africa/Bissau", tz);
    timezones.put("Africa/Casablanca", tz);
    timezones.put("Africa/Conakry", tz);
    timezones.put("Africa/Dakar", tz);
    timezones.put("Africa/El_Aaiun", tz);
    timezones.put("Africa/Freetown", tz);
    timezones.put("Africa/Lome", tz);
    timezones.put("Africa/Monrovia", tz);
    timezones.put("Africa/Nouakchott", tz);
    timezones.put("Africa/Ouagadougou", tz);
    timezones.put("Africa/Sao_Tome", tz);
    timezones.put("Africa/Timbuktu", tz);
    timezones.put("Atlantic/Reykjavik", tz);
    timezones.put("Atlantic/St_Helena", tz);
    timezones.put("Europe/Belfast", tz);
    timezones.put("Europe/Dublin", tz);
    timezones.put("Europe/London", tz);
    tz = new SimpleTimeZone
      (0 * 3600, "WET",
       Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
    timezones.put("WET", tz);
    timezones.put("Atlantic/Canary", tz);
    timezones.put("Atlantic/Faeroe", tz);
    timezones.put("Atlantic/Madeira", tz);
    timezones.put("Europe/Lisbon", tz);
    tz = new SimpleTimeZone(1000 * 3600, "Africa/Algiers");
    timezones.put("Africa/Algiers", tz);
    timezones.put("Africa/Bangui", tz);
    timezones.put("Africa/Brazzaville", tz);
    timezones.put("Africa/Douala", tz);
    timezones.put("Africa/Kinshasa", tz);
    timezones.put("Africa/Lagos", tz);
    timezones.put("Africa/Libreville", tz);
    timezones.put("Africa/Luanda", tz);
    timezones.put("Africa/Malabo", tz);
    timezones.put("Africa/Ndjamena", tz);
    timezones.put("Africa/Niamey", tz);
    timezones.put("Africa/Porto-Novo", tz);
    timezones.put("Africa/Tunis", tz);
    tz = new SimpleTimeZone
      (1000 * 3600, "Africa/Windhoek",
       Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Africa/Windhoek", tz);
    tz = new SimpleTimeZone
      (1000 * 3600, "CET",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("CET", tz);
    timezones.put("ECT", tz);
    timezones.put("MET", tz);
    timezones.put("Africa/Ceuta", tz);
    timezones.put("Arctic/Longyearbyen", tz);
    timezones.put("Europe/Amsterdam", tz);
    timezones.put("Europe/Andorra", tz);
    timezones.put("Europe/Belgrade", tz);
    timezones.put("Europe/Berlin", tz);
    timezones.put("Europe/Bratislava", tz);
    timezones.put("Europe/Brussels", tz);
    timezones.put("Europe/Budapest", tz);
    timezones.put("Europe/Copenhagen", tz);
    timezones.put("Europe/Gibraltar", tz);
    timezones.put("Europe/Ljubljana", tz);
    timezones.put("Europe/Luxembourg", tz);
    timezones.put("Europe/Madrid", tz);
    timezones.put("Europe/Malta", tz);
    timezones.put("Europe/Monaco", tz);
    timezones.put("Europe/Oslo", tz);
    timezones.put("Europe/Paris", tz);
    timezones.put("Europe/Prague", tz);
    timezones.put("Europe/Rome", tz);
    timezones.put("Europe/San_Marino", tz);
    timezones.put("Europe/Sarajevo", tz);
    timezones.put("Europe/Skopje", tz);
    timezones.put("Europe/Stockholm", tz);
    timezones.put("Europe/Tirane", tz);
    timezones.put("Europe/Vaduz", tz);
    timezones.put("Europe/Vatican", tz);
    timezones.put("Europe/Vienna", tz);
    timezones.put("Europe/Warsaw", tz);
    timezones.put("Europe/Zagreb", tz);
    timezones.put("Europe/Zurich", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "ART",
       Calendar.APRIL, -1, Calendar.FRIDAY, 0 * 3600,
       Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 23000 * 3600);
    timezones.put("ART", tz);
    timezones.put("Africa/Cairo", tz);
    tz = new SimpleTimeZone(2000 * 3600, "CAT");
    timezones.put("CAT", tz);
    timezones.put("Africa/Blantyre", tz);
    timezones.put("Africa/Bujumbura", tz);
    timezones.put("Africa/Gaborone", tz);
    timezones.put("Africa/Harare", tz);
    timezones.put("Africa/Johannesburg", tz);
    timezones.put("Africa/Kigali", tz);
    timezones.put("Africa/Lubumbashi", tz);
    timezones.put("Africa/Lusaka", tz);
    timezones.put("Africa/Maputo", tz);
    timezones.put("Africa/Maseru", tz);
    timezones.put("Africa/Mbabane", tz);
    timezones.put("Africa/Tripoli", tz);
    timezones.put("Europe/Riga", tz);
    timezones.put("Europe/Tallinn", tz);
    timezones.put("Europe/Vilnius", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "Asia/Amman",
       Calendar.MARCH, -1, Calendar.THURSDAY, 0 * 3600,
       Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 0 * 3600);
    timezones.put("Asia/Amman", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "Asia/Beirut",
       Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("Asia/Beirut", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "Asia/Damascus",
       Calendar.APRIL, 1, 0, 0 * 3600,
       Calendar.OCTOBER, 1, 0, 0 * 3600);
    timezones.put("Asia/Damascus", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "Asia/Gaza",
       Calendar.APRIL, 3, Calendar.FRIDAY, 0 * 3600,
       Calendar.OCTOBER, 3, Calendar.FRIDAY, 0 * 3600);
    timezones.put("Asia/Gaza", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "Asia/Jerusalem",
       Calendar.APRIL, 1, 0, 1000 * 3600,
       Calendar.OCTOBER, 1, 0, 1000 * 3600);
    timezones.put("Asia/Jerusalem", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "EET",
       Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600);
    timezones.put("EET", tz);
    timezones.put("Asia/Istanbul", tz);
    timezones.put("Asia/Nicosia", tz);
    timezones.put("Europe/Athens", tz);
    timezones.put("Europe/Bucharest", tz);
    timezones.put("Europe/Chisinau", tz);
    timezones.put("Europe/Helsinki", tz);
    timezones.put("Europe/Istanbul", tz);
    timezones.put("Europe/Kiev", tz);
    timezones.put("Europe/Nicosia", tz);
    timezones.put("Europe/Simferopol", tz);
    timezones.put("Europe/Sofia", tz);
    timezones.put("Europe/Uzhgorod", tz);
    timezones.put("Europe/Zaporozhye", tz);
    tz = new SimpleTimeZone
      (2000 * 3600, "Europe/Kaliningrad",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Europe/Kaliningrad", tz);
    timezones.put("Europe/Minsk", tz);
    tz = new SimpleTimeZone
      (3000 * 3600, "Asia/Baghdad",
       Calendar.APRIL, 1, 0, 3000 * 3600,
       Calendar.OCTOBER, 1, 0, 3000 * 3600);
    timezones.put("Asia/Baghdad", tz);
    tz = new SimpleTimeZone
      (3000 * 3600, "Europe/Moscow",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Europe/Moscow", tz);
    timezones.put("Europe/Tiraspol", tz);
    tz = new SimpleTimeZone(3000 * 3600, "EAT");
    timezones.put("EAT", tz);
    timezones.put("Africa/Addis_Ababa", tz);
    timezones.put("Africa/Asmera", tz);
    timezones.put("Africa/Dar_es_Salaam", tz);
    timezones.put("Africa/Djibouti", tz);
    timezones.put("Africa/Kampala", tz);
    timezones.put("Africa/Khartoum", tz);
    timezones.put("Africa/Mogadishu", tz);
    timezones.put("Africa/Nairobi", tz);
    timezones.put("Antarctica/Syowa", tz);
    timezones.put("Asia/Aden", tz);
    timezones.put("Asia/Bahrain", tz);
    timezones.put("Asia/Kuwait", tz);
    timezones.put("Asia/Qatar", tz);
    timezones.put("Asia/Riyadh", tz);
    timezones.put("Indian/Antananarivo", tz);
    timezones.put("Indian/Comoro", tz);
    timezones.put("Indian/Mayotte", tz);
    tz = new SimpleTimeZone(3500 * 3600, "Asia/Tehran");
    timezones.put("Asia/Tehran", tz);
    tz = new SimpleTimeZone
      (4000 * 3600, "Asia/Baku",
       Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600);
    timezones.put("Asia/Baku", tz);
    tz = new SimpleTimeZone
      (4000 * 3600, "Asia/Aqtau",
       Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("Asia/Aqtau", tz);
    timezones.put("Asia/Tbilisi", tz);
    tz = new SimpleTimeZone
      (4000 * 3600, "Asia/Yerevan",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Yerevan", tz);
    timezones.put("Europe/Samara", tz);
    tz = new SimpleTimeZone(4000 * 3600, "NET");
    timezones.put("NET", tz);
    timezones.put("Asia/Dubai", tz);
    timezones.put("Asia/Muscat", tz);
    timezones.put("Indian/Mahe", tz);
    timezones.put("Indian/Mauritius", tz);
    timezones.put("Indian/Reunion", tz);
    tz = new SimpleTimeZone(4500 * 3600, "Asia/Kabul");
    timezones.put("Asia/Kabul", tz);
    tz = new SimpleTimeZone
      (5000 * 3600, "Asia/Aqtobe",
       Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("Asia/Aqtobe", tz);
    tz = new SimpleTimeZone
      (5000 * 3600, "Asia/Bishkek",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2500 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2500 * 3600);
    timezones.put("Asia/Bishkek", tz);
    tz = new SimpleTimeZone
      (5000 * 3600, "Asia/Yekaterinburg",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Yekaterinburg", tz);
    tz = new SimpleTimeZone(5000 * 3600, "PLT");
    timezones.put("PLT", tz);
    timezones.put("Asia/Ashgabat", tz);
    timezones.put("Asia/Dushanbe", tz);
    timezones.put("Asia/Karachi", tz);
    timezones.put("Asia/Samarkand", tz);
    timezones.put("Asia/Tashkent", tz);
    timezones.put("Indian/Chagos", tz);
    timezones.put("Indian/Kerguelen", tz);
    timezones.put("Indian/Maldives", tz);
    tz = new SimpleTimeZone(5500 * 3600, "IST");
    timezones.put("IST", tz);
    timezones.put("Asia/Calcutta", tz);
    tz = new SimpleTimeZone(5750 * 3600, "Asia/Katmandu");
    timezones.put("Asia/Katmandu", tz);
    tz = new SimpleTimeZone(6000 * 3600, "BST");
    timezones.put("BST", tz);
    timezones.put("Antarctica/Mawson", tz);
    timezones.put("Asia/Colombo", tz);
    timezones.put("Asia/Dhaka", tz);
    timezones.put("Asia/Thimphu", tz);
    tz = new SimpleTimeZone
      (6000 * 3600, "Asia/Almaty",
       Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600);
    timezones.put("Asia/Almaty", tz);
    tz = new SimpleTimeZone
      (6000 * 3600, "Asia/Novosibirsk",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Novosibirsk", tz);
    timezones.put("Asia/Omsk", tz);
    tz = new SimpleTimeZone(6500 * 3600, "Asia/Rangoon");
    timezones.put("Asia/Rangoon", tz);
    timezones.put("Indian/Cocos", tz);
    tz = new SimpleTimeZone(7000 * 3600, "VST");
    timezones.put("VST", tz);
    timezones.put("Antarctica/Davis", tz);
    timezones.put("Asia/Bangkok", tz);
    timezones.put("Asia/Hovd", tz);
    timezones.put("Asia/Jakarta", tz);
    timezones.put("Asia/Phnom_Penh", tz);
    timezones.put("Asia/Saigon", tz);
    timezones.put("Asia/Vientiane", tz);
    timezones.put("Indian/Christmas", tz);
    tz = new SimpleTimeZone
      (7000 * 3600, "Asia/Krasnoyarsk",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Krasnoyarsk", tz);
    tz = new SimpleTimeZone(8000 * 3600, "CTT");
    timezones.put("CTT", tz);
    timezones.put("Antarctica/Casey", tz);
    timezones.put("Asia/Brunei", tz);
    timezones.put("Asia/Chungking", tz);
    timezones.put("Asia/Harbin", tz);
    timezones.put("Asia/Hong_Kong", tz);
    timezones.put("Asia/Kashgar", tz);
    timezones.put("Asia/Kuala_Lumpur", tz);
    timezones.put("Asia/Kuching", tz);
    timezones.put("Asia/Macao", tz);
    timezones.put("Asia/Manila", tz);
    timezones.put("Asia/Shanghai", tz);
    timezones.put("Asia/Singapore", tz);
    timezones.put("Asia/Taipei", tz);
    timezones.put("Asia/Ujung_Pandang", tz);
    timezones.put("Asia/Ulaanbaatar", tz);
    timezones.put("Asia/Urumqi", tz);
    timezones.put("Australia/Perth", tz);
    tz = new SimpleTimeZone
      (8000 * 3600, "Asia/Irkutsk",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Irkutsk", tz);
    tz = new SimpleTimeZone(9000 * 3600, "JST");
    timezones.put("JST", tz);
    timezones.put("Asia/Dili", tz);
    timezones.put("Asia/Jayapura", tz);
    timezones.put("Asia/Pyongyang", tz);
    timezones.put("Asia/Seoul", tz);
    timezones.put("Asia/Tokyo", tz);
    timezones.put("Pacific/Palau", tz);
    tz = new SimpleTimeZone
      (9000 * 3600, "Asia/Yakutsk",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Yakutsk", tz);
    tz = new SimpleTimeZone
      (9500 * 3600, "Australia/Adelaide",
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Australia/Adelaide", tz);
    timezones.put("Australia/Broken_Hill", tz);
    tz = new SimpleTimeZone(9500 * 3600, "ACT");
    timezones.put("ACT", tz);
    timezones.put("Australia/Darwin", tz);
    tz = new SimpleTimeZone(10000 * 3600, "Antarctica/DumontDUrville");
    timezones.put("Antarctica/DumontDUrville", tz);
    timezones.put("Australia/Brisbane", tz);
    timezones.put("Australia/Lindeman", tz);
    timezones.put("Pacific/Guam", tz);
    timezones.put("Pacific/Port_Moresby", tz);
    timezones.put("Pacific/Saipan", tz);
    timezones.put("Pacific/Truk", tz);
    timezones.put("Pacific/Yap", tz);
    tz = new SimpleTimeZone
      (10000 * 3600, "Asia/Vladivostok",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Vladivostok", tz);
    tz = new SimpleTimeZone
      (10000 * 3600, "Australia/Hobart",
       Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Australia/Hobart", tz);
    tz = new SimpleTimeZone
      (10000 * 3600, "AET",
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("AET", tz);
    timezones.put("Australia/Melbourne", tz);
    timezones.put("Australia/Sydney", tz);
    tz = new SimpleTimeZone
      (10500 * 3600, "Australia/Lord_Howe",
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, 500 * 3600);
    timezones.put("Australia/Lord_Howe", tz);
    tz = new SimpleTimeZone
      (11000 * 3600, "Asia/Magadan",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Magadan", tz);
    tz = new SimpleTimeZone(11000 * 3600, "SST");
    timezones.put("SST", tz);
    timezones.put("Pacific/Efate", tz);
    timezones.put("Pacific/Guadalcanal", tz);
    timezones.put("Pacific/Kosrae", tz);
    timezones.put("Pacific/Noumea", tz);
    timezones.put("Pacific/Ponape", tz);
    tz = new SimpleTimeZone(11500 * 3600, "Pacific/Norfolk");
    timezones.put("Pacific/Norfolk", tz);
    tz = new SimpleTimeZone
      (12000 * 3600, "NST",
       Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.MARCH, 3, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("NST", tz);
    timezones.put("Antarctica/McMurdo", tz);
    timezones.put("Antarctica/South_Pole", tz);
    timezones.put("Pacific/Auckland", tz);
    tz = new SimpleTimeZone
      (12000 * 3600, "Asia/Anadyr",
       Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600,
       Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600);
    timezones.put("Asia/Anadyr", tz);
    timezones.put("Asia/Kamchatka", tz);
    tz = new SimpleTimeZone(12000 * 3600, "Pacific/Fiji");
    timezones.put("Pacific/Fiji", tz);
    timezones.put("Pacific/Funafuti", tz);
    timezones.put("Pacific/Kwajalein", tz);
    timezones.put("Pacific/Majuro", tz);
    timezones.put("Pacific/Nauru", tz);
    timezones.put("Pacific/Tarawa", tz);
    timezones.put("Pacific/Wake", tz);
    timezones.put("Pacific/Wallis", tz);
    tz = new SimpleTimeZone
      (12750 * 3600, "Pacific/Chatham",
       Calendar.OCTOBER, 1, Calendar.SUNDAY, 2750 * 3600,
       Calendar.MARCH, 3, Calendar.SUNDAY, 2750 * 3600);
    timezones.put("Pacific/Chatham", tz);
    tz = new SimpleTimeZone(13000 * 3600, "Pacific/Enderbury");
    timezones.put("Pacific/Enderbury", tz);
    timezones.put("Pacific/Tongatapu", tz);
    tz = new SimpleTimeZone(14000 * 3600, "Pacific/Kiritimati");
    timezones.put("Pacific/Kiritimati", tz);
  }


  /* Look up default timezone */
  static
  {
    if (Configuration.INIT_LOAD_LIBRARY)
      {
	System.loadLibrary("javautil");
      }
    String tzid = System.getProperty("user.timezone");

    if (tzid == null)
      tzid = getDefaultTimeZoneId();

    if (tzid == null)
      tzid = "GMT";

    defaultZone = getTimeZone(tzid);
  }

  /* This method returns us a time zone id string which is in the
     form <standard zone name><GMT offset><daylight time zone name>.
     The GMT offset is in seconds, except where it is evenly divisible
     by 3600, then it is in hours.  If the zone does not observe
     daylight time, then the daylight zone name is omitted.  Examples:
     in Chicago, the timezone would be CST6CDT.  In Indianapolis 
     (which does not have Daylight Savings Time) the string would
     be EST5
   */
  private static native String getDefaultTimeZoneId();

  /**
   * Gets the time zone offset, for current date, modified in case of 
   * daylight savings.  This is the offset to add to UTC to get the local
   * time.
   * @param era the era of the given date
   * @param year the year of the given date
   * @param month the month of the given date, 0 for January.
   * @param day the day of month
   * @param dayOfWeek the day of week
   * @param milliseconds the millis in the day (in local standard time)
   * @return the time zone offset in milliseconds.
   */
  public abstract int getOffset(int era, int year, int month,
				int day, int dayOfWeek, int milliseconds);

  /**
   * Gets the time zone offset, ignoring daylight savings.  This is
   * the offset to add to UTC to get the local time.
   * @return the time zone offset in milliseconds.  
   */
  public abstract int getRawOffset();

  /**
   * Sets the time zone offset, ignoring daylight savings.  This is
   * the offset to add to UTC to get the local time.
   * @param offsetMillis the time zone offset to GMT.
   */
  public abstract void setRawOffset(int offsetMillis);

  /**
   * Gets the identifier of this time zone. For instance, PST for
   * Pacific Standard Time.
   * @returns the ID of this time zone.  
   */
  public String getID()
  {
    return ID;
  }

  /**
   * Sets the identifier of this time zone. For instance, PST for
   * Pacific Standard Time.
   * @param id the new time zone ID.
   */
  public void setID(String id)
  {
    this.ID = id;
  }

  /**
   * This method returns a string name of the time zone suitable
   * for displaying to the user.  The string returned will be the long
   * description of the timezone in the current locale.  The name
   * displayed will assume daylight savings time is not in effect.
   *
   * @return The name of the time zone.
   */
  public final String getDisplayName()
  {
    return (getDisplayName(false, LONG, Locale.getDefault()));
  }

  /**
   * This method returns a string name of the time zone suitable
   * for displaying to the user.  The string returned will be the long
   * description of the timezone in the specified locale. The name
   * displayed will assume daylight savings time is not in effect.
   *
   * @param locale The locale for this timezone name.
   *
   * @return The name of the time zone.
   */
  public final String getDisplayName(Locale locale)
  {
    return (getDisplayName(false, LONG, locale));
  }

  /**
   * This method returns a string name of the time zone suitable
   * for displaying to the user.  The string returned will be of the
   * specified type in the current locale. 
   *
   * @param dst Whether or not daylight savings time is in effect.
   * @param style <code>LONG</code> for a long name, <code>SHORT</code> for
   * a short abbreviation.
   *
   * @return The name of the time zone.
   */
  public final String getDisplayName(boolean dst, int style)
  {
    return (getDisplayName(dst, style, Locale.getDefault()));
  }


  /**
   * This method returns a string name of the time zone suitable
   * for displaying to the user.  The string returned will be of the
   * specified type in the specified locale. 
   *
   * @param dst Whether or not daylight savings time is in effect.
   * @param style <code>LONG</code> for a long name, <code>SHORT</code> for
   * a short abbreviation.
   * @param locale The locale for this timezone name.
   *
   * @return The name of the time zone.
   */
  public String getDisplayName(boolean dst, int style, Locale locale)
  {
    DateFormatSymbols dfs;
    try
      {
	dfs = new DateFormatSymbols(locale);

	// The format of the value returned is defined by us.
	String[][]zoneinfo = dfs.getZoneStrings();
	for (int i = 0; i < zoneinfo.length; i++)
	  {
	    if (zoneinfo[i][0].equals(getID()))
	      {
		if (!dst)
		  {
		    if (style == SHORT)
		      return (zoneinfo[i][2]);
		    else
		      return (zoneinfo[i][1]);
		  }
		else
		  {
		    if (style == SHORT)
		      return (zoneinfo[i][4]);
		    else
		      return (zoneinfo[i][3]);
		  }
	      }
	  }
      }
    catch (MissingResourceException e)
      {
      }

    return getDefaultDisplayName(dst);
  }

  private String getDefaultDisplayName(boolean dst)
  {
    int offset = getRawOffset();
    if (dst && this instanceof SimpleTimeZone)
      {
	// ugly, but this is a design failure of the API:
	// getDisplayName takes a dst parameter even though
	// TimeZone knows nothing about daylight saving offsets.
	offset += ((SimpleTimeZone) this).getDSTSavings();
      }

    StringBuffer sb = new StringBuffer(9);
    sb.append("GMT");
    sb.append(offset >= 0 ? '+' : '-');

    offset = Math.abs(offset) / (1000 * 60);
    int hours = offset / 60;
    int minutes = offset % 60;

    sb.append((char) ('0' + hours / 10)).append((char) ('0' + hours % 10));
    sb.append(':');
    sb.append((char) ('0' + minutes / 10)).append((char) ('0' + minutes % 10));
    return sb.toString();
  }

  /** 
   * Returns true, if this time zone uses Daylight Savings Time.
   */
  public abstract boolean useDaylightTime();

  /**
   * Returns true, if the given date is in Daylight Savings Time in this
   * time zone.
   * @param date the given Date.
   */
  public abstract boolean inDaylightTime(Date date);

  /**
   * Gets the daylight savings offset.  This is a positive offset in
   * milliseconds with respect to standard time.  Typically this
   * is one hour, but for some time zones this may be half an our.
   * <p>The default implementation returns 3600000 milliseconds
   * (one hour) if the time zone uses daylight savings time
   * (as specified by {@link #useDaylightTime()}), otherwise
   * it returns 0.
   * @return the daylight savings offset in milliseconds.
   * @since 1.4
   */
  public int getDSTSavings ()
  {
    return useDaylightTime () ? 3600000 : 0;
  }

  /**
   * Gets the TimeZone for the given ID.
   * @param ID the time zone identifier.
   * @return The time zone for the identifier or GMT, if no such time
   * zone exists.
   */
  // FIXME: XXX: JCL indicates this and other methods are synchronized.
  public static TimeZone getTimeZone(String ID)
  {
    // First check timezones hash
    TimeZone tz = (TimeZone) timezones.get(ID);
    if (tz != null)
      {
	if (tz.getID().equals(ID))
	  return tz;

	// We always return a timezone with the requested ID.
	// This is the same behaviour as with JDK1.2.
	tz = (TimeZone) tz.clone();
	tz.setID(ID);
	// We also save the alias, so that we return the same
	// object again if getTimeZone is called with the same
	// alias.
	timezones.put(ID, tz);
	return tz;
      }

    // See if the ID is really a GMT offset form.
    // Note that GMT is in the table so we know it is different.
    if (ID.startsWith("GMT"))
      {
	int pos = 3;
	int offset_direction = 1;

	if (ID.charAt(pos) == '-')
	  {
	    offset_direction = -1;
	    pos++;
	  }
	else if (ID.charAt(pos) == '+')
	  {
	    pos++;
	  }

	try
	  {
	    int hour, minute;

	    String offset_str = ID.substring(pos);
	    int idx = offset_str.indexOf(":");
	    if (idx != -1)
	      {
		hour = Integer.parseInt(offset_str.substring(0, idx));
		minute = Integer.parseInt(offset_str.substring(idx + 1));
	      }
	    else
	      {
		int offset_length = offset_str.length();
		if (offset_length <= 2)
		  {
		    // Only hour
		    hour = Integer.parseInt(offset_str);
		    minute = 0;
		  }
		else
		  {
		    // hour and minute, not separated by colon
		    hour = Integer.parseInt
		      (offset_str.substring(0, offset_length - 2));
		    minute = Integer.parseInt
		      (offset_str.substring(offset_length - 2));
		  }
	      }

	    return new SimpleTimeZone((hour * (60 * 60 * 1000) +
				       minute * (60 * 1000))
				      * offset_direction, ID);
	  }
	catch (NumberFormatException e)
	  {
	  }
      }

    // Finally, return GMT per spec
    return getTimeZone("GMT");
  }

  /**
   * Gets the available IDs according to the given time zone
   * offset.  
   * @param rawOffset the given time zone GMT offset.
   * @return An array of IDs, where the time zone has the specified GMT
   * offset. For example <code>{"Phoenix", "Denver"}</code>, since both have
   * GMT-07:00, but differ in daylight savings behaviour.
   */
  public static String[] getAvailableIDs(int rawOffset)
  {
    int count = 0;
    Iterator iter = timezones.entrySet().iterator();
    while (iter.hasNext())
      {
	// Don't iterate the values, since we want to count 
	// doubled values (aliases)
	Map.Entry entry = (Map.Entry) iter.next();
	if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset)
	  count++;
      }

    String[] ids = new String[count];
    count = 0;
    iter = timezones.entrySet().iterator();
    while (iter.hasNext())
      {
	Map.Entry entry = (Map.Entry) iter.next();
	if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset)
	  ids[count++] = (String) entry.getKey();
      }
    return ids;
  }

  /**
   * Gets all available IDs.
   * @return An array of all supported IDs.
   */
  public static String[] getAvailableIDs()
  {
    return (String[])
      timezones.keySet().toArray(new String[timezones.size()]);
  }

  /**
   * Returns the time zone under which the host is running.  This
   * can be changed with setDefault.
   * @return the time zone for this host.
   * @see #setDefault
   */
  public static TimeZone getDefault()
  {
    return defaultZone;
  }

  public static void setDefault(TimeZone zone)
  {
    defaultZone = zone;
  }

  /**
   * Test if the other time zone uses the same rule and only
   * possibly differs in ID.  This implementation for this particular
   * class will return true if the raw offsets are identical.  Subclasses
   * should override this method if they use daylight savings.
   * @return true if this zone has the same raw offset
   */
  public boolean hasSameRules(TimeZone other)
  {
    return other.getRawOffset() == getRawOffset();
  }

  /**
   * Returns a clone of this object.  I can't imagine, why this is
   * useful for a time zone.
   */
  public Object clone()
  {
    try
      {
	return super.clone();
      }
    catch (CloneNotSupportedException ex)
      {
	return null;
      }
  }
}
'>6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264
/* Parser for C and Objective-C.
   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
   Free Software Foundation, Inc.

   Parser actions based on the old Bison parser; structure somewhat
   influenced by and fragments based on the C++ parser.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

/* TODO:

   Make sure all relevant comments, and all relevant code from all
   actions, brought over from old parser.  Verify exact correspondence
   of syntax accepted.

   Add testcases covering every input symbol in every state in old and
   new parsers.

   Include full syntax for GNU C, including erroneous cases accepted
   with error messages, in syntax productions in comments.

   Make more diagnostics in the front end generally take an explicit
   location rather than implicitly using input_location.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "langhooks.h"
#include "input.h"
#include "cpplib.h"
#include "timevar.h"
#include "c-pragma.h"
#include "c-tree.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "ggc.h"
#include "c-common.h"
#include "vec.h"
#include "target.h"
#include "cgraph.h"


/* Initialization routine for this file.  */

void
c_parse_init (void)
{
  /* The only initialization required is of the reserved word
     identifiers.  */
  unsigned int i;
  tree id;
  int mask = 0;

  mask |= D_CXXONLY;
  if (!flag_isoc99)
    mask |= D_C99;
  if (flag_no_asm)
    {
      mask |= D_ASM | D_EXT;
      if (!flag_isoc99)
	mask |= D_EXT89;
    }
  if (!c_dialect_objc ())
    mask |= D_OBJC | D_CXX_OBJC;

  ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
  for (i = 0; i < num_c_common_reswords; i++)
    {
      /* If a keyword is disabled, do not enter it into the table
	 and so create a canonical spelling that isn't a keyword.  */
      if (c_common_reswords[i].disable & mask)
	{
	  if (warn_cxx_compat
	      && (c_common_reswords[i].disable & D_CXXWARN))
	    {
	      id = get_identifier (c_common_reswords[i].word);
	      C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN);
	      C_IS_RESERVED_WORD (id) = 1;
	    }
	  continue;
	}

      id = get_identifier (c_common_reswords[i].word);
      C_SET_RID_CODE (id, c_common_reswords[i].rid);
      C_IS_RESERVED_WORD (id) = 1;
      ridpointers [(int) c_common_reswords[i].rid] = id;
    }
}

/* The C lexer intermediates between the lexer in cpplib and c-lex.c
   and the C parser.  Unlike the C++ lexer, the parser structure
   stores the lexer information instead of using a separate structure.
   Identifiers are separated into ordinary identifiers, type names,
   keywords and some other Objective-C types of identifiers, and some
   look-ahead is maintained.

   ??? It might be a good idea to lex the whole file up front (as for
   C++).  It would then be possible to share more of the C and C++
   lexer code, if desired.  */

/* The following local token type is used.  */

/* A keyword.  */
#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))

/* More information about the type of a CPP_NAME token.  */
typedef enum c_id_kind {
  /* An ordinary identifier.  */
  C_ID_ID,
  /* An identifier declared as a typedef name.  */
  C_ID_TYPENAME,
  /* An identifier declared as an Objective-C class name.  */
  C_ID_CLASSNAME,
  /* Not an identifier.  */
  C_ID_NONE
} c_id_kind;

/* A single C token after string literal concatenation and conversion
   of preprocessing tokens to tokens.  */
typedef struct c_token GTY (())
{
  /* The kind of token.  */
  ENUM_BITFIELD (cpp_ttype) type : 8;
  /* If this token is a CPP_NAME, this value indicates whether also
     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
  ENUM_BITFIELD (c_id_kind) id_kind : 8;
  /* If this token is a keyword, this value indicates which keyword.
     Otherwise, this value is RID_MAX.  */
  ENUM_BITFIELD (rid) keyword : 8;
  /* If this token is a CPP_PRAGMA, this indicates the pragma that
     was seen.  Otherwise it is PRAGMA_NONE.  */
  ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
  /* The value associated with this token, if any.  */
  tree value;
  /* The location at which this token was found.  */
  location_t location;
} c_token;

/* A parser structure recording information about the state and
   context of parsing.  Includes lexer information with up to two
   tokens of look-ahead; more are not needed for C.  */
typedef struct c_parser GTY(())
{
  /* The look-ahead tokens.  */
  c_token tokens[2];
  /* How many look-ahead tokens are available (0, 1 or 2).  */
  short tokens_avail;
  /* True if a syntax error is being recovered from; false otherwise.
     c_parser_error sets this flag.  It should clear this flag when
     enough tokens have been consumed to recover from the error.  */
  BOOL_BITFIELD error : 1;
  /* True if we're processing a pragma, and shouldn't automatically
     consume CPP_PRAGMA_EOL.  */
  BOOL_BITFIELD in_pragma : 1;
  /* True if we're parsing the outermost block of an if statement.  */
  BOOL_BITFIELD in_if_block : 1;
  /* True if we want to lex an untranslated string.  */
  BOOL_BITFIELD lex_untranslated_string : 1;
  /* Objective-C specific parser/lexer information.  */
  BOOL_BITFIELD objc_pq_context : 1;
  /* The following flag is needed to contextualize Objective-C lexical
     analysis.  In some cases (e.g., 'int NSObject;'), it is
     undesirable to bind an identifier to an Objective-C class, even
     if a class with that name exists.  */
  BOOL_BITFIELD objc_need_raw_identifier : 1;
} c_parser;


/* The actual parser and external interface.  ??? Does this need to be
   garbage-collected?  */

static GTY (()) c_parser *the_parser;


/* Read in and lex a single token, storing it in *TOKEN.  */

static void
c_lex_one_token (c_parser *parser, c_token *token)
{
  timevar_push (TV_LEX);

  token->type = c_lex_with_flags (&token->value, &token->location, NULL,
				  (parser->lex_untranslated_string
				   ? C_LEX_STRING_NO_TRANSLATE : 0));
  token->id_kind = C_ID_NONE;
  token->keyword = RID_MAX;
  token->pragma_kind = PRAGMA_NONE;

  switch (token->type)
    {
    case CPP_NAME:
      {
	tree decl;

	bool objc_force_identifier = parser->objc_need_raw_identifier;
	if (c_dialect_objc ())
	  parser->objc_need_raw_identifier = false;

	if (C_IS_RESERVED_WORD (token->value))
	  {
	    enum rid rid_code = C_RID_CODE (token->value);

	    if (rid_code == RID_CXX_COMPAT_WARN)
	      {
		warning_at (token->location,
			    OPT_Wc___compat,
			    "identifier %qs conflicts with C++ keyword",
			    IDENTIFIER_POINTER (token->value));
	      }
	    else if (c_dialect_objc ())
	      {
		if (!objc_is_reserved_word (token->value)
		    && (!OBJC_IS_PQ_KEYWORD (rid_code)
			|| parser->objc_pq_context))
		  {
		    /* Return the canonical spelling for this keyword.  */
		    token->value = ridpointers[(int) rid_code];
		    token->type = CPP_KEYWORD;
		    token->keyword = rid_code;
		    break;
		  }
	      }
	    else
	      {
		token->type = CPP_KEYWORD;
		token->keyword = rid_code;
		break;
	      }
	  }

	decl = lookup_name (token->value);
	if (decl)
	  {
	    if (TREE_CODE (decl) == TYPE_DECL)
	      {
		token->id_kind = C_ID_TYPENAME;
		break;
	      }
	  }
	else if (c_dialect_objc ())
	  {
	    tree objc_interface_decl = objc_is_class_name (token->value);
	    /* Objective-C class names are in the same namespace as
	       variables and typedefs, and hence are shadowed by local
	       declarations.  */
	    if (objc_interface_decl
		&& (global_bindings_p ()
		    || (!objc_force_identifier && !decl)))
	      {
		token->value = objc_interface_decl;
		token->id_kind = C_ID_CLASSNAME;
		break;
	      }
	  }
        token->id_kind = C_ID_ID;
      }
      break;
    case CPP_AT_NAME:
      /* This only happens in Objective-C; it must be a keyword.  */
      token->type = CPP_KEYWORD;
      token->keyword = C_RID_CODE (token->value);
      break;
    case CPP_COLON:
    case CPP_COMMA:
    case CPP_CLOSE_PAREN:
    case CPP_SEMICOLON:
      /* These tokens may affect the interpretation of any identifiers
	 following, if doing Objective-C.  */
      if (c_dialect_objc ())
	parser->objc_need_raw_identifier = false;
      break;
    case CPP_PRAGMA:
      /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST.  */
      token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value);
      token->value = NULL;
      break;
    default:
      break;
    }
  timevar_pop (TV_LEX);
}

/* Return a pointer to the next token from PARSER, reading it in if
   necessary.  */

static inline c_token *
c_parser_peek_token (c_parser *parser)
{
  if (parser->tokens_avail == 0)
    {
      c_lex_one_token (parser, &parser->tokens[0]);
      parser->tokens_avail = 1;
    }
  return &parser->tokens[0];
}

/* Return true if the next token from PARSER has the indicated
   TYPE.  */

static inline bool
c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
{
  return c_parser_peek_token (parser)->type == type;
}

/* Return true if the next token from PARSER does not have the
   indicated TYPE.  */

static inline bool
c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
{
  return !c_parser_next_token_is (parser, type);
}

/* Return true if the next token from PARSER is the indicated
   KEYWORD.  */

static inline bool
c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
{
  return c_parser_peek_token (parser)->keyword == keyword;
}

/* Return true if TOKEN can start a type name,
   false otherwise.  */
static bool
c_token_starts_typename (c_token *token)
{
  switch (token->type)
    {
    case CPP_NAME:
      switch (token->id_kind)
	{
	case C_ID_ID:
	  return false;
	case C_ID_TYPENAME:
	  return true;
	case C_ID_CLASSNAME:
	  gcc_assert (c_dialect_objc ());
	  return true;
	default:
	  gcc_unreachable ();
	}
    case CPP_KEYWORD:
      switch (token->keyword)
	{
	case RID_UNSIGNED:
	case RID_LONG:
	case RID_SHORT:
	case RID_SIGNED:
	case RID_COMPLEX:
	case RID_INT:
	case RID_CHAR:
	case RID_FLOAT:
	case RID_DOUBLE:
	case RID_VOID:
	case RID_DFLOAT32:
	case RID_DFLOAT64:
	case RID_DFLOAT128:
	case RID_BOOL:
	case RID_ENUM:
	case RID_STRUCT:
	case RID_UNION:
	case RID_TYPEOF:
	case RID_CONST:
	case RID_VOLATILE:
	case RID_RESTRICT:
	case RID_ATTRIBUTE:
	case RID_FRACT:
	case RID_ACCUM:
	case RID_SAT:
	  return true;
	default:
	  return false;
	}
    case CPP_LESS:
      if (c_dialect_objc ())
	return true;
      return false;
    default:
      return false;
    }
}

/* Return true if the next token from PARSER can start a type name,
   false otherwise.  */
static inline bool
c_parser_next_token_starts_typename (c_parser *parser)
{
  c_token *token = c_parser_peek_token (parser);
  return c_token_starts_typename (token);
}

/* Return true if TOKEN can start declaration specifiers, false
   otherwise.  */
static bool
c_token_starts_declspecs (c_token *token)
{
  switch (token->type)
    {
    case CPP_NAME:
      switch (token->id_kind)
	{
	case C_ID_ID:
	  return false;
	case C_ID_TYPENAME:
	  return true;
	case C_ID_CLASSNAME:
	  gcc_assert (c_dialect_objc ());
	  return true;
	default:
	  gcc_unreachable ();
	}
    case CPP_KEYWORD:
      switch (token->keyword)
	{
	case RID_STATIC:
	case RID_EXTERN:
	case RID_REGISTER:
	case RID_TYPEDEF:
	case RID_INLINE:
	case RID_AUTO:
	case RID_THREAD:
	case RID_UNSIGNED:
	case RID_LONG:
	case RID_SHORT:
	case RID_SIGNED:
	case RID_COMPLEX:
	case RID_INT:
	case RID_CHAR:
	case RID_FLOAT:
	case RID_DOUBLE:
	case RID_VOID:
	case RID_DFLOAT32:
	case RID_DFLOAT64:
	case RID_DFLOAT128:
	case RID_BOOL:
	case RID_ENUM:
	case RID_STRUCT:
	case RID_UNION:
	case RID_TYPEOF:
	case RID_CONST:
	case RID_VOLATILE:
	case RID_RESTRICT:
	case RID_ATTRIBUTE:
	case RID_FRACT:
	case RID_ACCUM:
	case RID_SAT:
	  return true;
	default:
	  return false;
	}
    case CPP_LESS:
      if (c_dialect_objc ())
	return true;
      return false;
    default:
      return false;
    }
}

/* Return true if the next token from PARSER can start declaration
   specifiers, false otherwise.  */
static inline bool
c_parser_next_token_starts_declspecs (c_parser *parser)
{
  c_token *token = c_parser_peek_token (parser);
  return c_token_starts_declspecs (token);
}

/* Return a pointer to the next-but-one token from PARSER, reading it
   in if necessary.  The next token is already read in.  */

static c_token *
c_parser_peek_2nd_token (c_parser *parser)
{
  if (parser->tokens_avail >= 2)
    return &parser->tokens[1];
  gcc_assert (parser->tokens_avail == 1);
  gcc_assert (parser->tokens[0].type != CPP_EOF);
  gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
  c_lex_one_token (parser, &parser->tokens[1]);
  parser->tokens_avail = 2;
  return &parser->tokens[1];
}

/* Consume the next token from PARSER.  */

static void
c_parser_consume_token (c_parser *parser)
{
  gcc_assert (parser->tokens_avail >= 1);
  gcc_assert (parser->tokens[0].type != CPP_EOF);
  gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
  gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
  if (parser->tokens_avail == 2)
    parser->tokens[0] = parser->tokens[1];
  parser->tokens_avail--;
}

/* Expect the current token to be a #pragma.  Consume it and remember
   that we've begun parsing a pragma.  */

static void
c_parser_consume_pragma (c_parser *parser)
{
  gcc_assert (!parser->in_pragma);
  gcc_assert (parser->tokens_avail >= 1);
  gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
  if (parser->tokens_avail == 2)
    parser->tokens[0] = parser->tokens[1];
  parser->tokens_avail--;
  parser->in_pragma = true;
}

/* Update the globals input_location and in_system_header from
   TOKEN.  */
static inline void
c_parser_set_source_position_from_token (c_token *token)
{
  if (token->type != CPP_EOF)
    {
      input_location = token->location;
    }
}

/* Issue a diagnostic of the form
      FILE:LINE: MESSAGE before TOKEN
   where TOKEN is the next token in the input stream of PARSER.
   MESSAGE (specified by the caller) is usually of the form "expected
   OTHER-TOKEN".

   Do not issue a diagnostic if still recovering from an error.

   ??? This is taken from the C++ parser, but building up messages in
   this way is not i18n-friendly and some other approach should be
   used.  */

static void
c_parser_error (c_parser *parser, const char *gmsgid)
{
  c_token *token = c_parser_peek_token (parser);
  if (parser->error)
    return;
  parser->error = true;
  if (!gmsgid)
    return;
  /* This diagnostic makes more sense if it is tagged to the line of
     the token we just peeked at.  */
  c_parser_set_source_position_from_token (token);
  c_parse_error (gmsgid,
		 /* Because c_parse_error does not understand
		    CPP_KEYWORD, keywords are treated like
		    identifiers.  */
		 (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
		 token->value);
}

/* If the next token is of the indicated TYPE, consume it.  Otherwise,
   issue the error MSGID.  If MSGID is NULL then a message has already
   been produced and no message will be produced this time.  Returns
   true if found, false otherwise.  */

static bool
c_parser_require (c_parser *parser,
		  enum cpp_ttype type,
		  const char *msgid)
{
  if (c_parser_next_token_is (parser, type))
    {
      c_parser_consume_token (parser);
      return true;
    }
  else
    {
      c_parser_error (parser, msgid);
      return false;
    }
}

/* If the next token is the indicated keyword, consume it.  Otherwise,
   issue the error MSGID.  Returns true if found, false otherwise.  */

static bool
c_parser_require_keyword (c_parser *parser,
			  enum rid keyword,
			  const char *msgid)
{
  if (c_parser_next_token_is_keyword (parser, keyword))
    {
      c_parser_consume_token (parser);
      return true;
    }
  else
    {
      c_parser_error (parser, msgid);
      return false;
    }
}

/* Like c_parser_require, except that tokens will be skipped until the
   desired token is found.  An error message is still produced if the
   next token is not as expected.  If MSGID is NULL then a message has
   already been produced and no message will be produced this
   time.  */

static void
c_parser_skip_until_found (c_parser *parser,
			   enum cpp_ttype type,
			   const char *msgid)
{
  unsigned nesting_depth = 0;

  if (c_parser_require (parser, type, msgid))
    return;

  /* Skip tokens until the desired token is found.  */
  while (true)
    {
      /* Peek at the next token.  */
      c_token *token = c_parser_peek_token (parser);
      /* If we've reached the token we want, consume it and stop.  */
      if (token->type == type && !nesting_depth)
	{
	  c_parser_consume_token (parser);
	  break;
	}

      /* If we've run out of tokens, stop.  */
      if (token->type == CPP_EOF)
	return;
      if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
	return;
      if (token->type == CPP_OPEN_BRACE
	  || token->type == CPP_OPEN_PAREN
	  || token->type == CPP_OPEN_SQUARE)
	++nesting_depth;
      else if (token->type == CPP_CLOSE_BRACE
	       || token->type == CPP_CLOSE_PAREN
	       || token->type == CPP_CLOSE_SQUARE)
	{
	  if (nesting_depth-- == 0)
	    break;
	}
      /* Consume this token.  */
      c_parser_consume_token (parser);
    }
  parser->error = false;
}

/* Skip tokens until the end of a parameter is found, but do not
   consume the comma, semicolon or closing delimiter.  */

static void
c_parser_skip_to_end_of_parameter (c_parser *parser)
{
  unsigned nesting_depth = 0;

  while (true)
    {
      c_token *token = c_parser_peek_token (parser);
      if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON)
	  && !nesting_depth)
	break;
      /* If we've run out of tokens, stop.  */
      if (token->type == CPP_EOF)
	return;
      if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
	return;
      if (token->type == CPP_OPEN_BRACE
	  || token->type == CPP_OPEN_PAREN
	  || token->type == CPP_OPEN_SQUARE)
	++nesting_depth;
      else if (token->type == CPP_CLOSE_BRACE
	       || token->type == CPP_CLOSE_PAREN
	       || token->type == CPP_CLOSE_SQUARE)
	{
	  if (nesting_depth-- == 0)
	    break;
	}
      /* Consume this token.  */
      c_parser_consume_token (parser);
    }
  parser->error = false;
}

/* Expect to be at the end of the pragma directive and consume an
   end of line marker.  */

static void
c_parser_skip_to_pragma_eol (c_parser *parser)
{
  gcc_assert (parser->in_pragma);
  parser->in_pragma = false;

  if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line"))
    while (true)
      {
	c_token *token = c_parser_peek_token (parser);
	if (token->type == CPP_EOF)
	  break;
	if (token->type == CPP_PRAGMA_EOL)
	  {
	    c_parser_consume_token (parser);
	    break;
	  }
	c_parser_consume_token (parser);
      }

  parser->error = false;
}

/* Skip tokens until we have consumed an entire block, or until we
   have consumed a non-nested ';'.  */

static void
c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
{
  unsigned nesting_depth = 0;
  bool save_error = parser->error;

  while (true)
    {
      c_token *token;

      /* Peek at the next token.  */
      token = c_parser_peek_token (parser);

      switch (token->type)
	{
	case CPP_EOF:
	  return;

	case CPP_PRAGMA_EOL:
	  if (parser->in_pragma)
	    return;
	  break;

	case CPP_SEMICOLON:
	  /* If the next token is a ';', we have reached the
	     end of the statement.  */
	  if (!nesting_depth)
	    {
	      /* Consume the ';'.  */
	      c_parser_consume_token (parser);
	      goto finished;
	    }
	  break;

	case CPP_CLOSE_BRACE:
	  /* If the next token is a non-nested '}', then we have
	     reached the end of the current block.  */
	  if (nesting_depth == 0 || --nesting_depth == 0)
	    {
	      c_parser_consume_token (parser);
	      goto finished;
	    }
	  break;

	case CPP_OPEN_BRACE:
	  /* If it the next token is a '{', then we are entering a new
	     block.  Consume the entire block.  */
	  ++nesting_depth;
	  break;

	case CPP_PRAGMA:
	  /* If we see a pragma, consume the whole thing at once.  We
	     have some safeguards against consuming pragmas willy-nilly.
	     Normally, we'd expect to be here with parser->error set,
	     which disables these safeguards.  But it's possible to get
	     here for secondary error recovery, after parser->error has
	     been cleared.  */
	  c_parser_consume_pragma (parser);
	  c_parser_skip_to_pragma_eol (parser);
	  parser->error = save_error;
	  continue;

	default:
	  break;
	}

      c_parser_consume_token (parser);
    }

 finished:
  parser->error = false;
}

/* CPP's options (initialized by c-opts.c).  */
extern cpp_options *cpp_opts;

/* Save the warning flags which are controlled by __extension__.  */

static inline int
disable_extension_diagnostics (void)
{
  int ret = (pedantic
	     | (warn_pointer_arith << 1)
	     | (warn_traditional << 2)
	     | (flag_iso << 3)
	     | (warn_long_long << 4)
	     | (cpp_opts->warn_long_long << 5));
  cpp_opts->pedantic = pedantic = 0;
  warn_pointer_arith = 0;
  cpp_opts->warn_traditional = warn_traditional = 0;
  flag_iso = 0;
  warn_long_long = 0;
  cpp_opts->warn_long_long = 0;
  return ret;
}

/* Restore the warning flags which are controlled by __extension__.
   FLAGS is the return value from disable_extension_diagnostics.  */

static inline void
restore_extension_diagnostics (int flags)
{
  cpp_opts->pedantic = pedantic = flags & 1;
  warn_pointer_arith = (flags >> 1) & 1;
  cpp_opts->warn_traditional = warn_traditional = (flags >> 2) & 1;
  flag_iso = (flags >> 3) & 1;
  warn_long_long = (flags >> 4) & 1;
  cpp_opts->warn_long_long = (flags >> 5) & 1;
}

/* Possibly kinds of declarator to parse.  */
typedef enum c_dtr_syn {
  /* A normal declarator with an identifier.  */
  C_DTR_NORMAL,
  /* An abstract declarator (maybe empty).  */
  C_DTR_ABSTRACT,
  /* A parameter declarator: may be either, but after a type name does
     not redeclare a typedef name as an identifier if it can
     alternatively be interpreted as a typedef name; see DR#009,
     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
     following DR#249.  For example, given a typedef T, "int T" and
     "int *T" are valid parameter declarations redeclaring T, while
     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
     abstract declarators rather than involving redundant parentheses;
     the same applies with attributes inside the parentheses before
     "T".  */
  C_DTR_PARM
} c_dtr_syn;

static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
				bool);
static struct c_typespec c_parser_enum_specifier (c_parser *);
static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
static tree c_parser_struct_declaration (c_parser *);
static struct c_typespec c_parser_typeof_specifier (c_parser *);
static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
						 bool *);
static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
							c_dtr_syn, bool *);
static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
							      bool,
							      struct c_declarator *);
static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree);
static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
static tree c_parser_simple_asm_expr (c_parser *);
static tree c_parser_attributes (c_parser *);
static struct c_type_name *c_parser_type_name (c_parser *);
static struct c_expr c_parser_initializer (c_parser *);
static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
static void c_parser_initelt (c_parser *);
static void c_parser_initval (c_parser *, struct c_expr *);
static tree c_parser_compound_statement (c_parser *);
static void c_parser_compound_statement_nostart (c_parser *);
static void c_parser_label (c_parser *);
static void c_parser_statement (c_parser *);
static void c_parser_statement_after_labels (c_parser *);
static void c_parser_if_statement (c_parser *);
static void c_parser_switch_statement (c_parser *);
static void c_parser_while_statement (c_parser *);
static void c_parser_do_statement (c_parser *);
static void c_parser_for_statement (c_parser *);
static tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *, bool);
static tree c_parser_asm_clobbers (c_parser *);
static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
static struct c_expr c_parser_conditional_expression (c_parser *,
						      struct c_expr *);
static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
static struct c_expr c_parser_sizeof_expression (c_parser *);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
								   struct c_type_name *);
static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
								struct c_expr);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
static tree c_parser_expr_list (c_parser *, bool);
static void c_parser_omp_construct (c_parser *);
static void c_parser_omp_threadprivate (c_parser *);
static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_flush (c_parser *);
static void c_parser_omp_taskwait (c_parser *);

enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool c_parser_pragma (c_parser *, enum pragma_context);

/* These Objective-C parser functions are only ever called when
   compiling Objective-C.  */
static void c_parser_objc_class_definition (c_parser *);
static void c_parser_objc_class_instance_variables (c_parser *);
static void c_parser_objc_class_declaration (c_parser *);
static void c_parser_objc_alias_declaration (c_parser *);
static void c_parser_objc_protocol_definition (c_parser *);
static enum tree_code c_parser_objc_method_type (c_parser *);
static void c_parser_objc_method_definition (c_parser *);
static void c_parser_objc_methodprotolist (c_parser *);
static void c_parser_objc_methodproto (c_parser *);
static tree c_parser_objc_method_decl (c_parser *);
static tree c_parser_objc_type_name (c_parser *);
static tree c_parser_objc_protocol_refs (c_parser *);
static void c_parser_objc_try_catch_statement (c_parser *);
static void c_parser_objc_synchronized_statement (c_parser *);
static tree c_parser_objc_selector (c_parser *);
static tree c_parser_objc_selector_arg (c_parser *);
static tree c_parser_objc_receiver (c_parser *);
static tree c_parser_objc_message_args (c_parser *);
static tree c_parser_objc_keywordexpr (c_parser *);

/* Parse a translation unit (C90 6.7, C99 6.9).

   translation-unit:
     external-declarations

   external-declarations:
     external-declaration
     external-declarations external-declaration

   GNU extensions:

   translation-unit:
     empty
*/

static void
c_parser_translation_unit (c_parser *parser)
{
  if (c_parser_next_token_is (parser, CPP_EOF))
    {
      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
	       "ISO C forbids an empty translation unit");
    }
  else
    {
      void *obstack_position = obstack_alloc (&parser_obstack, 0);
      do
	{
	  ggc_collect ();
	  c_parser_external_declaration (parser);
	  obstack_free (&parser_obstack, obstack_position);
	}
      while (c_parser_next_token_is_not (parser, CPP_EOF));
    }
}

/* Parse an external declaration (C90 6.7, C99 6.9).

   external-declaration:
     function-definition
     declaration

   GNU extensions:

   external-declaration:
     asm-definition
     ;
     __extension__ external-declaration

   Objective-C:

   external-declaration:
     objc-class-definition
     objc-class-declaration
     objc-alias-declaration
     objc-protocol-definition
     objc-method-definition
     @end
*/

static void
c_parser_external_declaration (c_parser *parser)
{
  int ext;
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_KEYWORD:
      switch (c_parser_peek_token (parser)->keyword)
	{
	case RID_EXTENSION:
	  ext = disable_extension_diagnostics ();
	  c_parser_consume_token (parser);
	  c_parser_external_declaration (parser);
	  restore_extension_diagnostics (ext);
	  break;
	case RID_ASM:
	  c_parser_asm_definition (parser);
	  break;
	case RID_AT_INTERFACE:
	case RID_AT_IMPLEMENTATION:
	  gcc_assert (c_dialect_objc ());
	  c_parser_objc_class_definition (parser);
	  break;
	case RID_CLASS:
	  gcc_assert (c_dialect_objc ());
	  c_parser_objc_class_declaration (parser);
	  break;
	case RID_AT_ALIAS:
	  gcc_assert (c_dialect_objc ());
	  c_parser_objc_alias_declaration (parser);
	  break;
	case RID_AT_PROTOCOL:
	  gcc_assert (c_dialect_objc ());
	  c_parser_objc_protocol_definition (parser);
	  break;
	case RID_AT_END:
	  gcc_assert (c_dialect_objc ());
	  c_parser_consume_token (parser);
	  objc_finish_implementation ();
	  break;
	default:
	  goto decl_or_fndef;
	}
      break;
    case CPP_SEMICOLON:
      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
	       "ISO C does not allow extra %<;%> outside of a function");
      c_parser_consume_token (parser);
      break;
    case CPP_PRAGMA:
      c_parser_pragma (parser, pragma_external);
      break;
    case CPP_PLUS:
    case CPP_MINUS:
      if (c_dialect_objc ())
	{
	  c_parser_objc_method_definition (parser);
	  break;
	}
      /* Else fall through, and yield a syntax error trying to parse
	 as a declaration or function definition.  */
    default:
    decl_or_fndef:
      /* A declaration or a function definition.  We can only tell
	 which after parsing the declaration specifiers, if any, and
	 the first declarator.  */
      c_parser_declaration_or_fndef (parser, true, true, false, true);
      break;
    }
}


/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
   6.7, 6.9.1).  If FNDEF_OK is true, a function definition is
   accepted; otherwise (old-style parameter declarations) only other
   declarations are accepted.  If NESTED is true, we are inside a
   function or parsing old-style parameter declarations; any functions
   encountered are nested functions and declaration specifiers are
   required; otherwise we are at top level and functions are normal
   functions and declaration specifiers may be optional.  If EMPTY_OK
   is true, empty declarations are OK (subject to all other
   constraints); otherwise (old-style parameter declarations) they are
   diagnosed.  If START_ATTR_OK is true, the declaration specifiers
   may start with attributes; otherwise they may not.

   declaration:
     declaration-specifiers init-declarator-list[opt] ;

   function-definition:
     declaration-specifiers[opt] declarator declaration-list[opt]
       compound-statement

   declaration-list:
     declaration
     declaration-list declaration

   init-declarator-list:
     init-declarator
     init-declarator-list , init-declarator

   init-declarator:
     declarator simple-asm-expr[opt] attributes[opt]
     declarator simple-asm-expr[opt] attributes[opt] = initializer

   GNU extensions:

   nested-function-definition:
     declaration-specifiers declarator declaration-list[opt]
       compound-statement

   The simple-asm-expr and attributes are GNU extensions.

   This function does not handle __extension__; that is handled in its
   callers.  ??? Following the old parser, __extension__ may start
   external declarations, declarations in functions and declarations
   at the start of "for" loops, but not old-style parameter
   declarations.

   C99 requires declaration specifiers in a function definition; the
   absence is diagnosed through the diagnosis of implicit int.  In GNU
   C we also allow but diagnose declarations without declaration
   specifiers, but only at top level (elsewhere they conflict with
   other syntax).
   
   OpenMP:
   
   declaration:
     threadprivate-directive  */

static void
c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
			       bool nested, bool start_attr_ok)
{
  struct c_declspecs *specs;
  tree prefix_attrs;
  tree all_prefix_attrs;
  bool diagnosed_no_specs = false;
  location_t here = c_parser_peek_token (parser)->location;

  specs = build_null_declspecs ();
  c_parser_declspecs (parser, specs, true, true, start_attr_ok);
  if (parser->error)
    {
      c_parser_skip_to_end_of_block_or_statement (parser);
      return;
    }
  if (nested && !specs->declspecs_seen_p)
    {
      c_parser_error (parser, "expected declaration specifiers");
      c_parser_skip_to_end_of_block_or_statement (parser);
      return;
    }
  finish_declspecs (specs);
  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
    {
      if (empty_ok)
	shadow_tag (specs);
      else
	{
	  shadow_tag_warned (specs, 1);
	  pedwarn (here, 0, "empty declaration");
	}
      c_parser_consume_token (parser);
      return;
    }
  pending_xref_error ();
  prefix_attrs = specs->attrs;
  all_prefix_attrs = prefix_attrs;
  specs->attrs = NULL_TREE;
  while (true)
    {
      struct c_declarator *declarator;
      bool dummy = false;
      tree fnbody;
      /* Declaring either one or more declarators (in which case we
	 should diagnose if there were no declaration specifiers) or a
	 function definition (in which case the diagnostic for
	 implicit int suffices).  */
      declarator = c_parser_declarator (parser, specs->type_seen_p,
					C_DTR_NORMAL, &dummy);
      if (declarator == NULL)
	{
	  c_parser_skip_to_end_of_block_or_statement (parser);
	  return;
	}
      if (c_parser_next_token_is (parser, CPP_EQ)
	  || c_parser_next_token_is (parser, CPP_COMMA)
	  || c_parser_next_token_is (parser, CPP_SEMICOLON)
	  || c_parser_next_token_is_keyword (parser, RID_ASM)
	  || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
	{
	  tree asm_name = NULL_TREE;
	  tree postfix_attrs = NULL_TREE;
	  if (!diagnosed_no_specs && !specs->declspecs_seen_p)
	    {
	      diagnosed_no_specs = true;
	      pedwarn (here, 0, "data definition has no type or storage class");
	    }
	  /* Having seen a data definition, there cannot now be a
	     function definition.  */
	  fndef_ok = false;
	  if (c_parser_next_token_is_keyword (parser, RID_ASM))
	    asm_name = c_parser_simple_asm_expr (parser);
	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
	    postfix_attrs = c_parser_attributes (parser);
	  if (c_parser_next_token_is (parser, CPP_EQ))
	    {
	      tree d;
	      struct c_expr init;
	      c_parser_consume_token (parser);
	      /* The declaration of the variable is in effect while
		 its initializer is parsed.  */
	      d = start_decl (declarator, specs, true,
			      chainon (postfix_attrs, all_prefix_attrs));
	      if (!d)
		d = error_mark_node;
	      start_init (d, asm_name, global_bindings_p ());
	      init = c_parser_initializer (parser);
	      finish_init ();
	      if (d != error_mark_node)
		{
		  maybe_warn_string_init (TREE_TYPE (d), init);
		  finish_decl (d, init.value, asm_name);
		}
	    }
	  else
	    {
	      tree d = start_decl (declarator, specs, false,
				   chainon (postfix_attrs,
					    all_prefix_attrs));
	      if (d)
		finish_decl (d, NULL_TREE, asm_name);
	    }
	  if (c_parser_next_token_is (parser, CPP_COMMA))
	    {
	      c_parser_consume_token (parser);
	      if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
		all_prefix_attrs = chainon (c_parser_attributes (parser),
					    prefix_attrs);
	      else
		all_prefix_attrs = prefix_attrs;
	      continue;
	    }
	  else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	    {
	      c_parser_consume_token (parser);
	      return;
	    }
	  else
	    {
	      c_parser_error (parser, "expected %<,%> or %<;%>");
	      c_parser_skip_to_end_of_block_or_statement (parser);
	      return;
	    }
	}
      else if (!fndef_ok)
	{
	  c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
			  "%<asm%> or %<__attribute__%>");
	  c_parser_skip_to_end_of_block_or_statement (parser);
	  return;
	}
      /* Function definition (nested or otherwise).  */
      if (nested)
	{
	  pedwarn (here, OPT_pedantic, "ISO C forbids nested functions");
	  c_push_function_context ();
	}
      if (!start_function (specs, declarator, all_prefix_attrs))
	{
	  /* This can appear in many cases looking nothing like a
	     function definition, so we don't give a more specific
	     error suggesting there was one.  */
	  c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
			  "or %<__attribute__%>");
	  if (nested)
	    c_pop_function_context ();
	  break;
	}
      /* Parse old-style parameter declarations.  ??? Attributes are
	 not allowed to start declaration specifiers here because of a
	 syntax conflict between a function declaration with attribute
	 suffix and a function definition with an attribute prefix on
	 first old-style parameter declaration.  Following the old
	 parser, they are not accepted on subsequent old-style
	 parameter declarations either.  However, there is no
	 ambiguity after the first declaration, nor indeed on the
	 first as long as we don't allow postfix attributes after a
	 declarator with a nonempty identifier list in a definition;
	 and postfix attributes have never been accepted here in
	 function definitions either.  */
      while (c_parser_next_token_is_not (parser, CPP_EOF)
	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
	c_parser_declaration_or_fndef (parser, false, false, true, false);
      store_parm_decls ();
      DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
	= c_parser_peek_token (parser)->location;
      fnbody = c_parser_compound_statement (parser);
      if (nested)
	{
	  tree decl = current_function_decl;
	  add_stmt (fnbody);
	  finish_function ();
	  c_pop_function_context ();
	  add_stmt (build_stmt (DECL_EXPR, decl));
	}
      else
	{
	  add_stmt (fnbody);
	  finish_function ();
	}
      break;
    }
}

/* Parse an asm-definition (asm() outside a function body).  This is a
   GNU extension.

   asm-definition:
     simple-asm-expr ;
*/

static void
c_parser_asm_definition (c_parser *parser)
{
  tree asm_str = c_parser_simple_asm_expr (parser);
  if (asm_str)
    cgraph_add_asm_node (asm_str);
  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}

/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
   6.7), adding them to SPECS (which may already include some).
   Storage class specifiers are accepted iff SCSPEC_OK; type
   specifiers are accepted iff TYPESPEC_OK; attributes are accepted at
   the start iff START_ATTR_OK.

   declaration-specifiers:
     storage-class-specifier declaration-specifiers[opt]
     type-specifier declaration-specifiers[opt]
     type-qualifier declaration-specifiers[opt]
     function-specifier declaration-specifiers[opt]

   Function specifiers (inline) are from C99, and are currently
   handled as storage class specifiers, as is __thread.

   C90 6.5.1, C99 6.7.1:
   storage-class-specifier:
     typedef
     extern
     static
     auto
     register

   C99 6.7.4:
   function-specifier:
     inline

   C90 6.5.2, C99 6.7.2:
   type-specifier:
     void
     char
     short
     int
     long
     float
     double
     signed
     unsigned
     _Bool
     _Complex
     [_Imaginary removed in C99 TC2]
     struct-or-union-specifier
     enum-specifier
     typedef-name

   (_Bool and _Complex are new in C99.)

   C90 6.5.3, C99 6.7.3:

   type-qualifier:
     const
     restrict
     volatile

   (restrict is new in C99.)

   GNU extensions:

   declaration-specifiers:
     attributes declaration-specifiers[opt]

   storage-class-specifier:
     __thread

   type-specifier:
     typeof-specifier
     _Decimal32
     _Decimal64
     _Decimal128
     _Fract
     _Accum
     _Sat

  (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
   http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)

   Objective-C:

   type-specifier:
     class-name objc-protocol-refs[opt]
     typedef-name objc-protocol-refs
     objc-protocol-refs
*/

static void
c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
		    bool scspec_ok, bool typespec_ok, bool start_attr_ok)
{
  bool attrs_ok = start_attr_ok;
  bool seen_type = specs->type_seen_p;
  while (c_parser_next_token_is (parser, CPP_NAME)
	 || c_parser_next_token_is (parser, CPP_KEYWORD)
	 || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
    {
      struct c_typespec t;
      tree attrs;
      if (c_parser_next_token_is (parser, CPP_NAME))
	{
	  tree value = c_parser_peek_token (parser)->value;
	  c_id_kind kind = c_parser_peek_token (parser)->id_kind;
	  /* This finishes the specifiers unless a type name is OK, it
	     is declared as a type name and a type name hasn't yet
	     been seen.  */
	  if (!typespec_ok || seen_type
	      || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
	    break;
	  c_parser_consume_token (parser);
	  seen_type = true;
	  attrs_ok = true;
	  if (kind == C_ID_TYPENAME
	      && (!c_dialect_objc ()
		  || c_parser_next_token_is_not (parser, CPP_LESS)))
	    {
	      t.kind = ctsk_typedef;
	      /* For a typedef name, record the meaning, not the name.
		 In case of 'foo foo, bar;'.  */
	      t.spec = lookup_name (value);
	    }
	  else
	    {
	      tree proto = NULL_TREE;
	      gcc_assert (c_dialect_objc ());
	      t.kind = ctsk_objc;
	      if (c_parser_next_token_is (parser, CPP_LESS))
		proto = c_parser_objc_protocol_refs (parser);
	      t.spec = objc_get_protocol_qualified_type (value, proto);
	    }
	  declspecs_add_type (specs, t);
	  continue;
	}
      if (c_parser_next_token_is (parser, CPP_LESS))
	{
	  /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" -
	     nisse@lysator.liu.se.  */
	  tree proto;
	  gcc_assert (c_dialect_objc ());
	  if (!typespec_ok || seen_type)
	    break;
	  proto = c_parser_objc_protocol_refs (parser);
	  t.kind = ctsk_objc;
	  t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
	  declspecs_add_type (specs, t);
	  continue;
	}
      gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
      switch (c_parser_peek_token (parser)->keyword)
	{
	case RID_STATIC:
	case RID_EXTERN:
	case RID_REGISTER:
	case RID_TYPEDEF:
	case RID_INLINE:
	case RID_AUTO:
	case RID_THREAD:
	  if (!scspec_ok)
	    goto out;
	  attrs_ok = true;
	  /* TODO: Distinguish between function specifiers (inline)
	     and storage class specifiers, either here or in
	     declspecs_add_scspec.  */
	  declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
	  c_parser_consume_token (parser);
	  break;
	case RID_UNSIGNED:
	case RID_LONG:
	case RID_SHORT:
	case RID_SIGNED:
	case RID_COMPLEX:
	case RID_INT:
	case RID_CHAR:
	case RID_FLOAT:
	case RID_DOUBLE:
	case RID_VOID:
	case RID_DFLOAT32:
	case RID_DFLOAT64:
	case RID_DFLOAT128:
	case RID_BOOL:
	case RID_FRACT:
	case RID_ACCUM:
	case RID_SAT:
	  if (!typespec_ok)
	    goto out;
	  attrs_ok = true;
	  seen_type = true;
	  if (c_dialect_objc ())
	    parser->objc_need_raw_identifier = true;
	  t.kind = ctsk_resword;
	  t.spec = c_parser_peek_token (parser)->value;
	  declspecs_add_type (specs, t);
	  c_parser_consume_token (parser);
	  break;
	case RID_ENUM:
	  if (!typespec_ok)
	    goto out;
	  attrs_ok = true;
	  seen_type = true;
	  t = c_parser_enum_specifier (parser);
	  declspecs_add_type (specs, t);
	  break;
	case RID_STRUCT:
	case RID_UNION:
	  if (!typespec_ok)
	    goto out;
	  attrs_ok = true;
	  seen_type = true;
	  t = c_parser_struct_or_union_specifier (parser);
	  declspecs_add_type (specs, t);
	  break;
	case RID_TYPEOF:
	  /* ??? The old parser rejected typeof after other type
	     specifiers, but is a syntax error the best way of
	     handling this?  */
	  if (!typespec_ok || seen_type)
	    goto out;
	  attrs_ok = true;
	  seen_type = true;
	  t = c_parser_typeof_specifier (parser);
	  declspecs_add_type (specs, t);
	  break;
	case RID_CONST:
	case RID_VOLATILE:
	case RID_RESTRICT:
	  attrs_ok = true;
	  declspecs_add_qual (specs, c_parser_peek_token (parser)->value);
	  c_parser_consume_token (parser);
	  break;
	case RID_ATTRIBUTE:
	  if (!attrs_ok)
	    goto out;
	  attrs = c_parser_attributes (parser);
	  declspecs_add_attrs (specs, attrs);
	  break;
	default:
	  goto out;
	}
    }
 out: ;
}

/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2).

   enum-specifier:
     enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt]
     enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt]
     enum attributes[opt] identifier

   The form with trailing comma is new in C99.  The forms with
   attributes are GNU extensions.  In GNU C, we accept any expression
   without commas in the syntax (assignment expressions, not just
   conditional expressions); assignment expressions will be diagnosed
   as non-constant.

   enumerator-list:
     enumerator
     enumerator-list , enumerator

   enumerator:
     enumeration-constant
     enumeration-constant = constant-expression
*/

static struct c_typespec
c_parser_enum_specifier (c_parser *parser)
{
  struct c_typespec ret;
  tree attrs;
  tree ident = NULL_TREE;
  location_t ident_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
  c_parser_consume_token (parser);
  attrs = c_parser_attributes (parser);
  /* Set the location in case we create a decl now.  */
  c_parser_set_source_position_from_token (c_parser_peek_token (parser));
  if (c_parser_next_token_is (parser, CPP_NAME))
    {
      ident = c_parser_peek_token (parser)->value;
      ident_loc = c_parser_peek_token (parser)->location;
      c_parser_consume_token (parser);
    }
  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
    {
      /* Parse an enum definition.  */
      struct c_enum_contents the_enum;
      tree type = start_enum (&the_enum, ident);
      tree postfix_attrs;
      /* We chain the enumerators in reverse order, then put them in
	 forward order at the end.  */
      tree values = NULL_TREE;
      c_parser_consume_token (parser);
      while (true)
	{
	  tree enum_id;
	  tree enum_value;
	  tree enum_decl;
	  bool seen_comma;
	  c_token *token;
	  location_t comma_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
	  location_t value_loc;
	  if (c_parser_next_token_is_not (parser, CPP_NAME))
	    {
	      c_parser_error (parser, "expected identifier");
	      c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
	      values = error_mark_node;
	      break;
	    }
	  token = c_parser_peek_token (parser);
	  enum_id = token->value;
	  /* Set the location in case we create a decl now.  */
	  c_parser_set_source_position_from_token (token);
	  value_loc = token->location;
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_EQ))
	    {
	      c_parser_consume_token (parser);
	      value_loc = c_parser_peek_token (parser)->location;
	      enum_value = c_parser_expr_no_commas (parser, NULL).value;
	    }
	  else
	    enum_value = NULL_TREE;
	  enum_decl = build_enumerator (&the_enum, enum_id, enum_value, 
					value_loc);
	  TREE_CHAIN (enum_decl) = values;
	  values = enum_decl;
	  seen_comma = false;
	  if (c_parser_next_token_is (parser, CPP_COMMA))
	    {
	      comma_loc = c_parser_peek_token (parser)->location;
	      seen_comma = true;
	      c_parser_consume_token (parser);
	    }
	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	    {
	      if (seen_comma && !flag_isoc99)
		pedwarn (comma_loc, OPT_pedantic, "comma at end of enumerator list");
	      c_parser_consume_token (parser);
	      break;
	    }
	  if (!seen_comma)
	    {
	      c_parser_error (parser, "expected %<,%> or %<}%>");
	      c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
	      values = error_mark_node;
	      break;
	    }
	}
      postfix_attrs = c_parser_attributes (parser);
      ret.spec = finish_enum (type, nreverse (values),
			      chainon (attrs, postfix_attrs));
      ret.kind = ctsk_tagdef;
      return ret;
    }
  else if (!ident)
    {
      c_parser_error (parser, "expected %<{%>");
      ret.spec = error_mark_node;
      ret.kind = ctsk_tagref;
      return ret;
    }
  ret = parser_xref_tag (ENUMERAL_TYPE, ident);
  /* In ISO C, enumerated types can be referred to only if already
     defined.  */
  if (pedantic && !COMPLETE_TYPE_P (ret.spec))
    {
      gcc_assert (ident);
      pedwarn (ident_loc, OPT_pedantic,
	       "ISO C forbids forward references to %<enum%> types");
    }
  return ret;
}

/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1).

   struct-or-union-specifier:
     struct-or-union attributes[opt] identifier[opt]
       { struct-contents } attributes[opt]
     struct-or-union attributes[opt] identifier

   struct-contents:
     struct-declaration-list

   struct-declaration-list:
     struct-declaration ;
     struct-declaration-list struct-declaration ;

   GNU extensions:

   struct-contents:
     empty
     struct-declaration
     struct-declaration-list struct-declaration

   struct-declaration-list:
     struct-declaration-list ;
     ;

   (Note that in the syntax here, unlike that in ISO C, the semicolons
   are included here rather than in struct-declaration, in order to
   describe the syntax with extra semicolons and missing semicolon at
   end.)

   Objective-C:

   struct-declaration-list:
     @defs ( class-name )

   (Note this does not include a trailing semicolon, but can be
   followed by further declarations, and gets a pedwarn-if-pedantic
   when followed by a semicolon.)  */

static struct c_typespec
c_parser_struct_or_union_specifier (c_parser *parser)
{
  struct c_typespec ret;
  tree attrs;
  tree ident = NULL_TREE;
  enum tree_code code;
  switch (c_parser_peek_token (parser)->keyword)
    {
    case RID_STRUCT:
      code = RECORD_TYPE;
      break;
    case RID_UNION:
      code = UNION_TYPE;
      break;
    default:
      gcc_unreachable ();
    }
  c_parser_consume_token (parser);
  attrs = c_parser_attributes (parser);
  /* Set the location in case we create a decl now.  */
  c_parser_set_source_position_from_token (c_parser_peek_token (parser));
  if (c_parser_next_token_is (parser, CPP_NAME))
    {
      ident = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
    }
  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
    {
      /* Parse a struct or union definition.  Start the scope of the
	 tag before parsing components.  */
      tree type = start_struct (code, ident);
      tree postfix_attrs;
      /* We chain the components in reverse order, then put them in
	 forward order at the end.  Each struct-declaration may
	 declare multiple components (comma-separated), so we must use
	 chainon to join them, although when parsing each
	 struct-declaration we can use TREE_CHAIN directly.

	 The theory behind all this is that there will be more
	 semicolon separated fields than comma separated fields, and
	 so we'll be minimizing the number of node traversals required
	 by chainon.  */
      tree contents = NULL_TREE;
      c_parser_consume_token (parser);
      /* Handle the Objective-C @defs construct,
	 e.g. foo(sizeof(struct{ @defs(ClassName) }));.  */
      if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS))
	{
	  tree name;
	  gcc_assert (c_dialect_objc ());
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    goto end_at_defs;
	  if (c_parser_next_token_is (parser, CPP_NAME)
	      && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)
	    {
	      name = c_parser_peek_token (parser)->value;
	      c_parser_consume_token (parser);
	    }
	  else
	    {
	      c_parser_error (parser, "expected class name");
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      goto end_at_defs;
	    }
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  contents = nreverse (objc_get_class_ivars (name));
	}
    end_at_defs:
      /* Parse the struct-declarations and semicolons.  Problems with
	 semicolons are diagnosed here; empty structures are diagnosed
	 elsewhere.  */
      while (true)
	{
	  tree decls;
	  /* Parse any stray semicolon.  */
	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	    {
	      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
		       "extra semicolon in struct or union specified");
	      c_parser_consume_token (parser);
	      continue;
	    }
	  /* Stop if at the end of the struct or union contents.  */
	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	    {
	      c_parser_consume_token (parser);
	      break;
	    }
	  /* Accept #pragmas at struct scope.  */
	  if (c_parser_next_token_is (parser, CPP_PRAGMA))
	    {
	      c_parser_pragma (parser, pragma_external);
	      continue;
	    }
	  /* Parse some comma-separated declarations, but not the
	     trailing semicolon if any.  */
	  decls = c_parser_struct_declaration (parser);
	  contents = chainon (decls, contents);
	  /* If no semicolon follows, either we have a parse error or
	     are at the end of the struct or union and should
	     pedwarn.  */
	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	    c_parser_consume_token (parser);
	  else
	    {
	      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
		pedwarn (c_parser_peek_token (parser)->location, 0, 
			 "no semicolon at end of struct or union");
	      else
		{
		  c_parser_error (parser, "expected %<;%>");
		  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
		  break;
		}
	    }
	}
      postfix_attrs = c_parser_attributes (parser);
      ret.spec = finish_struct (type, nreverse (contents),
				chainon (attrs, postfix_attrs));
      ret.kind = ctsk_tagdef;
      return ret;
    }
  else if (!ident)
    {
      c_parser_error (parser, "expected %<{%>");
      ret.spec = error_mark_node;
      ret.kind = ctsk_tagref;
      return ret;
    }
  ret = parser_xref_tag (code, ident);
  return ret;
}

/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without*
   the trailing semicolon.

   struct-declaration:
     specifier-qualifier-list struct-declarator-list

   specifier-qualifier-list:
     type-specifier specifier-qualifier-list[opt]
     type-qualifier specifier-qualifier-list[opt]
     attributes specifier-qualifier-list[opt]

   struct-declarator-list:
     struct-declarator
     struct-declarator-list , attributes[opt] struct-declarator

   struct-declarator:
     declarator attributes[opt]
     declarator[opt] : constant-expression attributes[opt]

   GNU extensions:

   struct-declaration:
     __extension__ struct-declaration
     specifier-qualifier-list

   Unlike the ISO C syntax, semicolons are handled elsewhere.  The use
   of attributes where shown is a GNU extension.  In GNU C, we accept
   any expression without commas in the syntax (assignment
   expressions, not just conditional expressions); assignment
   expressions will be diagnosed as non-constant.  */

static tree
c_parser_struct_declaration (c_parser *parser)
{
  struct c_declspecs *specs;
  tree prefix_attrs;
  tree all_prefix_attrs;
  tree decls;
  location_t decl_loc;
  if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
    {
      int ext;
      tree decl;
      ext = disable_extension_diagnostics ();
      c_parser_consume_token (parser);
      decl = c_parser_struct_declaration (parser);
      restore_extension_diagnostics (ext);
      return decl;
    }
  specs = build_null_declspecs ();
  decl_loc = c_parser_peek_token (parser)->location;
  c_parser_declspecs (parser, specs, false, true, true);
  if (parser->error)
    return NULL_TREE;
  if (!specs->declspecs_seen_p)
    {
      c_parser_error (parser, "expected specifier-qualifier-list");
      return NULL_TREE;
    }
  finish_declspecs (specs);
  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
    {
      tree ret;
      if (!specs->type_seen_p)
	{
	  pedwarn (decl_loc, OPT_pedantic, 
		   "ISO C forbids member declarations with no members");
	  shadow_tag_warned (specs, pedantic);
	  ret = NULL_TREE;
	}
      else
	{
	  /* Support for unnamed structs or unions as members of
	     structs or unions (which is [a] useful and [b] supports
	     MS P-SDK).  */
	  tree attrs = NULL;

	  ret = grokfield (c_parser_peek_token (parser)->location,
			   build_id_declarator (NULL_TREE), specs,
			   NULL_TREE, &attrs);
	  if (ret)
	    decl_attributes (&ret, attrs, 0);
	}
      return ret;
    }
  pending_xref_error ();
  prefix_attrs = specs->attrs;
  all_prefix_attrs = prefix_attrs;
  specs->attrs = NULL_TREE;
  decls = NULL_TREE;
  while (true)
    {
      /* Declaring one or more declarators or un-named bit-fields.  */
      struct c_declarator *declarator;
      bool dummy = false;
      if (c_parser_next_token_is (parser, CPP_COLON))
	declarator = build_id_declarator (NULL_TREE);
      else
	declarator = c_parser_declarator (parser, specs->type_seen_p,
					  C_DTR_NORMAL, &dummy);
      if (declarator == NULL)
	{
	  c_parser_skip_to_end_of_block_or_statement (parser);
	  break;
	}
      if (c_parser_next_token_is (parser, CPP_COLON)
	  || c_parser_next_token_is (parser, CPP_COMMA)
	  || c_parser_next_token_is (parser, CPP_SEMICOLON)
	  || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
	  || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
	{
	  tree postfix_attrs = NULL_TREE;
	  tree width = NULL_TREE;
	  tree d;
	  if (c_parser_next_token_is (parser, CPP_COLON))
	    {
	      c_parser_consume_token (parser);
	      width = c_parser_expr_no_commas (parser, NULL).value;
	    }
	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
	    postfix_attrs = c_parser_attributes (parser);
	  d = grokfield (c_parser_peek_token (parser)->location,
			 declarator, specs, width, &all_prefix_attrs);
	  decl_attributes (&d, chainon (postfix_attrs,
					all_prefix_attrs), 0);
	  TREE_CHAIN (d) = decls;
	  decls = d;
	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
	    all_prefix_attrs = chainon (c_parser_attributes (parser),
					prefix_attrs);
	  else
	    all_prefix_attrs = prefix_attrs;
	  if (c_parser_next_token_is (parser, CPP_COMMA))
	    c_parser_consume_token (parser);
	  else if (c_parser_next_token_is (parser, CPP_SEMICOLON)
		   || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	    {
	      /* Semicolon consumed in caller.  */
	      break;
	    }
	  else
	    {
	      c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>");
	      break;
	    }
	}
      else
	{
	  c_parser_error (parser,
			  "expected %<:%>, %<,%>, %<;%>, %<}%> or "
			  "%<__attribute__%>");
	  break;
	}
    }
  return decls;
}

/* Parse a typeof specifier (a GNU extension).

   typeof-specifier:
     typeof ( expression )
     typeof ( type-name )
*/

static struct c_typespec
c_parser_typeof_specifier (c_parser *parser)
{
  struct c_typespec ret;
  ret.kind = ctsk_typeof;
  ret.spec = error_mark_node;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
  c_parser_consume_token (parser);
  skip_evaluation++;
  in_typeof++;
  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      skip_evaluation--;
      in_typeof--;
      return ret;
    }
  if (c_parser_next_token_starts_typename (parser))
    {
      struct c_type_name *type = c_parser_type_name (parser);
      skip_evaluation--;
      in_typeof--;
      if (type != NULL)
	{
	  ret.spec = groktypename (type);
	  pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
	}
    }
  else
    {
      bool was_vm;
      location_t here = c_parser_peek_token (parser)->location;
      struct c_expr expr = c_parser_expression (parser);
      skip_evaluation--;
      in_typeof--;
      if (TREE_CODE (expr.value) == COMPONENT_REF
	  && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
	error_at (here, "%<typeof%> applied to a bit-field");
      ret.spec = TREE_TYPE (expr.value);
      was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
      /* This should be returned with the type so that when the type
	 is evaluated, this can be evaluated.  For now, we avoid
	 evaluation when the context might.  */
      if (!skip_evaluation && was_vm)
	{
	  tree e = expr.value;

	  /* If the expression is not of a type to which we cannot assign a line
	     number, wrap the thing in a no-op NOP_EXPR.  */
	  if (DECL_P (e) || CONSTANT_CLASS_P (e))
	    e = build1 (NOP_EXPR, void_type_node, e);

	  protected_set_expr_location (e, here);

	  add_stmt (e);
	}
      pop_maybe_used (was_vm);
    }
  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
  return ret;
}

/* Parse a declarator, possibly an abstract declarator (C90 6.5.4,
   6.5.5, C99 6.7.5, 6.7.6).  If TYPE_SEEN_P then a typedef name may
   be redeclared; otherwise it may not.  KIND indicates which kind of
   declarator is wanted.  Returns a valid declarator except in the
   case of a syntax error in which case NULL is returned.  *SEEN_ID is
   set to true if an identifier being declared is seen; this is used
   to diagnose bad forms of abstract array declarators and to
   determine whether an identifier list is syntactically permitted.

   declarator:
     pointer[opt] direct-declarator

   direct-declarator:
     identifier
     ( attributes[opt] declarator )
     direct-declarator array-declarator
     direct-declarator ( parameter-type-list )
     direct-declarator ( identifier-list[opt] )

   pointer:
     * type-qualifier-list[opt]
     * type-qualifier-list[opt] pointer

   type-qualifier-list:
     type-qualifier
     attributes
     type-qualifier-list type-qualifier
     type-qualifier-list attributes

   parameter-type-list:
     parameter-list
     parameter-list , ...

   parameter-list:
     parameter-declaration
     parameter-list , parameter-declaration

   parameter-declaration:
     declaration-specifiers declarator attributes[opt]
     declaration-specifiers abstract-declarator[opt] attributes[opt]

   identifier-list:
     identifier
     identifier-list , identifier

   abstract-declarator:
     pointer
     pointer[opt] direct-abstract-declarator

   direct-abstract-declarator:
     ( attributes[opt] abstract-declarator )
     direct-abstract-declarator[opt] array-declarator
     direct-abstract-declarator[opt] ( parameter-type-list[opt] )

   GNU extensions:

   direct-declarator:
     direct-declarator ( parameter-forward-declarations
			 parameter-type-list[opt] )

   direct-abstract-declarator:
     direct-abstract-declarator[opt] ( parameter-forward-declarations
				       parameter-type-list[opt] )

   parameter-forward-declarations:
     parameter-list ;
     parameter-forward-declarations parameter-list ;

   The uses of attributes shown above are GNU extensions.

   Some forms of array declarator are not included in C99 in the
   syntax for abstract declarators; these are disallowed elsewhere.
   This may be a defect (DR#289).

   This function also accepts an omitted abstract declarator as being
   an abstract declarator, although not part of the formal syntax.  */

static struct c_declarator *
c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
		     bool *seen_id)
{
  /* Parse any initial pointer part.  */
  if (c_parser_next_token_is (parser, CPP_MULT))
    {
      struct c_declspecs *quals_attrs = build_null_declspecs ();
      struct c_declarator *inner;
      c_parser_consume_token (parser);
      c_parser_declspecs (parser, quals_attrs, false, false, true);
      inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
      if (inner == NULL)
	return NULL;
      else
	return make_pointer_declarator (quals_attrs, inner);
    }
  /* Now we have a direct declarator, direct abstract declarator or
     nothing (which counts as a direct abstract declarator here).  */
  return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id);
}

/* Parse a direct declarator or direct abstract declarator; arguments
   as c_parser_declarator.  */

static struct c_declarator *
c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
			    bool *seen_id)
{
  /* The direct declarator must start with an identifier (possibly
     omitted) or a parenthesized declarator (possibly abstract).  In
     an ordinary declarator, initial parentheses must start a
     parenthesized declarator.  In an abstract declarator or parameter
     declarator, they could start a parenthesized declarator or a
     parameter list.  To tell which, the open parenthesis and any
     following attributes must be read.  If a declaration specifier
     follows, then it is a parameter list; if the specifier is a
     typedef name, there might be an ambiguity about redeclaring it,
     which is resolved in the direction of treating it as a typedef
     name.  If a close parenthesis follows, it is also an empty
     parameter list, as the syntax does not permit empty abstract
     declarators.  Otherwise, it is a parenthesized declarator (in
     which case the analysis may be repeated inside it, recursively).

     ??? There is an ambiguity in a parameter declaration "int
     (__attribute__((foo)) x)", where x is not a typedef name: it
     could be an abstract declarator for a function, or declare x with
     parentheses.  The proper resolution of this ambiguity needs
     documenting.  At present we follow an accident of the old
     parser's implementation, whereby the first parameter must have
     some declaration specifiers other than just attributes.  Thus as
     a parameter declaration it is treated as a parenthesized
     parameter named x, and as an abstract declarator it is
     rejected.

     ??? Also following the old parser, attributes inside an empty
     parameter list are ignored, making it a list not yielding a
     prototype, rather than giving an error or making it have one
     parameter with implicit type int.

     ??? Also following the old parser, typedef names may be
     redeclared in declarators, but not Objective-C class names.  */

  if (kind != C_DTR_ABSTRACT
      && c_parser_next_token_is (parser, CPP_NAME)
      && ((type_seen_p
	   && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME)
	  || c_parser_peek_token (parser)->id_kind == C_ID_ID))
    {
      struct c_declarator *inner
	= build_id_declarator (c_parser_peek_token (parser)->value);
      *seen_id = true;
      inner->id_loc = c_parser_peek_token (parser)->location;
      c_parser_consume_token (parser);
      return c_parser_direct_declarator_inner (parser, *seen_id, inner);
    }

  if (kind != C_DTR_NORMAL
      && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
    {
      struct c_declarator *inner = build_id_declarator (NULL_TREE);
      return c_parser_direct_declarator_inner (parser, *seen_id, inner);
    }

  /* Either we are at the end of an abstract declarator, or we have
     parentheses.  */

  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    {
      tree attrs;
      struct c_declarator *inner;
      c_parser_consume_token (parser);
      attrs = c_parser_attributes (parser);
      if (kind != C_DTR_NORMAL
	  && (c_parser_next_token_starts_declspecs (parser)
	      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
	{
	  struct c_arg_info *args
	    = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
					 attrs);
	  if (args == NULL)
	    return NULL;
	  else
	    {
	      inner
		= build_function_declarator (args,
					     build_id_declarator (NULL_TREE));
	      return c_parser_direct_declarator_inner (parser, *seen_id,
						       inner);
	    }
	}
      /* A parenthesized declarator.  */
      inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
      if (inner != NULL && attrs != NULL)
	inner = build_attrs_declarator (attrs, inner);
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	{
	  c_parser_consume_token (parser);
	  if (inner == NULL)
	    return NULL;
	  else
	    return c_parser_direct_declarator_inner (parser, *seen_id, inner);
	}
      else
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  return NULL;
	}
    }
  else
    {
      if (kind == C_DTR_NORMAL)
	{
	  c_parser_error (parser, "expected identifier or %<(%>");
	  return NULL;
	}
      else
	return build_id_declarator (NULL_TREE);
    }
}

/* Parse part of a direct declarator or direct abstract declarator,
   given that some (in INNER) has already been parsed; ID_PRESENT is
   true if an identifier is present, false for an abstract
   declarator.  */

static struct c_declarator *
c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
				  struct c_declarator *inner)
{
  /* Parse a sequence of array declarators and parameter lists.  */
  if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
    {
      struct c_declarator *declarator;
      struct c_declspecs *quals_attrs = build_null_declspecs ();
      bool static_seen;
      bool star_seen;
      tree dimen;
      c_parser_consume_token (parser);
      c_parser_declspecs (parser, quals_attrs, false, false, true);
      static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
      if (static_seen)
	c_parser_consume_token (parser);
      if (static_seen && !quals_attrs->declspecs_seen_p)
	c_parser_declspecs (parser, quals_attrs, false, false, true);
      if (!quals_attrs->declspecs_seen_p)
	quals_attrs = NULL;
      /* If "static" is present, there must be an array dimension.
	 Otherwise, there may be a dimension, "*", or no
	 dimension.  */
      if (static_seen)
	{
	  star_seen = false;
	  dimen = c_parser_expr_no_commas (parser, NULL).value;
	}
      else
	{
	  if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
	    {
	      dimen = NULL_TREE;
	      star_seen = false;
	    }
	  else if (c_parser_next_token_is (parser, CPP_MULT))
	    {
	      if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
		{
		  dimen = NULL_TREE;
		  star_seen = true;
		  c_parser_consume_token (parser);
		}
	      else
		{
		  star_seen = false;
		  dimen = c_parser_expr_no_commas (parser, NULL).value;
		}
	    }
	  else
	    {
	      star_seen = false;
	      dimen = c_parser_expr_no_commas (parser, NULL).value;
	    }
	}
      if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
	c_parser_consume_token (parser);
      else
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
				     "expected %<]%>");
	  return NULL;
	}
      declarator = build_array_declarator (dimen, quals_attrs, static_seen,
					   star_seen);
      if (declarator == NULL)
	return NULL;
      inner = set_array_declarator_inner (declarator, inner);
      return c_parser_direct_declarator_inner (parser, id_present, inner);
    }
  else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    {
      tree attrs;
      struct c_arg_info *args;
      c_parser_consume_token (parser);
      attrs = c_parser_attributes (parser);
      args = c_parser_parms_declarator (parser, id_present, attrs);
      if (args == NULL)
	return NULL;
      else
	{
	  inner = build_function_declarator (args, inner);
	  return c_parser_direct_declarator_inner (parser, id_present, inner);
	}
    }
  return inner;
}

/* Parse a parameter list or identifier list, including the closing
   parenthesis but not the opening one.  ATTRS are the attributes at
   the start of the list.  ID_LIST_OK is true if an identifier list is
   acceptable; such a list must not have attributes at the start.  */

static struct c_arg_info *
c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
{
  push_scope ();
  declare_parm_level ();
  /* If the list starts with an identifier, it is an identifier list.
     Otherwise, it is either a prototype list or an empty list.  */
  if (id_list_ok
      && !attrs
      && c_parser_next_token_is (parser, CPP_NAME)
      && c_parser_peek_token (parser)->id_kind == C_ID_ID)
    {
      tree list = NULL_TREE, *nextp = &list;
      while (c_parser_next_token_is (parser, CPP_NAME)
	     && c_parser_peek_token (parser)->id_kind == C_ID_ID)
	{
	  *nextp = build_tree_list (NULL_TREE,
				    c_parser_peek_token (parser)->value);
	  nextp = & TREE_CHAIN (*nextp);
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is_not (parser, CPP_COMMA))
	    break;
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	    {
	      c_parser_error (parser, "expected identifier");
	      break;
	    }
	}
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	{
	  struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
	  ret->parms = 0;
	  ret->tags = 0;
	  ret->types = list;
	  ret->others = 0;
	  ret->pending_sizes = 0;
	  ret->had_vla_unspec = 0;
	  c_parser_consume_token (parser);
	  pop_scope ();
	  return ret;
	}
      else
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  pop_scope ();
	  return NULL;
	}
    }
  else
    {
      struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs);
      pop_scope ();
      return ret;
    }
}

/* Parse a parameter list (possibly empty), including the closing
   parenthesis but not the opening one.  ATTRS are the attributes at
   the start of the list.  */

static struct c_arg_info *
c_parser_parms_list_declarator (c_parser *parser, tree attrs)
{
  bool good_parm = false;
  /* ??? Following the old parser, forward parameter declarations may
     use abstract declarators, and if no real parameter declarations
     follow the forward declarations then this is not diagnosed.  Also
     note as above that attributes are ignored as the only contents of
     the parentheses, or as the only contents after forward
     declarations.  */
  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
    {
      struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
      ret->parms = 0;
      ret->tags = 0;
      ret->types = 0;
      ret->others = 0;
      ret->pending_sizes = 0;
      ret->had_vla_unspec = 0;
      c_parser_consume_token (parser);
      return ret;
    }
  if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
    {
      struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
      ret->parms = 0;
      ret->tags = 0;
      ret->others = 0;
      ret->pending_sizes = 0;
      ret->had_vla_unspec = 0;
      /* Suppress -Wold-style-definition for this case.  */
      ret->types = error_mark_node;
      error_at (c_parser_peek_token (parser)->location,
		"ISO C requires a named argument before %<...%>");
      c_parser_consume_token (parser);
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	{
	  c_parser_consume_token (parser);
	  return ret;
	}
      else
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  return NULL;
	}
    }
  /* Nonempty list of parameters, either terminated with semicolon
     (forward declarations; recurse) or with close parenthesis (normal
     function) or with ", ... )" (variadic function).  */
  while (true)
    {
      /* Parse a parameter.  */
      struct c_parm *parm = c_parser_parameter_declaration (parser, attrs);
      attrs = NULL_TREE;
      if (parm != NULL)
	{
	  good_parm = true;
	  push_parm_decl (parm);
	}
      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	{
	  tree new_attrs;
	  c_parser_consume_token (parser);
	  mark_forward_parm_decls ();
	  new_attrs = c_parser_attributes (parser);
	  return c_parser_parms_list_declarator (parser, new_attrs);
	}
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	{
	  c_parser_consume_token (parser);
	  if (good_parm)
	    return get_parm_info (false);
	  else
	    {
	      struct c_arg_info *ret
		= XOBNEW (&parser_obstack, struct c_arg_info);
	      ret->parms = 0;
	      ret->tags = 0;
	      ret->types = 0;
	      ret->others = 0;
	      ret->pending_sizes = 0;
	      ret->had_vla_unspec = 0;
	      return ret;
	    }
	}
      if (!c_parser_require (parser, CPP_COMMA,
			     "expected %<;%>, %<,%> or %<)%>"))
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	  get_pending_sizes ();
	  return NULL;
	}
      if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
	{
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	    {
	      c_parser_consume_token (parser);
	      if (good_parm)
		return get_parm_info (true);
	      else
		{
		  struct c_arg_info *ret
		    = XOBNEW (&parser_obstack, struct c_arg_info);
		  ret->parms = 0;
		  ret->tags = 0;
		  ret->types = 0;
		  ret->others = 0;
		  ret->pending_sizes = 0;
		  ret->had_vla_unspec = 0;
		  return ret;
		}
	    }
	  else
	    {
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
					 "expected %<)%>");
	      get_pending_sizes ();
	      return NULL;
	    }
	}
    }
}

/* Parse a parameter declaration.  ATTRS are the attributes at the
   start of the declaration if it is the first parameter.  */

static struct c_parm *
c_parser_parameter_declaration (c_parser *parser, tree attrs)
{
  struct c_declspecs *specs;
  struct c_declarator *declarator;
  tree prefix_attrs;
  tree postfix_attrs = NULL_TREE;
  bool dummy = false;
  if (!c_parser_next_token_starts_declspecs (parser))
    {
      /* ??? In some Objective-C cases '...' isn't applicable so there
	 should be a different message.  */
      c_parser_error (parser,
		      "expected declaration specifiers or %<...%>");
      c_parser_skip_to_end_of_parameter (parser);
      return NULL;
    }
  specs = build_null_declspecs ();
  if (attrs)
    {
      declspecs_add_attrs (specs, attrs);
      attrs = NULL_TREE;
    }
  c_parser_declspecs (parser, specs, true, true, true);
  finish_declspecs (specs);
  pending_xref_error ();
  prefix_attrs = specs->attrs;
  specs->attrs = NULL_TREE;
  declarator = c_parser_declarator (parser, specs->type_seen_p,
				    C_DTR_PARM, &dummy);
  if (declarator == NULL)
    {
      c_parser_skip_until_found (parser, CPP_COMMA, NULL);
      return NULL;
    }
  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
    postfix_attrs = c_parser_attributes (parser);
  return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
		       declarator);
}

/* Parse a string literal in an asm expression.  It should not be
   translated, and wide string literals are an error although
   permitted by the syntax.  This is a GNU extension.

   asm-string-literal:
     string-literal

   ??? At present, following the old parser, the caller needs to have
   set lex_untranslated_string to 1.  It would be better to follow the
   C++ parser rather than using this kludge.  */

static tree
c_parser_asm_string_literal (c_parser *parser)
{
  tree str;
  if (c_parser_next_token_is (parser, CPP_STRING))
    {
      str = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
    }
  else if (c_parser_next_token_is (parser, CPP_WSTRING))
    {
      error_at (c_parser_peek_token (parser)->location,
		"wide string literal in %<asm%>");
      str = build_string (1, "");
      c_parser_consume_token (parser);
    }
  else
    {
      c_parser_error (parser, "expected string literal");
      str = NULL_TREE;
    }
  return str;
}

/* Parse a simple asm expression.  This is used in restricted
   contexts, where a full expression with inputs and outputs does not
   make sense.  This is a GNU extension.

   simple-asm-expr:
     asm ( asm-string-literal )
*/

static tree
c_parser_simple_asm_expr (c_parser *parser)
{
  tree str;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
  /* ??? Follow the C++ parser rather than using the
     lex_untranslated_string kludge.  */
  parser->lex_untranslated_string = true;
  c_parser_consume_token (parser);
  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      parser->lex_untranslated_string = false;
      return NULL_TREE;
    }
  str = c_parser_asm_string_literal (parser);
  parser->lex_untranslated_string = false;
  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
    {
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
      return NULL_TREE;
    }
  return str;
}

/* Parse (possibly empty) attributes.  This is a GNU extension.

   attributes:
     empty
     attributes attribute

   attribute:
     __attribute__ ( ( attribute-list ) )

   attribute-list:
     attrib
     attribute_list , attrib

   attrib:
     empty
     any-word
     any-word ( identifier )
     any-word ( identifier , nonempty-expr-list )
     any-word ( expr-list )

   where the "identifier" must not be declared as a type, and
   "any-word" may be any identifier (including one declared as a
   type), a reserved word storage class specifier, type specifier or
   type qualifier.  ??? This still leaves out most reserved keywords
   (following the old parser), shouldn't we include them, and why not
   allow identifiers declared as types to start the arguments?  */

static tree
c_parser_attributes (c_parser *parser)
{
  tree attrs = NULL_TREE;
  while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
    {
      /* ??? Follow the C++ parser rather than using the
	 lex_untranslated_string kludge.  */
      parser->lex_untranslated_string = true;
      c_parser_consume_token (parser);
      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	{
	  parser->lex_untranslated_string = false;
	  return attrs;
	}
      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	{
	  parser->lex_untranslated_string = false;
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	  return attrs;
	}
      /* Parse the attribute list.  */
      while (c_parser_next_token_is (parser, CPP_COMMA)
	     || c_parser_next_token_is (parser, CPP_NAME)
	     || c_parser_next_token_is (parser, CPP_KEYWORD))
	{
	  tree attr, attr_name, attr_args;
	  if (c_parser_next_token_is (parser, CPP_COMMA))
	    {
	      c_parser_consume_token (parser);
	      continue;
	    }
	  if (c_parser_next_token_is (parser, CPP_KEYWORD))
	    {
	      /* ??? See comment above about what keywords are
		 accepted here.  */
	      bool ok;
	      switch (c_parser_peek_token (parser)->keyword)
		{
		case RID_STATIC:
		case RID_UNSIGNED:
		case RID_LONG:
		case RID_CONST:
		case RID_EXTERN:
		case RID_REGISTER:
		case RID_TYPEDEF:
		case RID_SHORT:
		case RID_INLINE:
		case RID_VOLATILE:
		case RID_SIGNED:
		case RID_AUTO:
		case RID_RESTRICT:
		case RID_COMPLEX:
		case RID_THREAD:
		case RID_INT:
		case RID_CHAR:
		case RID_FLOAT:
		case RID_DOUBLE:
		case RID_VOID:
		case RID_DFLOAT32:
		case RID_DFLOAT64:
		case RID_DFLOAT128:
		case RID_BOOL:
		case RID_FRACT:
		case RID_ACCUM:
		case RID_SAT:
		  ok = true;
		  break;
		default:
		  ok = false;
		  break;
		}
	      if (!ok)
		break;
	      /* Accept __attribute__((__const)) as __attribute__((const))
		 etc.  */
	      attr_name
		= ridpointers[(int) c_parser_peek_token (parser)->keyword];
	    }
	  else
	    attr_name = c_parser_peek_token (parser)->value;
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
	    {
	      attr = build_tree_list (attr_name, NULL_TREE);
	      attrs = chainon (attrs, attr);
	      continue;
	    }
	  c_parser_consume_token (parser);
	  /* Parse the attribute contents.  If they start with an
	     identifier which is followed by a comma or close
	     parenthesis, then the arguments start with that
	     identifier; otherwise they are an expression list.  */
	  if (c_parser_next_token_is (parser, CPP_NAME)
	      && c_parser_peek_token (parser)->id_kind == C_ID_ID
	      && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
		  || (c_parser_peek_2nd_token (parser)->type
		      == CPP_CLOSE_PAREN)))
	    {
	      tree arg1 = c_parser_peek_token (parser)->value;
	      c_parser_consume_token (parser);
	      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
		attr_args = build_tree_list (NULL_TREE, arg1);
	      else
		{
		  c_parser_consume_token (parser);
		  attr_args = tree_cons (NULL_TREE, arg1,
					 c_parser_expr_list (parser, false));
		}
	    }
	  else
	    {
	      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
		attr_args = NULL_TREE;
	      else
		attr_args = c_parser_expr_list (parser, false);
	    }
	  attr = build_tree_list (attr_name, attr_args);
	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	    c_parser_consume_token (parser);
	  else
	    {
	      parser->lex_untranslated_string = false;
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
					 "expected %<)%>");
	      return attrs;
	    }
	  attrs = chainon (attrs, attr);
	}
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	c_parser_consume_token (parser);
      else
	{
	  parser->lex_untranslated_string = false;
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  return attrs;
	}
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	c_parser_consume_token (parser);
      else
	{
	  parser->lex_untranslated_string = false;
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  return attrs;
	}
      parser->lex_untranslated_string = false;
    }
  return attrs;
}

/* Parse a type name (C90 6.5.5, C99 6.7.6).

   type-name:
     specifier-qualifier-list abstract-declarator[opt]
*/

static struct c_type_name *
c_parser_type_name (c_parser *parser)
{
  struct c_declspecs *specs = build_null_declspecs ();
  struct c_declarator *declarator;
  struct c_type_name *ret;
  bool dummy = false;
  c_parser_declspecs (parser, specs, false, true, true);
  if (!specs->declspecs_seen_p)
    {
      c_parser_error (parser, "expected specifier-qualifier-list");
      return NULL;
    }
  pending_xref_error ();
  finish_declspecs (specs);
  declarator = c_parser_declarator (parser, specs->type_seen_p,
				    C_DTR_ABSTRACT, &dummy);
  if (declarator == NULL)
    return NULL;
  ret = XOBNEW (&parser_obstack, struct c_type_name);
  ret->specs = specs;
  ret->declarator = declarator;
  return ret;
}

/* Parse an initializer (C90 6.5.7, C99 6.7.8).

   initializer:
     assignment-expression
     { initializer-list }
     { initializer-list , }

   initializer-list:
     designation[opt] initializer
     initializer-list , designation[opt] initializer

   designation:
     designator-list =

   designator-list:
     designator
     designator-list designator

   designator:
     array-designator
     . identifier

   array-designator:
     [ constant-expression ]

   GNU extensions:

   initializer:
     { }

   designation:
     array-designator
     identifier :

   array-designator:
     [ constant-expression ... constant-expression ]

   Any expression without commas is accepted in the syntax for the
   constant-expressions, with non-constant expressions rejected later.

   This function is only used for top-level initializers; for nested
   ones, see c_parser_initval.  */

static struct c_expr
c_parser_initializer (c_parser *parser)
{
  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
    return c_parser_braced_init (parser, NULL_TREE, false);
  else
    {
      struct c_expr ret;
      ret = c_parser_expr_no_commas (parser, NULL);
      if (TREE_CODE (ret.value) != STRING_CST
	  && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
	ret = default_function_array_conversion (ret);
      return ret;
    }
}

/* Parse a braced initializer list.  TYPE is the type specified for a
   compound literal, and NULL_TREE for other initializers and for
   nested braced lists.  NESTED_P is true for nested braced lists,
   false for the list of a compound literal or the list that is the
   top-level initializer in a declaration.  */

static struct c_expr
c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
{
  location_t brace_loc = c_parser_peek_token (parser)->location;
  gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
  c_parser_consume_token (parser);
  if (nested_p)
    push_init_level (0);
  else
    really_start_incremental_init (type);
  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
    {
      pedwarn (brace_loc, OPT_pedantic, "ISO C forbids empty initializer braces");
    }
  else
    {
      /* Parse a non-empty initializer list, possibly with a trailing
	 comma.  */
      while (true)
	{
	  c_parser_initelt (parser);
	  if (parser->error)
	    break;
	  if (c_parser_next_token_is (parser, CPP_COMMA))
	    c_parser_consume_token (parser);
	  else
	    break;
	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	    break;
	}
    }
  if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
    {
      struct c_expr ret;
      ret.value = error_mark_node;
      ret.original_code = ERROR_MARK;
      c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>");
      pop_init_level (0);
      return ret;
    }
  c_parser_consume_token (parser);
  return pop_init_level (0);
}

/* Parse a nested initializer, including designators.  */

static void
c_parser_initelt (c_parser *parser)
{
  /* Parse any designator or designator list.  A single array
     designator may have the subsequent "=" omitted in GNU C, but a
     longer list or a structure member designator may not.  */
  if (c_parser_next_token_is (parser, CPP_NAME)
      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
    {
      /* Old-style structure member designator.  */
      set_init_label (c_parser_peek_token (parser)->value);
      /* Use the colon as the error location.  */
      pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic, 
	       "obsolete use of designated initializer with %<:%>");
      c_parser_consume_token (parser);
      c_parser_consume_token (parser);
    }
  else
    {
      /* des_seen is 0 if there have been no designators, 1 if there
	 has been a single array designator and 2 otherwise.  */
      int des_seen = 0;
      /* Location of a designator.  */
      location_t des_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
      while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)
	     || c_parser_next_token_is (parser, CPP_DOT))
	{
	  int des_prev = des_seen;
	  if (!des_seen)
	    des_loc = c_parser_peek_token (parser)->location;
	  if (des_seen < 2)
	    des_seen++;
	  if (c_parser_next_token_is (parser, CPP_DOT))
	    {
	      des_seen = 2;
	      c_parser_consume_token (parser);
	      if (c_parser_next_token_is (parser, CPP_NAME))
		{
		  set_init_label (c_parser_peek_token (parser)->value);
		  c_parser_consume_token (parser);
		}
	      else
		{
		  struct c_expr init;
		  init.value = error_mark_node;
		  init.original_code = ERROR_MARK;
		  c_parser_error (parser, "expected identifier");
		  c_parser_skip_until_found (parser, CPP_COMMA, NULL);
		  process_init_element (init, false);
		  return;
		}
	    }
	  else
	    {
	      tree first, second;
	      location_t ellipsis_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
	      /* ??? Following the old parser, [ objc-receiver
		 objc-message-args ] is accepted as an initializer,
		 being distinguished from a designator by what follows
		 the first assignment expression inside the square
		 brackets, but after a first array designator a
		 subsequent square bracket is for Objective-C taken to
		 start an expression, using the obsolete form of
		 designated initializer without '=', rather than
		 possibly being a second level of designation: in LALR
		 terms, the '[' is shifted rather than reducing
		 designator to designator-list.  */
	      if (des_prev == 1 && c_dialect_objc ())
		{
		  des_seen = des_prev;
		  break;
		}
	      if (des_prev == 0 && c_dialect_objc ())
		{
		  /* This might be an array designator or an
		     Objective-C message expression.  If the former,
		     continue parsing here; if the latter, parse the
		     remainder of the initializer given the starting
		     primary-expression.  ??? It might make sense to
		     distinguish when des_prev == 1 as well; see
		     previous comment.  */
		  tree rec, args;
		  struct c_expr mexpr;
		  c_parser_consume_token (parser);
		  if (c_parser_peek_token (parser)->type == CPP_NAME
		      && ((c_parser_peek_token (parser)->id_kind
			   == C_ID_TYPENAME)
			  || (c_parser_peek_token (parser)->id_kind
			      == C_ID_CLASSNAME)))
		    {
		      /* Type name receiver.  */
		      tree id = c_parser_peek_token (parser)->value;
		      c_parser_consume_token (parser);
		      rec = objc_get_class_reference (id);
		      goto parse_message_args;
		    }
		  first = c_parser_expr_no_commas (parser, NULL).value;
		  if (c_parser_next_token_is (parser, CPP_ELLIPSIS)
		      || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
		    goto array_desig_after_first;
		  /* Expression receiver.  So far only one part
		     without commas has been parsed; there might be
		     more of the expression.  */
		  rec = first;
		  while (c_parser_next_token_is (parser, CPP_COMMA))
		    {
		      struct c_expr next;
		      c_parser_consume_token (parser);
		      next = c_parser_expr_no_commas (parser, NULL);
		      next = default_function_array_conversion (next);
		      rec = build_compound_expr (rec, next.value);
		    }
		parse_message_args:
		  /* Now parse the objc-message-args.  */
		  args = c_parser_objc_message_args (parser);
		  c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
					     "expected %<]%>");
		  mexpr.value
		    = objc_build_message_expr (build_tree_list (rec, args));
		  mexpr.original_code = ERROR_MARK;
		  /* Now parse and process the remainder of the
		     initializer, starting with this message
		     expression as a primary-expression.  */
		  c_parser_initval (parser, &mexpr);
		  return;
		}
	      c_parser_consume_token (parser);
	      first = c_parser_expr_no_commas (parser, NULL).value;
	    array_desig_after_first:
	      if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
		{
		  ellipsis_loc = c_parser_peek_token (parser)->location;
		  c_parser_consume_token (parser);
		  second = c_parser_expr_no_commas (parser, NULL).value;
		}
	      else
		second = NULL_TREE;
	      if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
		{
		  c_parser_consume_token (parser);
		  set_init_index (first, second);
		  if (second)
		    pedwarn (ellipsis_loc, OPT_pedantic, 
			     "ISO C forbids specifying range of elements to initialize");
		}
	      else
		c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
					   "expected %<]%>");
	    }
	}
      if (des_seen >= 1)
	{
	  if (c_parser_next_token_is (parser, CPP_EQ))
	    {
	      if (!flag_isoc99)
		pedwarn (des_loc, OPT_pedantic, 
			 "ISO C90 forbids specifying subobject to initialize");
	      c_parser_consume_token (parser);
	    }
	  else
	    {
	      if (des_seen == 1)
		pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
			 "obsolete use of designated initializer without %<=%>");
	      else
		{
		  struct c_expr init;
		  init.value = error_mark_node;
		  init.original_code = ERROR_MARK;
		  c_parser_error (parser, "expected %<=%>");
		  c_parser_skip_until_found (parser, CPP_COMMA, NULL);
		  process_init_element (init, false);
		  return;
		}
	    }
	}
    }
  c_parser_initval (parser, NULL);
}

/* Parse a nested initializer; as c_parser_initializer but parses
   initializers within braced lists, after any designators have been
   applied.  If AFTER is not NULL then it is an Objective-C message
   expression which is the primary-expression starting the
   initializer.  */

static void
c_parser_initval (c_parser *parser, struct c_expr *after)
{
  struct c_expr init;
  gcc_assert (!after || c_dialect_objc ());
  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
    init = c_parser_braced_init (parser, NULL_TREE, true);
  else
    {
      init = c_parser_expr_no_commas (parser, after);
      if (init.value != NULL_TREE
	  && TREE_CODE (init.value) != STRING_CST
	  && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
	init = default_function_array_conversion (init);
    }
  process_init_element (init, false);
}

/* Parse a compound statement (possibly a function body) (C90 6.6.2,
   C99 6.8.2).

   compound-statement:
     { block-item-list[opt] }
     { label-declarations block-item-list }

   block-item-list:
     block-item
     block-item-list block-item

   block-item:
     nested-declaration
     statement

   nested-declaration:
     declaration

   GNU extensions:

   compound-statement:
     { label-declarations block-item-list }

   nested-declaration:
     __extension__ nested-declaration
     nested-function-definition

   label-declarations:
     label-declaration
     label-declarations label-declaration

   label-declaration:
     __label__ identifier-list ;

   Allowing the mixing of declarations and code is new in C99.  The
   GNU syntax also permits (not shown above) labels at the end of
   compound statements, which yield an error.  We don't allow labels
   on declarations; this might seem like a natural extension, but
   there would be a conflict between attributes on the label and
   prefix attributes on the declaration.  ??? The syntax follows the
   old parser in requiring something after label declarations.
   Although they are erroneous if the labels declared aren't defined,
   is it useful for the syntax to be this way?
   
   OpenMP:
   
   block-item:
     openmp-directive

   openmp-directive:
     barrier-directive
     flush-directive  */

static tree
c_parser_compound_statement (c_parser *parser)
{
  tree stmt;
  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
    {
      /* Ensure a scope is entered and left anyway to avoid confusion
	 if we have just prepared to enter a function body.  */
      stmt = c_begin_compound_stmt (true);
      c_end_compound_stmt (stmt, true);
      return error_mark_node;
    }
  stmt = c_begin_compound_stmt (true);
  c_parser_compound_statement_nostart (parser);
  return c_end_compound_stmt (stmt, true);
}

/* Parse a compound statement except for the opening brace.  This is
   used for parsing both compound statements and statement expressions
   (which follow different paths to handling the opening).  */

static void
c_parser_compound_statement_nostart (c_parser *parser)
{
  bool last_stmt = false;
  bool last_label = false;
  location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
    {
      c_parser_consume_token (parser);
      return;
    }
  if (c_parser_next_token_is_keyword (parser, RID_LABEL))
    {
      location_t err_loc = c_parser_peek_token (parser)->location;
      /* Read zero or more forward-declarations for labels that nested
	 functions can jump to.  */
      while (c_parser_next_token_is_keyword (parser, RID_LABEL))
	{
	  c_parser_consume_token (parser);
	  /* Any identifiers, including those declared as type names,
	     are OK here.  */
	  while (true)
	    {
	      tree label;
	      if (c_parser_next_token_is_not (parser, CPP_NAME))
		{
		  c_parser_error (parser, "expected identifier");
		  break;
		}
	      label
		= declare_label (c_parser_peek_token (parser)->value);
	      C_DECLARED_LABEL_FLAG (label) = 1;
	      add_stmt (build_stmt (DECL_EXPR, label));
	      c_parser_consume_token (parser);
	      if (c_parser_next_token_is (parser, CPP_COMMA))
		c_parser_consume_token (parser);
	      else
		break;
	    }
	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
	}
      pedwarn (err_loc, OPT_pedantic, "ISO C forbids label declarations");
    }
  /* We must now have at least one statement, label or declaration.  */
  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
    {
      c_parser_error (parser, "expected declaration or statement");
      c_parser_consume_token (parser);
      return;
    }
  while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
    {
      location_t loc = c_parser_peek_token (parser)->location;
      if (c_parser_next_token_is_keyword (parser, RID_CASE)
	  || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
	  || (c_parser_next_token_is (parser, CPP_NAME)
	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
	{
	  if (c_parser_next_token_is_keyword (parser, RID_CASE))
	    label_loc = c_parser_peek_2nd_token (parser)->location;
	  else
	    label_loc = c_parser_peek_token (parser)->location;
	  last_label = true;
	  last_stmt = false;
	  c_parser_label (parser);
	}
      else if (!last_label
	       && c_parser_next_token_starts_declspecs (parser))
	{
	  last_label = false;
	  c_parser_declaration_or_fndef (parser, true, true, true, true);
	  if (last_stmt)
	    pedwarn_c90 (loc, 
			 (pedantic && !flag_isoc99)
			 ? OPT_pedantic
			 : OPT_Wdeclaration_after_statement,
			 "ISO C90 forbids mixed declarations and code");
	  last_stmt = false;
	}
      else if (!last_label
	       && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
	{
	  /* __extension__ can start a declaration, but is also an
	     unary operator that can start an expression.  Consume all
	     but the last of a possible series of __extension__ to
	     determine which.  */
	  while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
		 && (c_parser_peek_2nd_token (parser)->keyword
		     == RID_EXTENSION))
	    c_parser_consume_token (parser);
	  if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
	    {
	      int ext;
	      ext = disable_extension_diagnostics ();
	      c_parser_consume_token (parser);
	      last_label = false;
	      c_parser_declaration_or_fndef (parser, true, true, true, true);
	      /* Following the old parser, __extension__ does not
		 disable this diagnostic.  */
	      restore_extension_diagnostics (ext);
	      if (last_stmt)
		pedwarn_c90 (loc, (pedantic && !flag_isoc99)
			     ? OPT_pedantic
			     : OPT_Wdeclaration_after_statement,
			     "ISO C90 forbids mixed declarations and code");
	      last_stmt = false;
	    }
	  else
	    goto statement;
	}
      else if (c_parser_next_token_is (parser, CPP_PRAGMA))
	{
	  /* External pragmas, and some omp pragmas, are not associated
	     with regular c code, and so are not to be considered statements
	     syntactically.  This ensures that the user doesn't put them
	     places that would turn into syntax errors if the directive
	     were ignored.  */
	  if (c_parser_pragma (parser, pragma_compound))
	    last_label = false, last_stmt = true;
	}
      else if (c_parser_next_token_is (parser, CPP_EOF))
	{
	  c_parser_error (parser, "expected declaration or statement");
	  return;
	}
      else if (c_parser_next_token_is_keyword (parser, RID_ELSE))
        {
          if (parser->in_if_block) 
            {
              error_at (loc, """expected %<}%> before %<else%>");
              return;
            }
          else 
            {
              error_at (loc, "%<else%> without a previous %<if%>");
              c_parser_consume_token (parser);
              continue;
            }
        }
      else
	{
	statement:
	  last_label = false;
	  last_stmt = true;
	  c_parser_statement_after_labels (parser);
	}

      parser->error = false;
    }
  if (last_label)
    error_at (label_loc, "label at end of compound statement");
  c_parser_consume_token (parser);
}

/* Parse a label (C90 6.6.1, C99 6.8.1).

   label:
     identifier : attributes[opt]
     case constant-expression :
     default :

   GNU extensions:

   label:
     case constant-expression ... constant-expression :

   The use of attributes on labels is a GNU extension.  The syntax in
   GNU C accepts any expressions without commas, non-constant
   expressions being rejected later.  */

static void
c_parser_label (c_parser *parser)
{
  location_t loc1 = c_parser_peek_token (parser)->location;
  tree label = NULL_TREE;
  if (c_parser_next_token_is_keyword (parser, RID_CASE))
    {
      tree exp1, exp2;
      c_parser_consume_token (parser);
      exp1 = c_parser_expr_no_commas (parser, NULL).value;
      if (c_parser_next_token_is (parser, CPP_COLON))
	{
	  c_parser_consume_token (parser);
	  label = do_case (exp1, NULL_TREE);
	}
      else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
	{
	  c_parser_consume_token (parser);
	  exp2 = c_parser_expr_no_commas (parser, NULL).value;
	  if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
	    label = do_case (exp1, exp2);
	}
      else
	c_parser_error (parser, "expected %<:%> or %<...%>");
    }
  else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
    {
      c_parser_consume_token (parser);
      if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
	label = do_case (NULL_TREE, NULL_TREE);
    }
  else
    {
      tree name = c_parser_peek_token (parser)->value;
      tree tlab;
      tree attrs;
      location_t loc2 = c_parser_peek_token (parser)->location;
      gcc_assert (c_parser_next_token_is (parser, CPP_NAME));
      c_parser_consume_token (parser);
      gcc_assert (c_parser_next_token_is (parser, CPP_COLON));
      c_parser_consume_token (parser);
      attrs = c_parser_attributes (parser);
      tlab = define_label (loc2, name);
      if (tlab)
	{
	  decl_attributes (&tlab, attrs, 0);
	  label = add_stmt (build_stmt (LABEL_EXPR, tlab));
	}
    }
  if (label)
    {
      SET_EXPR_LOCATION (label, loc1);
      if (c_parser_next_token_starts_declspecs (parser)
	  && !(c_parser_next_token_is (parser, CPP_NAME)
	       && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
	{
	  error_at (c_parser_peek_token (parser)->location,
		    "a label can only be part of a statement and "
		    "a declaration is not a statement");
	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, 
					 /*nested*/ true, /*empty_ok*/ false,
					 /*start_attr_ok*/ true);
	}
    }
}

/* Parse a statement (C90 6.6, C99 6.8).

   statement:
     labeled-statement
     compound-statement
     expression-statement
     selection-statement
     iteration-statement
     jump-statement

   labeled-statement:
     label statement

   expression-statement:
     expression[opt] ;

   selection-statement:
     if-statement
     switch-statement

   iteration-statement:
     while-statement
     do-statement
     for-statement

   jump-statement:
     goto identifier ;
     continue ;
     break ;
     return expression[opt] ;

   GNU extensions:

   statement:
     asm-statement

   jump-statement:
     goto * expression ;

   Objective-C:

   statement:
     objc-throw-statement
     objc-try-catch-statement
     objc-synchronized-statement

   objc-throw-statement:
     @throw expression ;
     @throw ;

   OpenMP:

   statement:
     openmp-construct

   openmp-construct:
     parallel-construct
     for-construct
     sections-construct
     single-construct
     parallel-for-construct
     parallel-sections-construct
     master-construct
     critical-construct
     atomic-construct
     ordered-construct

   parallel-construct:
     parallel-directive structured-block

   for-construct:
     for-directive iteration-statement

   sections-construct:
     sections-directive section-scope

   single-construct:
     single-directive structured-block

   parallel-for-construct:
     parallel-for-directive iteration-statement

   parallel-sections-construct:
     parallel-sections-directive section-scope

   master-construct:
     master-directive structured-block

   critical-construct:
     critical-directive structured-block

   atomic-construct:
     atomic-directive expression-statement

   ordered-construct:
     ordered-directive structured-block  */

static void
c_parser_statement (c_parser *parser)
{
  while (c_parser_next_token_is_keyword (parser, RID_CASE)
	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
	 || (c_parser_next_token_is (parser, CPP_NAME)
	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
    c_parser_label (parser);
  c_parser_statement_after_labels (parser);
}

/* Parse a statement, other than a labeled statement.  */

static void
c_parser_statement_after_labels (c_parser *parser)
{
  location_t loc = c_parser_peek_token (parser)->location;
  tree stmt = NULL_TREE;
  bool in_if_block = parser->in_if_block;
  parser->in_if_block = false;
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_OPEN_BRACE:
      add_stmt (c_parser_compound_statement (parser));
      break;
    case CPP_KEYWORD:
      switch (c_parser_peek_token (parser)->keyword)
	{
	case RID_IF:
	  c_parser_if_statement (parser);
	  break;
	case RID_SWITCH:
	  c_parser_switch_statement (parser);
	  break;
	case RID_WHILE:
	  c_parser_while_statement (parser);
	  break;
	case RID_DO:
	  c_parser_do_statement (parser);
	  break;
	case RID_FOR:
	  c_parser_for_statement (parser);
	  break;
	case RID_GOTO:
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_NAME))
	    {
	      stmt = c_finish_goto_label (c_parser_peek_token (parser)->value);
	      c_parser_consume_token (parser);
	    }
	  else if (c_parser_next_token_is (parser, CPP_MULT))
	    {
	      c_parser_consume_token (parser);
	      stmt = c_finish_goto_ptr (c_parser_expression (parser).value);
	    }
	  else
	    c_parser_error (parser, "expected identifier or %<*%>");
	  goto expect_semicolon;
	case RID_CONTINUE:
	  c_parser_consume_token (parser);
	  stmt = c_finish_bc_stmt (&c_cont_label, false);
	  goto expect_semicolon;
	case RID_BREAK:
	  c_parser_consume_token (parser);
	  stmt = c_finish_bc_stmt (&c_break_label, true);
	  goto expect_semicolon;
	case RID_RETURN:
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	    {
	      stmt = c_finish_return (NULL_TREE);
	      c_parser_consume_token (parser);
	    }
	  else
	    {
	      stmt = c_finish_return (c_parser_expression_conv (parser).value);
	      goto expect_semicolon;
	    }
	  break;
	case RID_ASM:
	  stmt = c_parser_asm_statement (parser);
	  break;
	case RID_THROW:
	  gcc_assert (c_dialect_objc ());
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	    {
	      stmt = objc_build_throw_stmt (NULL_TREE);
	      c_parser_consume_token (parser);
	    }
	  else
	    {
	      stmt
		= objc_build_throw_stmt (c_parser_expression (parser).value);
	      goto expect_semicolon;
	    }
	  break;
	case RID_TRY:
	  gcc_assert (c_dialect_objc ());
	  c_parser_objc_try_catch_statement (parser);
	  break;
	case RID_AT_SYNCHRONIZED:
	  gcc_assert (c_dialect_objc ());
	  c_parser_objc_synchronized_statement (parser);
	  break;
	default:
	  goto expr_stmt;
	}
      break;
    case CPP_SEMICOLON:
      c_parser_consume_token (parser);
      break;
    case CPP_CLOSE_PAREN:
    case CPP_CLOSE_SQUARE:
      /* Avoid infinite loop in error recovery:
	 c_parser_skip_until_found stops at a closing nesting
	 delimiter without consuming it, but here we need to consume
	 it to proceed further.  */
      c_parser_error (parser, "expected statement");
      c_parser_consume_token (parser);
      break;
    case CPP_PRAGMA:
      c_parser_pragma (parser, pragma_stmt);
      break;
    default:
    expr_stmt:
      stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value);
    expect_semicolon:
      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
      break;
    }
  /* Two cases cannot and do not have line numbers associated: If stmt
     is degenerate, such as "2;", then stmt is an INTEGER_CST, which
     cannot hold line numbers.  But that's OK because the statement
     will either be changed to a MODIFY_EXPR during gimplification of
     the statement expr, or discarded.  If stmt was compound, but
     without new variables, we will have skipped the creation of a
     BIND and will have a bare STATEMENT_LIST.  But that's OK because
     (recursively) all of the component statements should already have
     line numbers assigned.  ??? Can we discard no-op statements
     earlier?  */
  protected_set_expr_location (stmt, loc);

  parser->in_if_block = in_if_block;
}

/* Parse the condition from an if, do, while or for statements.  */

static tree
c_parser_condition (c_parser *parser)
{
  location_t loc;
  tree cond;
  loc = c_parser_peek_token (parser)->location;
  cond = c_objc_common_truthvalue_conversion 
    (loc, c_parser_expression_conv (parser).value);
  protected_set_expr_location (cond, loc);
  if (warn_sequence_point)
    verify_sequence_points (cond);
  return cond;
}

/* Parse a parenthesized condition from an if, do or while statement.

   condition:
     ( expression )
*/
static tree
c_parser_paren_condition (c_parser *parser)
{
  tree cond;
  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    return error_mark_node;
  cond = c_parser_condition (parser);
  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
  return cond;
}

/* Parse a statement which is a block in C99.  */

static tree
c_parser_c99_block_statement (c_parser *parser)
{
  tree block = c_begin_compound_stmt (flag_isoc99);
  c_parser_statement (parser);
  return c_end_compound_stmt (block, flag_isoc99);
}

/* Parse the body of an if statement.  This is just parsing a
   statement but (a) it is a block in C99, (b) we track whether the
   body is an if statement for the sake of -Wparentheses warnings, (c)
   we handle an empty body specially for the sake of -Wempty-body
   warnings, and (d) we call parser_compound_statement directly
   because c_parser_statement_after_labels resets
   parser->in_if_block.  */

static tree
c_parser_if_body (c_parser *parser, bool *if_p)
{
  tree block = c_begin_compound_stmt (flag_isoc99);
  while (c_parser_next_token_is_keyword (parser, RID_CASE)
	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
	 || (c_parser_next_token_is (parser, CPP_NAME)
	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
    c_parser_label (parser);
  *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
    {
      location_t loc = c_parser_peek_token (parser)->location;
      add_stmt (build_empty_stmt ());
      c_parser_consume_token (parser);
      if (!c_parser_next_token_is_keyword (parser, RID_ELSE))
	warning_at (loc, OPT_Wempty_body,
		    "suggest braces around empty body in an %<if%> statement");
    }
  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
    add_stmt (c_parser_compound_statement (parser));
  else
    c_parser_statement_after_labels (parser);
  return c_end_compound_stmt (block, flag_isoc99);
}

/* Parse the else body of an if statement.  This is just parsing a
   statement but (a) it is a block in C99, (b) we handle an empty body
   specially for the sake of -Wempty-body warnings.  */

static tree
c_parser_else_body (c_parser *parser)
{
  tree block = c_begin_compound_stmt (flag_isoc99);
  while (c_parser_next_token_is_keyword (parser, RID_CASE)
	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
	 || (c_parser_next_token_is (parser, CPP_NAME)
	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
    c_parser_label (parser);
  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
    {
      warning_at (c_parser_peek_token (parser)->location,
		  OPT_Wempty_body,
	         "suggest braces around empty body in an %<else%> statement");
      add_stmt (build_empty_stmt ());
      c_parser_consume_token (parser);
    }
  else 
    c_parser_statement_after_labels (parser);
  return c_end_compound_stmt (block, flag_isoc99);
}

/* Parse an if statement (C90 6.6.4, C99 6.8.4).

   if-statement:
     if ( expression ) statement
     if ( expression ) statement else statement
*/

static void
c_parser_if_statement (c_parser *parser)
{
  tree block;
  location_t loc;
  tree cond;
  bool first_if = false;
  tree first_body, second_body;
  bool in_if_block;

  gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
  c_parser_consume_token (parser);
  block = c_begin_compound_stmt (flag_isoc99);
  loc = c_parser_peek_token (parser)->location;
  cond = c_parser_paren_condition (parser);
  in_if_block = parser->in_if_block;
  parser->in_if_block = true;
  first_body = c_parser_if_body (parser, &first_if);
  parser->in_if_block = in_if_block;
  if (c_parser_next_token_is_keyword (parser, RID_ELSE))
    {
      c_parser_consume_token (parser);
      second_body = c_parser_else_body (parser);
    }
  else
    second_body = NULL_TREE;
  c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
  add_stmt (c_end_compound_stmt (block, flag_isoc99));
}

/* Parse a switch statement (C90 6.6.4, C99 6.8.4).

   switch-statement:
     switch (expression) statement
*/

static void
c_parser_switch_statement (c_parser *parser)
{
  tree block, expr, body, save_break;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
  c_parser_consume_token (parser);
  block = c_begin_compound_stmt (flag_isoc99);
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      expr = c_parser_expression (parser).value;
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  else
    expr = error_mark_node;
  c_start_case (expr);
  save_break = c_break_label;
  c_break_label = NULL_TREE;
  body = c_parser_c99_block_statement (parser);
  c_finish_case (body);
  if (c_break_label)
    add_stmt (build1 (LABEL_EXPR, void_type_node, c_break_label));
  c_break_label = save_break;
  add_stmt (c_end_compound_stmt (block, flag_isoc99));
}

/* Parse a while statement (C90 6.6.5, C99 6.8.5).

   while-statement:
      while (expression) statement
*/

static void
c_parser_while_statement (c_parser *parser)
{
  tree block, cond, body, save_break, save_cont;
  location_t loc;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
  c_parser_consume_token (parser);
  block = c_begin_compound_stmt (flag_isoc99);
  loc = c_parser_peek_token (parser)->location;
  cond = c_parser_paren_condition (parser);
  save_break = c_break_label;
  c_break_label = NULL_TREE;
  save_cont = c_cont_label;
  c_cont_label = NULL_TREE;
  body = c_parser_c99_block_statement (parser);
  c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
  add_stmt (c_end_compound_stmt (block, flag_isoc99));
  c_break_label = save_break;
  c_cont_label = save_cont;
}

/* Parse a do statement (C90 6.6.5, C99 6.8.5).

   do-statement:
     do statement while ( expression ) ;
*/

static void
c_parser_do_statement (c_parser *parser)
{
  tree block, cond, body, save_break, save_cont, new_break, new_cont;
  location_t loc;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
  c_parser_consume_token (parser);
  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
    warning_at (c_parser_peek_token (parser)->location,
		OPT_Wempty_body,
		"suggest braces around empty body in %<do%> statement");
  block = c_begin_compound_stmt (flag_isoc99);
  loc = c_parser_peek_token (parser)->location;
  save_break = c_break_label;
  c_break_label = NULL_TREE;
  save_cont = c_cont_label;
  c_cont_label = NULL_TREE;
  body = c_parser_c99_block_statement (parser);
  c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
  new_break = c_break_label;
  c_break_label = save_break;
  new_cont = c_cont_label;
  c_cont_label = save_cont;
  cond = c_parser_paren_condition (parser);
  if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
    c_parser_skip_to_end_of_block_or_statement (parser);
  c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
  add_stmt (c_end_compound_stmt (block, flag_isoc99));
}

/* Parse a for statement (C90 6.6.5, C99 6.8.5).

   for-statement:
     for ( expression[opt] ; expression[opt] ; expression[opt] ) statement
     for ( nested-declaration expression[opt] ; expression[opt] ) statement

   The form with a declaration is new in C99.

   ??? In accordance with the old parser, the declaration may be a
   nested function, which is then rejected in check_for_loop_decls,
   but does it make any sense for this to be included in the grammar?
   Note in particular that the nested function does not include a
   trailing ';', whereas the "declaration" production includes one.
   Also, can we reject bad declarations earlier and cheaper than
   check_for_loop_decls?  */

static void
c_parser_for_statement (c_parser *parser)
{
  tree block, cond, incr, save_break, save_cont, body;
  location_t loc;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
  loc = c_parser_peek_token (parser)->location;
  c_parser_consume_token (parser);
  block = c_begin_compound_stmt (flag_isoc99);
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      /* Parse the initialization declaration or expression.  */
      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	{
	  c_parser_consume_token (parser);
	  c_finish_expr_stmt (NULL_TREE);
	}
      else if (c_parser_next_token_starts_declspecs (parser))
	{
	  c_parser_declaration_or_fndef (parser, true, true, true, true);
	  check_for_loop_decls ();
	}
      else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
	{
	  /* __extension__ can start a declaration, but is also an
	     unary operator that can start an expression.  Consume all
	     but the last of a possible series of __extension__ to
	     determine which.  */
	  while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
		 && (c_parser_peek_2nd_token (parser)->keyword
		     == RID_EXTENSION))
	    c_parser_consume_token (parser);
	  if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
	    {
	      int ext;
	      ext = disable_extension_diagnostics ();
	      c_parser_consume_token (parser);
	      c_parser_declaration_or_fndef (parser, true, true, true, true);
	      restore_extension_diagnostics (ext);
	      check_for_loop_decls ();
	    }
	  else
	    goto init_expr;
	}
      else
	{
	init_expr:
	  c_finish_expr_stmt (c_parser_expression (parser).value);
	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
	}
      /* Parse the loop condition.  */
      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	{
	  c_parser_consume_token (parser);
	  cond = NULL_TREE;
	}
      else
	{
	  cond = c_parser_condition (parser);
	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
	}
      /* Parse the increment expression.  */
      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	incr = c_process_expr_stmt (NULL_TREE);
      else
	incr = c_process_expr_stmt (c_parser_expression (parser).value);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  else
    {
      cond = error_mark_node;
      incr = error_mark_node;
    }
  save_break = c_break_label;
  c_break_label = NULL_TREE;
  save_cont = c_cont_label;
  c_cont_label = NULL_TREE;
  body = c_parser_c99_block_statement (parser);
  c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
  add_stmt (c_end_compound_stmt (block, flag_isoc99));
  c_break_label = save_break;
  c_cont_label = save_cont;
}

/* Parse an asm statement, a GNU extension.  This is a full-blown asm
   statement with inputs, outputs, clobbers, and volatile tag
   allowed.

   asm-statement:
     asm type-qualifier[opt] ( asm-argument ) ;

   asm-argument:
     asm-string-literal
     asm-string-literal : asm-operands[opt]
     asm-string-literal : asm-operands[opt] : asm-operands[opt]
     asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers

   Qualifiers other than volatile are accepted in the syntax but
   warned for.  */

static tree
c_parser_asm_statement (c_parser *parser)
{
  tree quals, str, outputs, inputs, clobbers, ret;
  bool simple;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
  c_parser_consume_token (parser);
  if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
    {
      quals = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
    }
  else if (c_parser_next_token_is_keyword (parser, RID_CONST)
	   || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
    {
      warning_at (c_parser_peek_token (parser)->location,
		  0,
		  "%E qualifier ignored on asm",
		  c_parser_peek_token (parser)->value);
      quals = NULL_TREE;
      c_parser_consume_token (parser);
    }
  else
    quals = NULL_TREE;
  /* ??? Follow the C++ parser rather than using the
     lex_untranslated_string kludge.  */
  parser->lex_untranslated_string = true;
  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      parser->lex_untranslated_string = false;
      return NULL_TREE;
    }
  str = c_parser_asm_string_literal (parser);
  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
    {
      simple = true;
      outputs = NULL_TREE;
      inputs = NULL_TREE;
      clobbers = NULL_TREE;
      goto done_asm;
    }
  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
    {
      parser->lex_untranslated_string = false;
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
      return NULL_TREE;
    }
  simple = false;
  /* Parse outputs.  */
  if (c_parser_next_token_is (parser, CPP_COLON)
      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
    outputs = NULL_TREE;
  else
    outputs = c_parser_asm_operands (parser, false);
  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
    {
      inputs = NULL_TREE;
      clobbers = NULL_TREE;
      goto done_asm;
    }
  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
    {
      parser->lex_untranslated_string = false;
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
      return NULL_TREE;
    }
  /* Parse inputs.  */
  if (c_parser_next_token_is (parser, CPP_COLON)
      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
    inputs = NULL_TREE;
  else
    inputs = c_parser_asm_operands (parser, true);
  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
    {
      clobbers = NULL_TREE;
      goto done_asm;
    }
  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
    {
      parser->lex_untranslated_string = false;
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
      return NULL_TREE;
    }
  /* Parse clobbers.  */
  clobbers = c_parser_asm_clobbers (parser);
 done_asm:
  parser->lex_untranslated_string = false;
  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
    {
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
      return NULL_TREE;
    }
  if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
    c_parser_skip_to_end_of_block_or_statement (parser);
  ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs,
					       clobbers, simple));
  return ret;
}

/* Parse asm operands, a GNU extension.  If CONVERT_P (for inputs but
   not outputs), apply the default conversion of functions and arrays
   to pointers.

   asm-operands:
     asm-operand
     asm-operands , asm-operand

   asm-operand:
     asm-string-literal ( expression )
     [ identifier ] asm-string-literal ( expression )
*/

static tree
c_parser_asm_operands (c_parser *parser, bool convert_p)
{
  tree list = NULL_TREE;
  while (true)
    {
      tree name, str;
      struct c_expr expr;
      if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
	{
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_NAME))
	    {
	      tree id = c_parser_peek_token (parser)->value;
	      c_parser_consume_token (parser);
	      name = build_string (IDENTIFIER_LENGTH (id),
				   IDENTIFIER_POINTER (id));
	    }
	  else
	    {
	      c_parser_error (parser, "expected identifier");
	      c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
	      return NULL_TREE;
	    }
	  c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
				     "expected %<]%>");
	}
      else
	name = NULL_TREE;
      str = c_parser_asm_string_literal (parser);
      if (str == NULL_TREE)
	return NULL_TREE;
      parser->lex_untranslated_string = false;
      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	{
	  parser->lex_untranslated_string = true;
	  return NULL_TREE;
	}
      expr = c_parser_expression (parser);
      if (convert_p)
	expr = default_function_array_conversion (expr);
      parser->lex_untranslated_string = true;
      if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	  return NULL_TREE;
	}
      list = chainon (list, build_tree_list (build_tree_list (name, str),
					     expr.value));
      if (c_parser_next_token_is (parser, CPP_COMMA))
	c_parser_consume_token (parser);
      else
	break;
    }
  return list;
}

/* Parse asm clobbers, a GNU extension.

   asm-clobbers:
     asm-string-literal
     asm-clobbers , asm-string-literal
*/

static tree
c_parser_asm_clobbers (c_parser *parser)
{
  tree list = NULL_TREE;
  while (true)
    {
      tree str = c_parser_asm_string_literal (parser);
      if (str)
	list = tree_cons (NULL_TREE, str, list);
      else
	return NULL_TREE;
      if (c_parser_next_token_is (parser, CPP_COMMA))
	c_parser_consume_token (parser);
      else
	break;
    }
  return list;
}

/* Parse an expression other than a compound expression; that is, an
   assignment expression (C90 6.3.16, C99 6.5.16).  If AFTER is not
   NULL then it is an Objective-C message expression which is the
   primary-expression starting the expression as an initializer.

   assignment-expression:
     conditional-expression
     unary-expression assignment-operator assignment-expression

   assignment-operator: one of
     = *= /= %= += -= <<= >>= &= ^= |=

   In GNU C we accept any conditional expression on the LHS and
   diagnose the invalid lvalue rather than producing a syntax
   error.  */

static struct c_expr
c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
{
  struct c_expr lhs, rhs, ret;
  enum tree_code code;
  location_t op_location;
  gcc_assert (!after || c_dialect_objc ());
  lhs = c_parser_conditional_expression (parser, after);
  op_location = c_parser_peek_token (parser)->location;
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_EQ:
      code = NOP_EXPR;
      break;
    case CPP_MULT_EQ:
      code = MULT_EXPR;
      break;
    case CPP_DIV_EQ:
      code = TRUNC_DIV_EXPR;
      break;
    case CPP_MOD_EQ:
      code = TRUNC_MOD_EXPR;
      break;
    case CPP_PLUS_EQ:
      code = PLUS_EXPR;
      break;
    case CPP_MINUS_EQ:
      code = MINUS_EXPR;
      break;
    case CPP_LSHIFT_EQ:
      code = LSHIFT_EXPR;
      break;
    case CPP_RSHIFT_EQ:
      code = RSHIFT_EXPR;
      break;
    case CPP_AND_EQ:
      code = BIT_AND_EXPR;
      break;
    case CPP_XOR_EQ:
      code = BIT_XOR_EXPR;
      break;
    case CPP_OR_EQ:
      code = BIT_IOR_EXPR;
      break;
    default:
      return lhs;
    }
  c_parser_consume_token (parser);
  rhs = c_parser_expr_no_commas (parser, NULL);
  rhs = default_function_array_conversion (rhs);
  ret.value = build_modify_expr (op_location, lhs.value, code, rhs.value);
  if (code == NOP_EXPR)
    ret.original_code = MODIFY_EXPR;
  else
    {
      TREE_NO_WARNING (ret.value) = 1;
      ret.original_code = ERROR_MARK;
    }
  return ret;
}

/* Parse a conditional expression (C90 6.3.15, C99 6.5.15).  If AFTER
   is not NULL then it is an Objective-C message expression which is
   the primary-expression starting the expression as an initializer.

   conditional-expression:
     logical-OR-expression
     logical-OR-expression ? expression : conditional-expression

   GNU extensions:

   conditional-expression:
     logical-OR-expression ? : conditional-expression
*/

static struct c_expr
c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
{
  struct c_expr cond, exp1, exp2, ret;
  location_t cond_loc;

  gcc_assert (!after || c_dialect_objc ());

  cond_loc = c_parser_peek_token (parser)->location;
  cond = c_parser_binary_expression (parser, after);
  protected_set_expr_location (cond.value, cond_loc);

  if (c_parser_next_token_is_not (parser, CPP_QUERY))
    return cond;
  cond = default_function_array_conversion (cond);
  c_parser_consume_token (parser);
  if (c_parser_next_token_is (parser, CPP_COLON))
    {
      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
	       "ISO C forbids omitting the middle term of a ?: expression");
      /* Make sure first operand is calculated only once.  */
      exp1.value = save_expr (default_conversion (cond.value));
      cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
      skip_evaluation += cond.value == truthvalue_true_node;
    }
  else
    {
      cond.value
	= c_objc_common_truthvalue_conversion
	(cond_loc, default_conversion (cond.value));
      skip_evaluation += cond.value == truthvalue_false_node;
      exp1 = c_parser_expression_conv (parser);
      skip_evaluation += ((cond.value == truthvalue_true_node)
			  - (cond.value == truthvalue_false_node));
    }
  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
    {
      skip_evaluation -= cond.value == truthvalue_true_node;
      ret.value = error_mark_node;
      ret.original_code = ERROR_MARK;
      return ret;
    }
  exp2 = c_parser_conditional_expression (parser, NULL);
  exp2 = default_function_array_conversion (exp2);
  skip_evaluation -= cond.value == truthvalue_true_node;
  ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value);
  ret.original_code = ERROR_MARK;
  return ret;
}

/* Parse a binary expression; that is, a logical-OR-expression (C90
   6.3.5-6.3.14, C99 6.5.5-6.5.14).  If AFTER is not NULL then it is
   an Objective-C message expression which is the primary-expression
   starting the expression as an initializer.

   multiplicative-expression:
     cast-expression
     multiplicative-expression * cast-expression
     multiplicative-expression / cast-expression
     multiplicative-expression % cast-expression

   additive-expression:
     multiplicative-expression
     additive-expression + multiplicative-expression
     additive-expression - multiplicative-expression

   shift-expression:
     additive-expression
     shift-expression << additive-expression
     shift-expression >> additive-expression

   relational-expression:
     shift-expression
     relational-expression < shift-expression
     relational-expression > shift-expression
     relational-expression <= shift-expression
     relational-expression >= shift-expression

   equality-expression:
     relational-expression
     equality-expression == relational-expression
     equality-expression != relational-expression

   AND-expression:
     equality-expression
     AND-expression & equality-expression

   exclusive-OR-expression:
     AND-expression
     exclusive-OR-expression ^ AND-expression

   inclusive-OR-expression:
     exclusive-OR-expression
     inclusive-OR-expression | exclusive-OR-expression

   logical-AND-expression:
     inclusive-OR-expression
     logical-AND-expression && inclusive-OR-expression

   logical-OR-expression:
     logical-AND-expression
     logical-OR-expression || logical-AND-expression
*/

static struct c_expr
c_parser_binary_expression (c_parser *parser, struct c_expr *after)
{
  /* A binary expression is parsed using operator-precedence parsing,
     with the operands being cast expressions.  All the binary
     operators are left-associative.  Thus a binary expression is of
     form:

     E0 op1 E1 op2 E2 ...

     which we represent on a stack.  On the stack, the precedence
     levels are strictly increasing.  When a new operator is
     encountered of higher precedence than that at the top of the
     stack, it is pushed; its LHS is the top expression, and its RHS
     is everything parsed until it is popped.  When a new operator is
     encountered with precedence less than or equal to that at the top
     of the stack, triples E[i-1] op[i] E[i] are popped and replaced
     by the result of the operation until the operator at the top of
     the stack has lower precedence than the new operator or there is
     only one element on the stack; then the top expression is the LHS
     of the new operator.  In the case of logical AND and OR
     expressions, we also need to adjust skip_evaluation as
     appropriate when the operators are pushed and popped.  */

  /* The precedence levels, where 0 is a dummy lowest level used for
     the bottom of the stack.  */
  enum prec {
    PREC_NONE,
    PREC_LOGOR,
    PREC_LOGAND,
    PREC_BITOR,
    PREC_BITXOR,
    PREC_BITAND,
    PREC_EQ,
    PREC_REL,
    PREC_SHIFT,
    PREC_ADD,
    PREC_MULT,
    NUM_PRECS
  };
  struct {
    /* The expression at this stack level.  */
    struct c_expr expr;
    /* The precedence of the operator on its left, PREC_NONE at the
       bottom of the stack.  */
    enum prec prec;
    /* The operation on its left.  */
    enum tree_code op;
  } stack[NUM_PRECS];
  int sp;
  /* Location of the binary operator.  */
  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
#define POP								      \
  do {									      \
    switch (stack[sp].op)						      \
      {									      \
      case TRUTH_ANDIF_EXPR:						      \
	skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \
	break;								      \
      case TRUTH_ORIF_EXPR:						      \
	skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node;  \
	break;								      \
      default:								      \
	break;								      \
      }									      \
    stack[sp - 1].expr							      \
      = default_function_array_conversion (stack[sp - 1].expr);		      \
    stack[sp].expr							      \
      = default_function_array_conversion (stack[sp].expr);		      \
    stack[sp - 1].expr = parser_build_binary_op (binary_loc,		      \
						 stack[sp].op,		      \
						 stack[sp - 1].expr,	      \
						 stack[sp].expr);	      \
    sp--;								      \
  } while (0)
  gcc_assert (!after || c_dialect_objc ());
  stack[0].expr = c_parser_cast_expression (parser, after);
  stack[0].prec = PREC_NONE;
  sp = 0;
  while (true)
    {
      enum prec oprec;
      enum tree_code ocode;
      if (parser->error)
	goto out;
      switch (c_parser_peek_token (parser)->type)
	{
	case CPP_MULT:
	  oprec = PREC_MULT;
	  ocode = MULT_EXPR;
	  break;
	case CPP_DIV:
	  oprec = PREC_MULT;
	  ocode = TRUNC_DIV_EXPR;
	  break;
	case CPP_MOD:
	  oprec = PREC_MULT;
	  ocode = TRUNC_MOD_EXPR;
	  break;
	case CPP_PLUS:
	  oprec = PREC_ADD;
	  ocode = PLUS_EXPR;
	  break;
	case CPP_MINUS:
	  oprec = PREC_ADD;
	  ocode = MINUS_EXPR;
	  break;
	case CPP_LSHIFT:
	  oprec = PREC_SHIFT;
	  ocode = LSHIFT_EXPR;
	  break;
	case CPP_RSHIFT:
	  oprec = PREC_SHIFT;
	  ocode = RSHIFT_EXPR;
	  break;
	case CPP_LESS:
	  oprec = PREC_REL;
	  ocode = LT_EXPR;
	  break;
	case CPP_GREATER:
	  oprec = PREC_REL;
	  ocode = GT_EXPR;
	  break;
	case CPP_LESS_EQ:
	  oprec = PREC_REL;
	  ocode = LE_EXPR;
	  break;
	case CPP_GREATER_EQ:
	  oprec = PREC_REL;
	  ocode = GE_EXPR;
	  break;
	case CPP_EQ_EQ:
	  oprec = PREC_EQ;
	  ocode = EQ_EXPR;
	  break;
	case CPP_NOT_EQ:
	  oprec = PREC_EQ;
	  ocode = NE_EXPR;
	  break;
	case CPP_AND:
	  oprec = PREC_BITAND;
	  ocode = BIT_AND_EXPR;
	  break;
	case CPP_XOR:
	  oprec = PREC_BITXOR;
	  ocode = BIT_XOR_EXPR;
	  break;
	case CPP_OR:
	  oprec = PREC_BITOR;
	  ocode = BIT_IOR_EXPR;
	  break;
	case CPP_AND_AND:
	  oprec = PREC_LOGAND;
	  ocode = TRUTH_ANDIF_EXPR;
	  break;
	case CPP_OR_OR:
	  oprec = PREC_LOGOR;
	  ocode = TRUTH_ORIF_EXPR;
	  break;
	default:
	  /* Not a binary operator, so end of the binary
	     expression.  */
	  goto out;
	}
      binary_loc = c_parser_peek_token (parser)->location;
      c_parser_consume_token (parser);
      while (oprec <= stack[sp].prec)
	POP;
      switch (ocode)
	{
	case TRUTH_ANDIF_EXPR:
	  stack[sp].expr
	    = default_function_array_conversion (stack[sp].expr);
	  stack[sp].expr.value = c_objc_common_truthvalue_conversion
	    (binary_loc, default_conversion (stack[sp].expr.value));
	  skip_evaluation += stack[sp].expr.value == truthvalue_false_node;
	  break;
	case TRUTH_ORIF_EXPR:
	  stack[sp].expr
	    = default_function_array_conversion (stack[sp].expr);
	  stack[sp].expr.value = c_objc_common_truthvalue_conversion
	    (binary_loc, default_conversion (stack[sp].expr.value));
	  skip_evaluation += stack[sp].expr.value == truthvalue_true_node;
	  break;
	default:
	  break;
	}
      sp++;
      stack[sp].expr = c_parser_cast_expression (parser, NULL);
      stack[sp].prec = oprec;
      stack[sp].op = ocode;
    }
 out:
  while (sp > 0)
    POP;
  return stack[0].expr;
#undef POP
}

/* Parse a cast expression (C90 6.3.4, C99 6.5.4).  If AFTER is not
   NULL then it is an Objective-C message expression which is the
   primary-expression starting the expression as an initializer.

   cast-expression:
     unary-expression
     ( type-name ) unary-expression
*/

static struct c_expr
c_parser_cast_expression (c_parser *parser, struct c_expr *after)
{
  gcc_assert (!after || c_dialect_objc ());
  if (after)
    return c_parser_postfix_expression_after_primary (parser, *after);
  /* If the expression begins with a parenthesized type name, it may
     be either a cast or a compound literal; we need to see whether
     the next character is '{' to tell the difference.  If not, it is
     an unary expression.  */
  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
    {
      struct c_type_name *type_name;
      struct c_expr ret;
      struct c_expr expr;
      c_parser_consume_token (parser);
      type_name = c_parser_type_name (parser);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
      if (type_name == NULL)
	{
	  ret.value = error_mark_node;
	  ret.original_code = ERROR_MARK;
	  return ret;
	}

      /* Save casted types in the function's used types hash table.  */
      used_types_insert (type_name->specs->type);

      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
	return c_parser_postfix_expression_after_paren_type (parser,
							     type_name);
      expr = c_parser_cast_expression (parser, NULL);
      expr = default_function_array_conversion (expr);
      ret.value = c_cast_expr (type_name, expr.value);
      ret.original_code = ERROR_MARK;
      return ret;
    }
  else
    return c_parser_unary_expression (parser);
}

/* Parse an unary expression (C90 6.3.3, C99 6.5.3).

   unary-expression:
     postfix-expression
     ++ unary-expression
     -- unary-expression
     unary-operator cast-expression
     sizeof unary-expression
     sizeof ( type-name )

   unary-operator: one of
     & * + - ~ !

   GNU extensions:

   unary-expression:
     __alignof__ unary-expression
     __alignof__ ( type-name )
     && identifier

   unary-operator: one of
     __extension__ __real__ __imag__

   In addition, the GNU syntax treats ++ and -- as unary operators, so
   they may be applied to cast expressions with errors for non-lvalues
   given later.  */

static struct c_expr
c_parser_unary_expression (c_parser *parser)
{
  int ext;
  struct c_expr ret, op;
  location_t loc = c_parser_peek_token (parser)->location;
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_PLUS_PLUS:
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      return parser_build_unary_op (PREINCREMENT_EXPR, op, loc);
    case CPP_MINUS_MINUS:
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      return parser_build_unary_op (PREDECREMENT_EXPR, op, loc);
    case CPP_AND:
      c_parser_consume_token (parser);
      return parser_build_unary_op (ADDR_EXPR,
				    c_parser_cast_expression (parser, NULL),
				    loc);
    case CPP_MULT:
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      ret.value = build_indirect_ref (loc, op.value, "unary *");
      ret.original_code = ERROR_MARK;
      return ret;
    case CPP_PLUS:
      if (!c_dialect_objc () && !in_system_header)
	warning_at (c_parser_peek_token (parser)->location,
		    OPT_Wtraditional,
		    "traditional C rejects the unary plus operator");
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      return parser_build_unary_op (CONVERT_EXPR, op, loc);
    case CPP_MINUS:
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      return parser_build_unary_op (NEGATE_EXPR, op, loc);
    case CPP_COMPL:
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      return parser_build_unary_op (BIT_NOT_EXPR, op, loc);
    case CPP_NOT:
      c_parser_consume_token (parser);
      op = c_parser_cast_expression (parser, NULL);
      op = default_function_array_conversion (op);
      return parser_build_unary_op (TRUTH_NOT_EXPR, op, loc);
    case CPP_AND_AND:
      /* Refer to the address of a label as a pointer.  */
      c_parser_consume_token (parser);
      if (c_parser_next_token_is (parser, CPP_NAME))
	{
	  ret.value = finish_label_address_expr
	    (c_parser_peek_token (parser)->value, loc);
	  c_parser_consume_token (parser);
	}
      else
	{
	  c_parser_error (parser, "expected identifier");
	  ret.value = error_mark_node;
	}
	ret.original_code = ERROR_MARK;
	return ret;
    case CPP_KEYWORD:
      switch (c_parser_peek_token (parser)->keyword)
	{
	case RID_SIZEOF:
	  return c_parser_sizeof_expression (parser);
	case RID_ALIGNOF:
	  return c_parser_alignof_expression (parser);
	case RID_EXTENSION:
	  c_parser_consume_token (parser);
	  ext = disable_extension_diagnostics ();
	  ret = c_parser_cast_expression (parser, NULL);
	  restore_extension_diagnostics (ext);
	  return ret;
	case RID_REALPART:
	  c_parser_consume_token (parser);
	  op = c_parser_cast_expression (parser, NULL);
	  op = default_function_array_conversion (op);
	  return parser_build_unary_op (REALPART_EXPR, op, loc);
	case RID_IMAGPART:
	  c_parser_consume_token (parser);
	  op = c_parser_cast_expression (parser, NULL);
	  op = default_function_array_conversion (op);
	  return parser_build_unary_op (IMAGPART_EXPR, op, loc);
	default:
	  return c_parser_postfix_expression (parser);
	}
    default:
      return c_parser_postfix_expression (parser);
    }
}

/* Parse a sizeof expression.  */

static struct c_expr
c_parser_sizeof_expression (c_parser *parser)
{
  struct c_expr expr;
  location_t expr_loc;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
  c_parser_consume_token (parser);
  skip_evaluation++;
  in_sizeof++;
  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
    {
      /* Either sizeof ( type-name ) or sizeof unary-expression
	 starting with a compound literal.  */
      struct c_type_name *type_name;
      c_parser_consume_token (parser);
      expr_loc = c_parser_peek_token (parser)->location;
      type_name = c_parser_type_name (parser);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
      if (type_name == NULL)
	{
	  struct c_expr ret;
	  skip_evaluation--;
	  in_sizeof--;
	  ret.value = error_mark_node;
	  ret.original_code = ERROR_MARK;
	  return ret;
	}
      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
	{
	  expr = c_parser_postfix_expression_after_paren_type (parser,
							       type_name);
	  goto sizeof_expr;
	}
      /* sizeof ( type-name ).  */
      skip_evaluation--;
      in_sizeof--;
      return c_expr_sizeof_type (type_name);
    }
  else
    {
      expr_loc = c_parser_peek_token (parser)->location;
      expr = c_parser_unary_expression (parser);
    sizeof_expr:
      skip_evaluation--;
      in_sizeof--;
      if (TREE_CODE (expr.value) == COMPONENT_REF
	  && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
	error_at (expr_loc, "%<sizeof%> applied to a bit-field");
      return c_expr_sizeof_expr (expr);
    }
}

/* Parse an alignof expression.  */

static struct c_expr
c_parser_alignof_expression (c_parser *parser)
{
  struct c_expr expr;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
  c_parser_consume_token (parser);
  skip_evaluation++;
  in_alignof++;
  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
    {
      /* Either __alignof__ ( type-name ) or __alignof__
	 unary-expression starting with a compound literal.  */
      struct c_type_name *type_name;
      struct c_expr ret;
      c_parser_consume_token (parser);
      type_name = c_parser_type_name (parser);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
      if (type_name == NULL)
	{
	  struct c_expr ret;
	  skip_evaluation--;
	  in_alignof--;
	  ret.value = error_mark_node;
	  ret.original_code = ERROR_MARK;
	  return ret;
	}
      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
	{
	  expr = c_parser_postfix_expression_after_paren_type (parser,
							       type_name);
	  goto alignof_expr;
	}
      /* alignof ( type-name ).  */
      skip_evaluation--;
      in_alignof--;
      ret.value = c_alignof (groktypename (type_name));
      ret.original_code = ERROR_MARK;
      return ret;
    }
  else
    {
      struct c_expr ret;
      expr = c_parser_unary_expression (parser);
    alignof_expr:
      skip_evaluation--;
      in_alignof--;
      ret.value = c_alignof_expr (expr.value);
      ret.original_code = ERROR_MARK;
      return ret;
    }
}

/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).

   postfix-expression:
     primary-expression
     postfix-expression [ expression ]
     postfix-expression ( argument-expression-list[opt] )
     postfix-expression . identifier
     postfix-expression -> identifier
     postfix-expression ++
     postfix-expression --
     ( type-name ) { initializer-list }
     ( type-name ) { initializer-list , }

   argument-expression-list:
     argument-expression
     argument-expression-list , argument-expression

   primary-expression:
     identifier
     constant
     string-literal
     ( expression )

   GNU extensions:

   primary-expression:
     __func__
       (treated as a keyword in GNU C)
     __FUNCTION__
     __PRETTY_FUNCTION__
     ( compound-statement )
     __builtin_va_arg ( assignment-expression , type-name )
     __builtin_offsetof ( type-name , offsetof-member-designator )
     __builtin_choose_expr ( assignment-expression ,
			     assignment-expression ,
			     assignment-expression )
     __builtin_types_compatible_p ( type-name , type-name )

   offsetof-member-designator:
     identifier
     offsetof-member-designator . identifier
     offsetof-member-designator [ expression ]

   Objective-C:

   primary-expression:
     [ objc-receiver objc-message-args ]
     @selector ( objc-selector-arg )
     @protocol ( identifier )
     @encode ( type-name )
     objc-string-literal
*/

static struct c_expr
c_parser_postfix_expression (c_parser *parser)
{
  struct c_expr expr, e1, e2, e3;
  struct c_type_name *t1, *t2;
  location_t loc;
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_NUMBER:
      expr.value = c_parser_peek_token (parser)->value;
      expr.original_code = ERROR_MARK;
      loc = c_parser_peek_token (parser)->location;
      c_parser_consume_token (parser);
      if (TREE_CODE (expr.value) == FIXED_CST
	  && !targetm.fixed_point_supported_p ())
	{
	  error_at (loc, "fixed-point types not supported for this target");
	  expr.value = error_mark_node;
	}
      break;
    case CPP_CHAR:
    case CPP_CHAR16:
    case CPP_CHAR32:
    case CPP_WCHAR:
      expr.value = c_parser_peek_token (parser)->value;
      expr.original_code = ERROR_MARK;
      c_parser_consume_token (parser);
      break;
    case CPP_STRING:
    case CPP_STRING16:
    case CPP_STRING32:
    case CPP_WSTRING:
      expr.value = c_parser_peek_token (parser)->value;
      expr.original_code = STRING_CST;
      c_parser_consume_token (parser);
      break;
    case CPP_OBJC_STRING:
      gcc_assert (c_dialect_objc ());
      expr.value
	= objc_build_string_object (c_parser_peek_token (parser)->value);
      expr.original_code = ERROR_MARK;
      c_parser_consume_token (parser);
      break;
    case CPP_NAME:
      if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
	{
	  c_parser_error (parser, "expected expression");
	  expr.value = error_mark_node;
	  expr.original_code = ERROR_MARK;
	  break;
	}
      {
	tree id = c_parser_peek_token (parser)->value;
	location_t loc = c_parser_peek_token (parser)->location;
	c_parser_consume_token (parser);
	expr.value = build_external_ref (id,
					 (c_parser_peek_token (parser)->type
					  == CPP_OPEN_PAREN), loc);
	expr.original_code = ERROR_MARK;
      }
      break;
    case CPP_OPEN_PAREN:
      /* A parenthesized expression, statement expression or compound
	 literal.  */
      if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
	{
	  /* A statement expression.  */
	  tree stmt;
	  location_t here = c_parser_peek_token (parser)->location;
	  c_parser_consume_token (parser);
	  c_parser_consume_token (parser);
	  if (cur_stmt_list == NULL)
	    {
	      error_at (here, "braced-group within expression allowed "
			"only inside a function");
	      parser->error = true;
	      c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  stmt = c_begin_stmt_expr ();
	  c_parser_compound_statement_nostart (parser);
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  pedwarn (here, OPT_pedantic, 
		   "ISO C forbids braced-groups within expressions");
	  expr.value = c_finish_stmt_expr (stmt);
	  expr.original_code = ERROR_MARK;
	}
      else if (c_token_starts_typename (c_parser_peek_2nd_token (parser)))
	{
	  /* A compound literal.  ??? Can we actually get here rather
	     than going directly to
	     c_parser_postfix_expression_after_paren_type from
	     elsewhere?  */
	  struct c_type_name *type_name;
	  c_parser_consume_token (parser);
	  type_name = c_parser_type_name (parser);
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  if (type_name == NULL)
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	    }
	  else
	    expr = c_parser_postfix_expression_after_paren_type (parser,
								 type_name);
	}
      else
	{
	  /* A parenthesized expression.  */
	  c_parser_consume_token (parser);
	  expr = c_parser_expression (parser);
	  if (TREE_CODE (expr.value) == MODIFY_EXPR)
	    TREE_NO_WARNING (expr.value) = 1;
	  expr.original_code = ERROR_MARK;
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	}
      break;
    case CPP_KEYWORD:
      switch (c_parser_peek_token (parser)->keyword)
	{
	case RID_FUNCTION_NAME:
	case RID_PRETTY_FUNCTION_NAME:
	case RID_C99_FUNCTION_NAME:
	  expr.value = fname_decl (c_parser_peek_token (parser)->location,
				   c_parser_peek_token (parser)->keyword,
				   c_parser_peek_token (parser)->value);
	  expr.original_code = ERROR_MARK;
	  c_parser_consume_token (parser);
	  break;
	case RID_VA_ARG:
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  e1 = c_parser_expr_no_commas (parser, NULL);
	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
	    {
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  t1 = c_parser_type_name (parser);
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  if (t1 == NULL)
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	    }
	  else
	    {
	      expr.value = build_va_arg (e1.value, groktypename (t1));
	      expr.original_code = ERROR_MARK;
	    }
	  break;
	case RID_OFFSETOF:
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  t1 = c_parser_type_name (parser);
	  if (t1 == NULL)
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
	    {
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  {
	    tree type = groktypename (t1);
	    tree offsetof_ref;
	    if (type == error_mark_node)
	      offsetof_ref = error_mark_node;
	    else
	      offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
	    /* Parse the second argument to __builtin_offsetof.  We
	       must have one identifier, and beyond that we want to
	       accept sub structure and sub array references.  */
	    if (c_parser_next_token_is (parser, CPP_NAME))
	      {
		offsetof_ref = build_component_ref
		  (offsetof_ref, c_parser_peek_token (parser)->value);
		c_parser_consume_token (parser);
		while (c_parser_next_token_is (parser, CPP_DOT)
		       || c_parser_next_token_is (parser,
						  CPP_OPEN_SQUARE)
		       || c_parser_next_token_is (parser,
						  CPP_DEREF))
		  {
		    if (c_parser_next_token_is (parser, CPP_DEREF))
		      {
			loc = c_parser_peek_token (parser)->location;
			offsetof_ref = build_array_ref (offsetof_ref,
							integer_zero_node,
							loc);
			goto do_dot;
		      }
		    else if (c_parser_next_token_is (parser, CPP_DOT))
		      {
		      do_dot:
			c_parser_consume_token (parser);
			if (c_parser_next_token_is_not (parser,
							CPP_NAME))
			  {
			    c_parser_error (parser, "expected identifier");
			    break;
			  }
			offsetof_ref = build_component_ref
			  (offsetof_ref,
			   c_parser_peek_token (parser)->value);
			c_parser_consume_token (parser);
		      }
		    else
		      {
			tree idx;
			loc = c_parser_peek_token (parser)->location;
			c_parser_consume_token (parser);
			idx = c_parser_expression (parser).value;
			c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
						   "expected %<]%>");
			offsetof_ref = build_array_ref (offsetof_ref, idx, loc);
		      }
		  }
	      }
	    else
	      c_parser_error (parser, "expected identifier");
	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				       "expected %<)%>");
	    expr.value = fold_offsetof (offsetof_ref, NULL_TREE);
	    expr.original_code = ERROR_MARK;
	  }
	  break;
	case RID_CHOOSE_EXPR:
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  loc = c_parser_peek_token (parser)->location;
	  e1 = c_parser_expr_no_commas (parser, NULL);
	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
	    {
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  e2 = c_parser_expr_no_commas (parser, NULL);
	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
	    {
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  e3 = c_parser_expr_no_commas (parser, NULL);
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  {
	    tree c;

	    c = fold (e1.value);
	    if (TREE_CODE (c) != INTEGER_CST)
	      error_at (loc,
			"first argument to %<__builtin_choose_expr%> not"
			" a constant");
	    expr = integer_zerop (c) ? e3 : e2;
	  }
	  break;
	case RID_TYPES_COMPATIBLE_P:
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  t1 = c_parser_type_name (parser);
	  if (t1 == NULL)
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
	    {
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  t2 = c_parser_type_name (parser);
	  if (t2 == NULL)
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  {
	    tree e1, e2;

	    e1 = TYPE_MAIN_VARIANT (groktypename (t1));
	    e2 = TYPE_MAIN_VARIANT (groktypename (t2));

	    expr.value = comptypes (e1, e2)
	      ? build_int_cst (NULL_TREE, 1)
	      : build_int_cst (NULL_TREE, 0);
	    expr.original_code = ERROR_MARK;
	  }
	  break;
	case RID_AT_SELECTOR:
	  gcc_assert (c_dialect_objc ());
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  {
	    tree sel = c_parser_objc_selector_arg (parser);
	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				       "expected %<)%>");
	    expr.value = objc_build_selector_expr (sel);
	    expr.original_code = ERROR_MARK;
	  }
	  break;
	case RID_AT_PROTOCOL:
	  gcc_assert (c_dialect_objc ());
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  if (c_parser_next_token_is_not (parser, CPP_NAME))
	    {
	      c_parser_error (parser, "expected identifier");
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  {
	    tree id = c_parser_peek_token (parser)->value;
	    c_parser_consume_token (parser);
	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				       "expected %<)%>");
	    expr.value = objc_build_protocol_expr (id);
	    expr.original_code = ERROR_MARK;
	  }
	  break;
	case RID_AT_ENCODE:
	  /* Extension to support C-structures in the archiver.  */
	  gcc_assert (c_dialect_objc ());
	  c_parser_consume_token (parser);
	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      break;
	    }
	  t1 = c_parser_type_name (parser);
	  if (t1 == NULL)
	    {
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	      break;
	    }
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  {
	    tree type = groktypename (t1);
	    expr.value = objc_build_encode_expr (type);
	    expr.original_code = ERROR_MARK;
	  }
	  break;
	default:
	  c_parser_error (parser, "expected expression");
	  expr.value = error_mark_node;
	  expr.original_code = ERROR_MARK;
	  break;
	}
      break;
    case CPP_OPEN_SQUARE:
      if (c_dialect_objc ())
	{
	  tree receiver, args;
	  c_parser_consume_token (parser);
	  receiver = c_parser_objc_receiver (parser);
	  args = c_parser_objc_message_args (parser);
	  c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
				     "expected %<]%>");
	  expr.value = objc_build_message_expr (build_tree_list (receiver,
								 args));
	  expr.original_code = ERROR_MARK;
	  break;
	}
      /* Else fall through to report error.  */
    default:
      c_parser_error (parser, "expected expression");
      expr.value = error_mark_node;
      expr.original_code = ERROR_MARK;
      break;
    }
  return c_parser_postfix_expression_after_primary (parser, expr);
}

/* Parse a postfix expression after a parenthesized type name: the
   brace-enclosed initializer of a compound literal, possibly followed
   by some postfix operators.  This is separate because it is not
   possible to tell until after the type name whether a cast
   expression has a cast or a compound literal, or whether the operand
   of sizeof is a parenthesized type name or starts with a compound
   literal.  */

static struct c_expr
c_parser_postfix_expression_after_paren_type (c_parser *parser,
					      struct c_type_name *type_name)
{
  tree type;
  struct c_expr init;
  struct c_expr expr;
  location_t start_loc;
  start_init (NULL_TREE, NULL, 0);
  type = groktypename (type_name);
  start_loc = c_parser_peek_token (parser)->location;
  if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
    {
      error_at (start_loc, "compound literal has variable size");
      type = error_mark_node;
    }
  init = c_parser_braced_init (parser, type, false);
  finish_init ();
  maybe_warn_string_init (type, init);

  if (!flag_isoc99)
    pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
  expr.value = build_compound_literal (type, init.value);
  expr.original_code = ERROR_MARK;
  return c_parser_postfix_expression_after_primary (parser, expr);
}

/* Parse a postfix expression after the initial primary or compound
   literal; that is, parse a series of postfix operators.  */

static struct c_expr
c_parser_postfix_expression_after_primary (c_parser *parser,
					   struct c_expr expr)
{
  tree ident, idx, exprlist;
  location_t loc = c_parser_peek_token (parser)->location;
  while (true)
    {
      switch (c_parser_peek_token (parser)->type)
	{
	case CPP_OPEN_SQUARE:
	  /* Array reference.  */
	  loc = c_parser_peek_token (parser)->location;
	  c_parser_consume_token (parser);
	  idx = c_parser_expression (parser).value;
	  c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
				     "expected %<]%>");
	  expr.value = build_array_ref (expr.value, idx, loc);
	  expr.original_code = ERROR_MARK;
	  break;
	case CPP_OPEN_PAREN:
	  /* Function call.  */
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
	    exprlist = NULL_TREE;
	  else
	    exprlist = c_parser_expr_list (parser, true);
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  expr.value = build_function_call (expr.value, exprlist);
	  expr.original_code = ERROR_MARK;
          if (warn_disallowed_functions)
            warn_if_disallowed_function_p (expr.value);
	  break;
	case CPP_DOT:
	  /* Structure element reference.  */
	  c_parser_consume_token (parser);
	  expr = default_function_array_conversion (expr);
	  if (c_parser_next_token_is (parser, CPP_NAME))
	    ident = c_parser_peek_token (parser)->value;
	  else
	    {
	      c_parser_error (parser, "expected identifier");
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      return expr;
	    }
	  c_parser_consume_token (parser);
	  expr.value = build_component_ref (expr.value, ident);
	  expr.original_code = ERROR_MARK;
	  break;
	case CPP_DEREF:
	  /* Structure element reference.  */
	  c_parser_consume_token (parser);
	  expr = default_function_array_conversion (expr);
	  if (c_parser_next_token_is (parser, CPP_NAME))
	    ident = c_parser_peek_token (parser)->value;
	  else
	    {
	      c_parser_error (parser, "expected identifier");
	      expr.value = error_mark_node;
	      expr.original_code = ERROR_MARK;
	      return expr;
	    }
	  c_parser_consume_token (parser);
	  expr.value = build_component_ref (build_indirect_ref (loc,
								expr.value,
								"->"),
					    ident);
	  expr.original_code = ERROR_MARK;
	  break;
	case CPP_PLUS_PLUS:
	  /* Postincrement.  */
	  c_parser_consume_token (parser);
	  expr = default_function_array_conversion (expr);
	  expr.value = build_unary_op (loc,
				       POSTINCREMENT_EXPR, expr.value, 0);
	  expr.original_code = ERROR_MARK;
	  break;
	case CPP_MINUS_MINUS:
	  /* Postdecrement.  */
	  c_parser_consume_token (parser);
	  expr = default_function_array_conversion (expr);
	  expr.value = build_unary_op (loc,
				       POSTDECREMENT_EXPR, expr.value, 0);
	  expr.original_code = ERROR_MARK;
	  break;
	default:
	  return expr;
	}
    }
}

/* Parse an expression (C90 6.3.17, C99 6.5.17).

   expression:
     assignment-expression
     expression , assignment-expression
*/

static struct c_expr
c_parser_expression (c_parser *parser)
{
  struct c_expr expr;
  expr = c_parser_expr_no_commas (parser, NULL);
  while (c_parser_next_token_is (parser, CPP_COMMA))
    {
      struct c_expr next;
      c_parser_consume_token (parser);
      next = c_parser_expr_no_commas (parser, NULL);
      next = default_function_array_conversion (next);
      expr.value = build_compound_expr (expr.value, next.value);
      expr.original_code = COMPOUND_EXPR;
    }
  return expr;
}

/* Parse an expression and convert functions or arrays to
   pointers.  */

static struct c_expr
c_parser_expression_conv (c_parser *parser)
{
  struct c_expr expr;
  expr = c_parser_expression (parser);
  expr = default_function_array_conversion (expr);
  return expr;
}

/* Parse a non-empty list of expressions.  If CONVERT_P, convert
   functions and arrays to pointers.

   nonempty-expr-list:
     assignment-expression
     nonempty-expr-list , assignment-expression
*/

static tree
c_parser_expr_list (c_parser *parser, bool convert_p)
{
  struct c_expr expr;
  tree ret, cur;
  expr = c_parser_expr_no_commas (parser, NULL);
  if (convert_p)
    expr = default_function_array_conversion (expr);
  ret = cur = build_tree_list (NULL_TREE, expr.value);
  while (c_parser_next_token_is (parser, CPP_COMMA))
    {
      c_parser_consume_token (parser);
      expr = c_parser_expr_no_commas (parser, NULL);
      if (convert_p)
	expr = default_function_array_conversion (expr);
      cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value);
    }
  return ret;
}


/* Parse Objective-C-specific constructs.  */

/* Parse an objc-class-definition.

   objc-class-definition:
     @interface identifier objc-superclass[opt] objc-protocol-refs[opt]
       objc-class-instance-variables[opt] objc-methodprotolist @end
     @implementation identifier objc-superclass[opt]
       objc-class-instance-variables[opt]
     @interface identifier ( identifier ) objc-protocol-refs[opt]
       objc-methodprotolist @end
     @implementation identifier ( identifier )

   objc-superclass:
     : identifier

   "@interface identifier (" must start "@interface identifier (
   identifier ) ...": objc-methodprotolist in the first production may
   not start with a parenthesized identifier as a declarator of a data
   definition with no declaration specifiers if the objc-superclass,
   objc-protocol-refs and objc-class-instance-variables are omitted.  */

static void
c_parser_objc_class_definition (c_parser *parser)
{
  bool iface_p;
  tree id1;
  tree superclass;
  if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE))
    iface_p = true;
  else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION))
    iface_p = false;
  else
    gcc_unreachable ();
  c_parser_consume_token (parser);
  if (c_parser_next_token_is_not (parser, CPP_NAME))
    {
      c_parser_error (parser, "expected identifier");
      return;
    }
  id1 = c_parser_peek_token (parser)->value;
  c_parser_consume_token (parser);
  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    {
      tree id2;
      tree proto = NULL_TREE;
      c_parser_consume_token (parser);
      if (c_parser_next_token_is_not (parser, CPP_NAME))
	{
	  c_parser_error (parser, "expected identifier");
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	  return;
	}
      id2 = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
      if (!iface_p)
	{
	  objc_start_category_implementation (id1, id2);
	  return;
	}
      if (c_parser_next_token_is (parser, CPP_LESS))
	proto = c_parser_objc_protocol_refs (parser);
      objc_start_category_interface (id1, id2, proto);
      c_parser_objc_methodprotolist (parser);
      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
      objc_finish_interface ();
      return;
    }
  if (c_parser_next_token_is (parser, CPP_COLON))
    {
      c_parser_consume_token (parser);
      if (c_parser_next_token_is_not (parser, CPP_NAME))
	{
	  c_parser_error (parser, "expected identifier");
	  return;
	}
      superclass = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
    }
  else
    superclass = NULL_TREE;
  if (iface_p)
    {
      tree proto = NULL_TREE;
      if (c_parser_next_token_is (parser, CPP_LESS))
	proto = c_parser_objc_protocol_refs (parser);
      objc_start_class_interface (id1, superclass, proto);
    }
  else
    objc_start_class_implementation (id1, superclass);
  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
    c_parser_objc_class_instance_variables (parser);
  if (iface_p)
    {
      objc_continue_interface ();
      c_parser_objc_methodprotolist (parser);
      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
      objc_finish_interface ();
    }
  else
    {
      objc_continue_implementation ();
      return;
    }
}

/* Parse objc-class-instance-variables.

   objc-class-instance-variables:
     { objc-instance-variable-decl-list[opt] }

   objc-instance-variable-decl-list:
     objc-visibility-spec
     objc-instance-variable-decl ;
     ;
     objc-instance-variable-decl-list objc-visibility-spec
     objc-instance-variable-decl-list objc-instance-variable-decl ;
     objc-instance-variable-decl-list ;

   objc-visibility-spec:
     @private
     @protected
     @public

   objc-instance-variable-decl:
     struct-declaration
*/

static void
c_parser_objc_class_instance_variables (c_parser *parser)
{
  gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
  c_parser_consume_token (parser);
  while (c_parser_next_token_is_not (parser, CPP_EOF))
    {
      tree decls;
      /* Parse any stray semicolon.  */
      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	{
	  pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
		   "extra semicolon in struct or union specified");
	  c_parser_consume_token (parser);
	  continue;
	}
      /* Stop if at the end of the instance variables.  */
      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	{
	  c_parser_consume_token (parser);
	  break;
	}
      /* Parse any objc-visibility-spec.  */
      if (c_parser_next_token_is_keyword (parser, RID_PRIVATE))
	{
	  c_parser_consume_token (parser);
	  objc_set_visibility (2);
	  continue;
	}
      else if (c_parser_next_token_is_keyword (parser, RID_PROTECTED))
	{
	  c_parser_consume_token (parser);
	  objc_set_visibility (0);
	  continue;
	}
      else if (c_parser_next_token_is_keyword (parser, RID_PUBLIC))
	{
	  c_parser_consume_token (parser);
	  objc_set_visibility (1);
	  continue;
	}
      else if (c_parser_next_token_is (parser, CPP_PRAGMA))
	{
	  c_parser_pragma (parser, pragma_external);
	  continue;
	}

      /* Parse some comma-separated declarations.  */
      decls = c_parser_struct_declaration (parser);
      {
	/* Comma-separated instance variables are chained together in
	   reverse order; add them one by one.  */
	tree ivar = nreverse (decls);
	for (; ivar; ivar = TREE_CHAIN (ivar))
	  objc_add_instance_variable (copy_node (ivar));
      }
      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
    }
}

/* Parse an objc-class-declaration.

   objc-class-declaration:
     @class identifier-list ;
*/

static void
c_parser_objc_class_declaration (c_parser *parser)
{
  tree list = NULL_TREE;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_CLASS));
  c_parser_consume_token (parser);
  /* Any identifiers, including those declared as type names, are OK
     here.  */
  while (true)
    {
      tree id;
      if (c_parser_next_token_is_not (parser, CPP_NAME))
	{
	  c_parser_error (parser, "expected identifier");
	  break;
	}
      id = c_parser_peek_token (parser)->value;
      list = chainon (list, build_tree_list (NULL_TREE, id));
      c_parser_consume_token (parser);
      if (c_parser_next_token_is (parser, CPP_COMMA))
	c_parser_consume_token (parser);
      else
	break;
    }
  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
  objc_declare_class (list);
}

/* Parse an objc-alias-declaration.

   objc-alias-declaration:
     @compatibility_alias identifier identifier ;
*/

static void
c_parser_objc_alias_declaration (c_parser *parser)
{
  tree id1, id2;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS));
  c_parser_consume_token (parser);
  if (c_parser_next_token_is_not (parser, CPP_NAME))
    {
      c_parser_error (parser, "expected identifier");
      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
      return;
    }
  id1 = c_parser_peek_token (parser)->value;
  c_parser_consume_token (parser);
  if (c_parser_next_token_is_not (parser, CPP_NAME))
    {
      c_parser_error (parser, "expected identifier");
      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
      return;
    }
  id2 = c_parser_peek_token (parser)->value;
  c_parser_consume_token (parser);
  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
  objc_declare_alias (id1, id2);
}

/* Parse an objc-protocol-definition.

   objc-protocol-definition:
     @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end
     @protocol identifier-list ;

   "@protocol identifier ;" should be resolved as "@protocol
   identifier-list ;": objc-methodprotolist may not start with a
   semicolon in the first alternative if objc-protocol-refs are
   omitted.  */

static void
c_parser_objc_protocol_definition (c_parser *parser)
{
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL));
  c_parser_consume_token (parser);
  if (c_parser_next_token_is_not (parser, CPP_NAME))
    {
      c_parser_error (parser, "expected identifier");
      return;
    }
  if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
      || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON)
    {
      tree list = NULL_TREE;
      /* Any identifiers, including those declared as type names, are
	 OK here.  */
      while (true)
	{
	  tree id;
	  if (c_parser_next_token_is_not (parser, CPP_NAME))
	    {
	      c_parser_error (parser, "expected identifier");
	      break;
	    }
	  id = c_parser_peek_token (parser)->value;
	  list = chainon (list, build_tree_list (NULL_TREE, id));
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_COMMA))
	    c_parser_consume_token (parser);
	  else
	    break;
	}
      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
      objc_declare_protocols (list);
    }
  else
    {
      tree id = c_parser_peek_token (parser)->value;
      tree proto = NULL_TREE;
      c_parser_consume_token (parser);
      if (c_parser_next_token_is (parser, CPP_LESS))
	proto = c_parser_objc_protocol_refs (parser);
      parser->objc_pq_context = true;
      objc_start_protocol (id, proto);
      c_parser_objc_methodprotolist (parser);
      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
      parser->objc_pq_context = false;
      objc_finish_interface ();
    }
}

/* Parse an objc-method-type.

   objc-method-type:
     +
     -
*/

static enum tree_code
c_parser_objc_method_type (c_parser *parser)
{
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_PLUS:
      c_parser_consume_token (parser);
      return PLUS_EXPR;
    case CPP_MINUS:
      c_parser_consume_token (parser);
      return MINUS_EXPR;
    default:
      gcc_unreachable ();
    }
}

/* Parse an objc-method-definition.

   objc-method-definition:
     objc-method-type objc-method-decl ;[opt] compound-statement
*/

static void
c_parser_objc_method_definition (c_parser *parser)
{
  enum tree_code type = c_parser_objc_method_type (parser);
  tree decl;
  objc_set_method_type (type);
  parser->objc_pq_context = true;
  decl = c_parser_objc_method_decl (parser);
  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
    {
      c_parser_consume_token (parser);
      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
	       "extra semicolon in method definition specified");
    }
  if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
    {
      c_parser_error (parser, "expected %<{%>");
      return;
    }
  parser->objc_pq_context = false;
  objc_start_method_definition (decl);
  add_stmt (c_parser_compound_statement (parser));
  objc_finish_method_definition (current_function_decl);
}

/* Parse an objc-methodprotolist.

   objc-methodprotolist:
     empty
     objc-methodprotolist objc-methodproto
     objc-methodprotolist declaration
     objc-methodprotolist ;

   The declaration is a data definition, which may be missing
   declaration specifiers under the same rules and diagnostics as
   other data definitions outside functions, and the stray semicolon
   is diagnosed the same way as a stray semicolon outside a
   function.  */

static void
c_parser_objc_methodprotolist (c_parser *parser)
{
  while (true)
    {
      /* The list is terminated by @end.  */
      switch (c_parser_peek_token (parser)->type)
	{
	case CPP_SEMICOLON:
	  pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
		   "ISO C does not allow extra %<;%> outside of a function");
	  c_parser_consume_token (parser);
	  break;
	case CPP_PLUS:
	case CPP_MINUS:
	  c_parser_objc_methodproto (parser);
	  break;
	case CPP_PRAGMA:
	  c_parser_pragma (parser, pragma_external);
	  break;
	case CPP_EOF:
	  return;
	default:
	  if (c_parser_next_token_is_keyword (parser, RID_AT_END))
	    return;
	  c_parser_declaration_or_fndef (parser, false, true, false, true);
	  break;
	}
    }
}

/* Parse an objc-methodproto.

   objc-methodproto:
     objc-method-type objc-method-decl ;
*/

static void
c_parser_objc_methodproto (c_parser *parser)
{
  enum tree_code type = c_parser_objc_method_type (parser);
  tree decl;
  objc_set_method_type (type);
  /* Remember protocol qualifiers in prototypes.  */
  parser->objc_pq_context = true;
  decl = c_parser_objc_method_decl (parser);
  /* Forget protocol qualifiers here.  */
  parser->objc_pq_context = false;
  objc_add_method_declaration (decl);
  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}

/* Parse an objc-method-decl.

   objc-method-decl:
     ( objc-type-name ) objc-selector
     objc-selector
     ( objc-type-name ) objc-keyword-selector objc-optparmlist
     objc-keyword-selector objc-optparmlist

   objc-keyword-selector:
     objc-keyword-decl
     objc-keyword-selector objc-keyword-decl

   objc-keyword-decl:
     objc-selector : ( objc-type-name ) identifier
     objc-selector : identifier
     : ( objc-type-name ) identifier
     : identifier

   objc-optparmlist:
     objc-optparms objc-optellipsis

   objc-optparms:
     empty
     objc-opt-parms , parameter-declaration

   objc-optellipsis:
     empty
     , ...
*/

static tree
c_parser_objc_method_decl (c_parser *parser)
{
  tree type = NULL_TREE;
  tree sel;
  tree parms = NULL_TREE;
  bool ellipsis = false;

  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    {
      c_parser_consume_token (parser);
      type = c_parser_objc_type_name (parser);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  sel = c_parser_objc_selector (parser);
  /* If there is no selector, or a colon follows, we have an
     objc-keyword-selector.  If there is a selector, and a colon does
     not follow, that selector ends the objc-method-decl.  */
  if (!sel || c_parser_next_token_is (parser, CPP_COLON))
    {
      tree tsel = sel;
      tree list = NULL_TREE;
      while (true)
	{
	  tree atype = NULL_TREE, id, keyworddecl;
	  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
	    break;
	  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
	    {
	      c_parser_consume_token (parser);
	      atype = c_parser_objc_type_name (parser);
	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
					 "expected %<)%>");
	    }
	  if (c_parser_next_token_is_not (parser, CPP_NAME))
	    {
	      c_parser_error (parser, "expected identifier");
	      return error_mark_node;
	    }
	  id = c_parser_peek_token (parser)->value;
	  c_parser_consume_token (parser);
	  keyworddecl = objc_build_keyword_decl (tsel, atype, id);
	  list = chainon (list, keyworddecl);
	  tsel = c_parser_objc_selector (parser);
	  if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON))
	    break;
	}
      /* Parse the optional parameter list.  Optional Objective-C
	 method parameters follow the C syntax, and may include '...'
	 to denote a variable number of arguments.  */
      parms = make_node (TREE_LIST);
      while (c_parser_next_token_is (parser, CPP_COMMA))
	{
	  struct c_parm *parm;
	  c_parser_consume_token (parser);
	  if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
	    {
	      ellipsis = true;
	      c_parser_consume_token (parser);
	      break;
	    }
	  parm = c_parser_parameter_declaration (parser, NULL_TREE);
	  if (parm == NULL)
	    break;
	  parms = chainon (parms,
			   build_tree_list (NULL_TREE, grokparm (parm)));
	}
      sel = list;
    }
  return objc_build_method_signature (type, sel, parms, ellipsis);
}

/* Parse an objc-type-name.

   objc-type-name:
     objc-type-qualifiers[opt] type-name
     objc-type-qualifiers[opt]

   objc-type-qualifiers:
     objc-type-qualifier
     objc-type-qualifiers objc-type-qualifier

   objc-type-qualifier: one of
     in out inout bycopy byref oneway
*/

static tree
c_parser_objc_type_name (c_parser *parser)
{
  tree quals = NULL_TREE;
  struct c_type_name *type_name = NULL;
  tree type = NULL_TREE;
  while (true)
    {
      c_token *token = c_parser_peek_token (parser);
      if (token->type == CPP_KEYWORD
	  && (token->keyword == RID_IN
	      || token->keyword == RID_OUT
	      || token->keyword == RID_INOUT
	      || token->keyword == RID_BYCOPY
	      || token->keyword == RID_BYREF
	      || token->keyword == RID_ONEWAY))
	{
	  quals = chainon (quals, build_tree_list (NULL_TREE, token->value));
	  c_parser_consume_token (parser);
	}
      else
	break;
    }
  if (c_parser_next_token_starts_typename (parser))
    type_name = c_parser_type_name (parser);
  if (type_name)
    type = groktypename (type_name);
  return build_tree_list (quals, type);
}

/* Parse objc-protocol-refs.

   objc-protocol-refs:
     < identifier-list >
*/

static tree
c_parser_objc_protocol_refs (c_parser *parser)
{
  tree list = NULL_TREE;
  gcc_assert (c_parser_next_token_is (parser, CPP_LESS));
  c_parser_consume_token (parser);
  /* Any identifiers, including those declared as type names, are OK
     here.  */
  while (true)
    {
      tree id;
      if (c_parser_next_token_is_not (parser, CPP_NAME))
	{
	  c_parser_error (parser, "expected identifier");
	  break;
	}
      id = c_parser_peek_token (parser)->value;
      list = chainon (list, build_tree_list (NULL_TREE, id));
      c_parser_consume_token (parser);
      if (c_parser_next_token_is (parser, CPP_COMMA))
	c_parser_consume_token (parser);
      else
	break;
    }
  c_parser_require (parser, CPP_GREATER, "expected %<>%>");
  return list;
}

/* Parse an objc-try-catch-statement.

   objc-try-catch-statement:
     @try compound-statement objc-catch-list[opt]
     @try compound-statement objc-catch-list[opt] @finally compound-statement

   objc-catch-list:
     @catch ( parameter-declaration ) compound-statement
     objc-catch-list @catch ( parameter-declaration ) compound-statement
*/

static void
c_parser_objc_try_catch_statement (c_parser *parser)
{
  location_t loc;
  tree stmt;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRY));
  c_parser_consume_token (parser);
  loc = c_parser_peek_token (parser)->location;
  stmt = c_parser_compound_statement (parser);
  objc_begin_try_stmt (loc, stmt);
  while (c_parser_next_token_is_keyword (parser, RID_CATCH))
    {
      struct c_parm *parm;
      c_parser_consume_token (parser);
      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	break;
      parm = c_parser_parameter_declaration (parser, NULL_TREE);
      if (parm == NULL)
	{
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
	  break;
	}
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
      objc_begin_catch_clause (grokparm (parm));
      if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
	c_parser_compound_statement_nostart (parser);
      objc_finish_catch_clause ();
    }
  if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
    {
      location_t finloc;
      tree finstmt;
      c_parser_consume_token (parser);
      finloc = c_parser_peek_token (parser)->location;
      finstmt = c_parser_compound_statement (parser);
      objc_build_finally_clause (finloc, finstmt);
    }
  objc_finish_try_stmt ();
}

/* Parse an objc-synchronized-statement.

   objc-synchronized-statement:
     @synchronized ( expression ) compound-statement
*/

static void
c_parser_objc_synchronized_statement (c_parser *parser)
{
  location_t loc;
  tree expr, stmt;
  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
  c_parser_consume_token (parser);
  loc = c_parser_peek_token (parser)->location;
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      expr = c_parser_expression (parser).value;
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  else
    expr = error_mark_node;
  stmt = c_parser_compound_statement (parser);
  objc_build_synchronized (loc, expr, stmt);
}

/* Parse an objc-selector; return NULL_TREE without an error if the
   next token is not an objc-selector.

   objc-selector:
     identifier
     one of
       enum struct union if else while do for switch case default
       break continue return goto asm sizeof typeof __alignof
       unsigned long const short volatile signed restrict _Complex
       in out inout bycopy byref oneway int char float double void _Bool

   ??? Why this selection of keywords but not, for example, storage
   class specifiers?  */

static tree
c_parser_objc_selector (c_parser *parser)
{
  c_token *token = c_parser_peek_token (parser);
  tree value = token->value;
  if (token->type == CPP_NAME)
    {
      c_parser_consume_token (parser);
      return value;
    }
  if (token->type != CPP_KEYWORD)
    return NULL_TREE;
  switch (token->keyword)
    {
    case RID_ENUM:
    case RID_STRUCT:
    case RID_UNION:
    case RID_IF:
    case RID_ELSE:
    case RID_WHILE:
    case RID_DO:
    case RID_FOR:
    case RID_SWITCH:
    case RID_CASE:
    case RID_DEFAULT:
    case RID_BREAK:
    case RID_CONTINUE:
    case RID_RETURN:
    case RID_GOTO:
    case RID_ASM:
    case RID_SIZEOF:
    case RID_TYPEOF:
    case RID_ALIGNOF:
    case RID_UNSIGNED:
    case RID_LONG:
    case RID_CONST:
    case RID_SHORT:
    case RID_VOLATILE:
    case RID_SIGNED:
    case RID_RESTRICT:
    case RID_COMPLEX:
    case RID_IN:
    case RID_OUT:
    case RID_INOUT:
    case RID_BYCOPY:
    case RID_BYREF:
    case RID_ONEWAY:
    case RID_INT:
    case RID_CHAR:
    case RID_FLOAT:
    case RID_DOUBLE:
    case RID_VOID:
    case RID_BOOL:
      c_parser_consume_token (parser);
      return value;
    default:
      return NULL_TREE;
    }
}

/* Parse an objc-selector-arg.

   objc-selector-arg:
     objc-selector
     objc-keywordname-list

   objc-keywordname-list:
     objc-keywordname
     objc-keywordname-list objc-keywordname

   objc-keywordname:
     objc-selector :
     :
*/

static tree
c_parser_objc_selector_arg (c_parser *parser)
{
  tree sel = c_parser_objc_selector (parser);
  tree list = NULL_TREE;
  if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
    return sel;
  while (true)
    {
      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
	return list;
      list = chainon (list, build_tree_list (sel, NULL_TREE));
      sel = c_parser_objc_selector (parser);
      if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
	break;
    }
  return list;
}

/* Parse an objc-receiver.

   objc-receiver:
     expression
     class-name
     type-name
*/

static tree
c_parser_objc_receiver (c_parser *parser)
{
  if (c_parser_peek_token (parser)->type == CPP_NAME
      && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
	  || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
    {
      tree id = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
      return objc_get_class_reference (id);
    }
  return c_parser_expression (parser).value;
}

/* Parse objc-message-args.

   objc-message-args:
     objc-selector
     objc-keywordarg-list

   objc-keywordarg-list:
     objc-keywordarg
     objc-keywordarg-list objc-keywordarg

   objc-keywordarg:
     objc-selector : objc-keywordexpr
     : objc-keywordexpr
*/

static tree
c_parser_objc_message_args (c_parser *parser)
{
  tree sel = c_parser_objc_selector (parser);
  tree list = NULL_TREE;
  if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
    return sel;
  while (true)
    {
      tree keywordexpr;
      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
	return list;
      keywordexpr = c_parser_objc_keywordexpr (parser);
      list = chainon (list, build_tree_list (sel, keywordexpr));
      sel = c_parser_objc_selector (parser);
      if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
	break;
    }
  return list;
}

/* Parse an objc-keywordexpr.

   objc-keywordexpr:
     nonempty-expr-list
*/

static tree
c_parser_objc_keywordexpr (c_parser *parser)
{
  tree list = c_parser_expr_list (parser, true);
  if (TREE_CHAIN (list) == NULL_TREE)
    {
      /* Just return the expression, remove a level of
	 indirection.  */
      return TREE_VALUE (list);
    }
  else
    {
      /* We have a comma expression, we will collapse later.  */
      return list;
    }
}


/* Handle pragmas.  Some OpenMP pragmas are associated with, and therefore
   should be considered, statements.  ALLOW_STMT is true if we're within
   the context of a function and such pragmas are to be allowed.  Returns
   true if we actually parsed such a pragma.  */

static bool
c_parser_pragma (c_parser *parser, enum pragma_context context)
{
  unsigned int id;

  id = c_parser_peek_token (parser)->pragma_kind;
  gcc_assert (id != PRAGMA_NONE);

  switch (id)
    {
    case PRAGMA_OMP_BARRIER:
      if (context != pragma_compound)
	{
	  if (context == pragma_stmt)
	    c_parser_error (parser, "%<#pragma omp barrier%> may only be "
			    "used in compound statements");
	  goto bad_stmt;
	}
      c_parser_omp_barrier (parser);
      return false;

    case PRAGMA_OMP_FLUSH:
      if (context != pragma_compound)
	{
	  if (context == pragma_stmt)
	    c_parser_error (parser, "%<#pragma omp flush%> may only be "
			    "used in compound statements");
	  goto bad_stmt;
	}
      c_parser_omp_flush (parser);
      return false;

    case PRAGMA_OMP_TASKWAIT:
      if (context != pragma_compound)
	{
	  if (context == pragma_stmt)
	    c_parser_error (parser, "%<#pragma omp taskwait%> may only be "
			    "used in compound statements");
	  goto bad_stmt;
	}
      c_parser_omp_taskwait (parser);
      return false;

    case PRAGMA_OMP_THREADPRIVATE:
      c_parser_omp_threadprivate (parser);
      return false;

    case PRAGMA_OMP_SECTION:
      error_at (c_parser_peek_token (parser)->location,
		"%<#pragma omp section%> may only be used in "
		"%<#pragma omp sections%> construct");
      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
      return false;

    case PRAGMA_GCC_PCH_PREPROCESS:
      c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
      return false;

    default:
      if (id < PRAGMA_FIRST_EXTERNAL)
	{
	  if (context == pragma_external)
	    {
	    bad_stmt:
	      c_parser_error (parser, "expected declaration specifiers");
	      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
	      return false;
	    }
	  c_parser_omp_construct (parser);
	  return true;
	}
      break;
    }

  c_parser_consume_pragma (parser);
  c_invoke_pragma_handler (id);

  /* Skip to EOL, but suppress any error message.  Those will have been 
     generated by the handler routine through calling error, as opposed
     to calling c_parser_error.  */
  parser->error = true;
  c_parser_skip_to_pragma_eol (parser);

  return false;
}

/* The interface the pragma parsers have to the lexer.  */

enum cpp_ttype
pragma_lex (tree *value)
{
  c_token *tok = c_parser_peek_token (the_parser);
  enum cpp_ttype ret = tok->type;

  *value = tok->value;
  if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
    ret = CPP_EOF;
  else
    {
      if (ret == CPP_KEYWORD)
	ret = CPP_NAME;
      c_parser_consume_token (the_parser);
    }

  return ret;
}

static void
c_parser_pragma_pch_preprocess (c_parser *parser)
{
  tree name = NULL;

  c_parser_consume_pragma (parser);
  if (c_parser_next_token_is (parser, CPP_STRING))
    {
      name = c_parser_peek_token (parser)->value;
      c_parser_consume_token (parser);
    }
  else
    c_parser_error (parser, "expected string literal");
  c_parser_skip_to_pragma_eol (parser);

  if (name)
    c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
}

/* OpenMP 2.5 parsing routines.  */

/* Returns name of the next clause.
   If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
   the token is not consumed.  Otherwise appropriate pragma_omp_clause is
   returned and the token is consumed.  */

static pragma_omp_clause
c_parser_omp_clause_name (c_parser *parser)
{
  pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE;

  if (c_parser_next_token_is_keyword (parser, RID_IF))
    result = PRAGMA_OMP_CLAUSE_IF;
  else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
    result = PRAGMA_OMP_CLAUSE_DEFAULT;
  else if (c_parser_next_token_is (parser, CPP_NAME))
    {
      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);

      switch (p[0])
	{
	case 'c':
	  if (!strcmp ("collapse", p))
	    result = PRAGMA_OMP_CLAUSE_COLLAPSE;
	  else if (!strcmp ("copyin", p))
	    result = PRAGMA_OMP_CLAUSE_COPYIN;
          else if (!strcmp ("copyprivate", p))
	    result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
	  break;
	case 'f':
	  if (!strcmp ("firstprivate", p))
	    result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
	  break;
	case 'l':
	  if (!strcmp ("lastprivate", p))
	    result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
	  break;
	case 'n':
	  if (!strcmp ("nowait", p))
	    result = PRAGMA_OMP_CLAUSE_NOWAIT;
	  else if (!strcmp ("num_threads", p))
	    result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
	  break;
	case 'o':
	  if (!strcmp ("ordered", p))
	    result = PRAGMA_OMP_CLAUSE_ORDERED;
	  break;
	case 'p':
	  if (!strcmp ("private", p))
	    result = PRAGMA_OMP_CLAUSE_PRIVATE;
	  break;
	case 'r':
	  if (!strcmp ("reduction", p))
	    result = PRAGMA_OMP_CLAUSE_REDUCTION;
	  break;
	case 's':
	  if (!strcmp ("schedule", p))
	    result = PRAGMA_OMP_CLAUSE_SCHEDULE;
	  else if (!strcmp ("shared", p))
	    result = PRAGMA_OMP_CLAUSE_SHARED;
	  break;
	case 'u':
	  if (!strcmp ("untied", p))
	    result = PRAGMA_OMP_CLAUSE_UNTIED;
	  break;
	}
    }

  if (result != PRAGMA_OMP_CLAUSE_NONE)
    c_parser_consume_token (parser);

  return result;
}

/* Validate that a clause of the given type does not already exist.  */

static void
check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
			   const char *name)
{
  tree c;

  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
    if (OMP_CLAUSE_CODE (c) == code)
      {
	error ("too many %qs clauses", name);
	break;
      }
}

/* OpenMP 2.5:
   variable-list:
     identifier
     variable-list , identifier

   If KIND is nonzero, create the appropriate node and install the decl
   in OMP_CLAUSE_DECL and add the node to the head of the list.

   If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE;
   return the list created.  */

static tree
c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind,
                            tree list)
{
  if (c_parser_next_token_is_not (parser, CPP_NAME)
      || c_parser_peek_token (parser)->id_kind != C_ID_ID)
    c_parser_error (parser, "expected identifier");

  while (c_parser_next_token_is (parser, CPP_NAME)
	 && c_parser_peek_token (parser)->id_kind == C_ID_ID)
    {
      tree t = lookup_name (c_parser_peek_token (parser)->value);

      if (t == NULL_TREE)
	undeclared_variable (c_parser_peek_token (parser)->value,
			     c_parser_peek_token (parser)->location);
      else if (t == error_mark_node)
	;
      else if (kind != 0)
	{
	  tree u = build_omp_clause (kind);
	  OMP_CLAUSE_DECL (u) = t;
	  OMP_CLAUSE_CHAIN (u) = list;
	  list = u;
	}
      else
	list = tree_cons (t, NULL_TREE, list);

      c_parser_consume_token (parser);

      if (c_parser_next_token_is_not (parser, CPP_COMMA))
	break;

      c_parser_consume_token (parser);
    }

  return list;
}

/* Similarly, but expect leading and trailing parenthesis.  This is a very
   common case for omp clauses.  */

static tree
c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
			      tree list)
{
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      list = c_parser_omp_variable_list (parser, kind, list);
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  return list;
}

/* OpenMP 3.0:
   collapse ( constant-expression ) */

static tree
c_parser_omp_clause_collapse (c_parser *parser, tree list)
{
  tree c, num = error_mark_node;
  HOST_WIDE_INT n;
  location_t loc;

  check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse");

  loc = c_parser_peek_token (parser)->location;
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      num = c_parser_expr_no_commas (parser, NULL).value;
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  if (num == error_mark_node)
    return list;
  if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
      || !host_integerp (num, 0)
      || (n = tree_low_cst (num, 0)) <= 0
      || (int) n != n)
    {
      error_at (loc,
		"collapse argument needs positive constant integer expression");
      return list;
    }
  c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
  OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
  OMP_CLAUSE_CHAIN (c) = list;
  return c;
}

/* OpenMP 2.5:
   copyin ( variable-list ) */

static tree
c_parser_omp_clause_copyin (c_parser *parser, tree list)
{
  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list);
}

/* OpenMP 2.5:
   copyprivate ( variable-list ) */

static tree
c_parser_omp_clause_copyprivate (c_parser *parser, tree list)
{
  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list);
}

/* OpenMP 2.5:
   default ( shared | none ) */

static tree
c_parser_omp_clause_default (c_parser *parser, tree list)
{
  enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
  tree c;

  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    return list;
  if (c_parser_next_token_is (parser, CPP_NAME))
    {
      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);

      switch (p[0])
	{
	case 'n':
	  if (strcmp ("none", p) != 0)
	    goto invalid_kind;
	  kind = OMP_CLAUSE_DEFAULT_NONE;
	  break;

	case 's':
	  if (strcmp ("shared", p) != 0)
	    goto invalid_kind;
	  kind = OMP_CLAUSE_DEFAULT_SHARED;
	  break;

	default:
	  goto invalid_kind;
	}

      c_parser_consume_token (parser);
    }
  else
    {
    invalid_kind:
      c_parser_error (parser, "expected %<none%> or %<shared%>");
    }
  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");

  if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
    return list;

  check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default");
  c = build_omp_clause (OMP_CLAUSE_DEFAULT);
  OMP_CLAUSE_CHAIN (c) = list;
  OMP_CLAUSE_DEFAULT_KIND (c) = kind;

  return c;
}

/* OpenMP 2.5:
   firstprivate ( variable-list ) */

static tree
c_parser_omp_clause_firstprivate (c_parser *parser, tree list)
{
  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
}

/* OpenMP 2.5:
   if ( expression ) */

static tree
c_parser_omp_clause_if (c_parser *parser, tree list)
{
  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    {
      tree t = c_parser_paren_condition (parser);
      tree c;

      check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");

      c = build_omp_clause (OMP_CLAUSE_IF);
      OMP_CLAUSE_IF_EXPR (c) = t;
      OMP_CLAUSE_CHAIN (c) = list;
      list = c;
    }
  else
    c_parser_error (parser, "expected %<(%>");

  return list;
}

/* OpenMP 2.5:
   lastprivate ( variable-list ) */

static tree
c_parser_omp_clause_lastprivate (c_parser *parser, tree list)
{
  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
}

/* OpenMP 2.5:
   nowait */

static tree
c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
{
  tree c;

  check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");

  c = build_omp_clause (OMP_CLAUSE_NOWAIT);
  OMP_CLAUSE_CHAIN (c) = list;
  return c;
}

/* OpenMP 2.5:
   num_threads ( expression ) */

static tree
c_parser_omp_clause_num_threads (c_parser *parser, tree list)
{
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      location_t expr_loc = c_parser_peek_token (parser)->location;
      tree c, t = c_parser_expression (parser).value;

      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");

      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
	{
	  c_parser_error (parser, "expected integer expression");
	  return list;
	}

      /* Attempt to statically determine when the number isn't positive.  */
      c = fold_build2 (LE_EXPR, boolean_type_node, t,
		       build_int_cst (TREE_TYPE (t), 0));
      if (c == boolean_true_node)
	{
	  warning_at (expr_loc, 0,
		      "%<num_threads%> value must be positive");
	  t = integer_one_node;
	}

      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads");

      c = build_omp_clause (OMP_CLAUSE_NUM_THREADS);
      OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
      OMP_CLAUSE_CHAIN (c) = list;
      list = c;
    }

  return list;
}

/* OpenMP 2.5:
   ordered */

static tree
c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list)
{
  tree c;

  check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");

  c = build_omp_clause (OMP_CLAUSE_ORDERED);
  OMP_CLAUSE_CHAIN (c) = list;
  return c;
}

/* OpenMP 2.5:
   private ( variable-list ) */

static tree
c_parser_omp_clause_private (c_parser *parser, tree list)
{
  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list);
}

/* OpenMP 2.5:
   reduction ( reduction-operator : variable-list )

   reduction-operator:
     One of: + * - & ^ | && || */

static tree
c_parser_omp_clause_reduction (c_parser *parser, tree list)
{
  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    {
      enum tree_code code;

      switch (c_parser_peek_token (parser)->type)
	{
	case CPP_PLUS:
	  code = PLUS_EXPR;
	  break;
	case CPP_MULT:
	  code = MULT_EXPR;
	  break;
	case CPP_MINUS:
	  code = MINUS_EXPR;
	  break;
	case CPP_AND:
	  code = BIT_AND_EXPR;
	  break;
	case CPP_XOR:
	  code = BIT_XOR_EXPR;
	  break;
	case CPP_OR:
	  code = BIT_IOR_EXPR;
	  break;
	case CPP_AND_AND:
	  code = TRUTH_ANDIF_EXPR;
	  break;
	case CPP_OR_OR:
	  code = TRUTH_ORIF_EXPR;
	  break;
	default:
	  c_parser_error (parser,
			  "expected %<+%>, %<*%>, %<-%>, %<&%>, "
			  "%<^%>, %<|%>, %<&&%>, or %<||%>");
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
	  return list;
	}
      c_parser_consume_token (parser);
      if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
	{
	  tree nl, c;

	  nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list);
	  for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
	    OMP_CLAUSE_REDUCTION_CODE (c) = code;

	  list = nl;
	}
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  return list;
}

/* OpenMP 2.5:
   schedule ( schedule-kind )
   schedule ( schedule-kind , expression )

   schedule-kind:
     static | dynamic | guided | runtime | auto
*/

static tree
c_parser_omp_clause_schedule (c_parser *parser, tree list)
{
  tree c, t;

  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
    return list;

  c = build_omp_clause (OMP_CLAUSE_SCHEDULE);

  if (c_parser_next_token_is (parser, CPP_NAME))
    {
      tree kind = c_parser_peek_token (parser)->value;
      const char *p = IDENTIFIER_POINTER (kind);

      switch (p[0])
	{
	case 'd':
	  if (strcmp ("dynamic", p) != 0)
	    goto invalid_kind;
	  OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
	  break;

        case 'g':
	  if (strcmp ("guided", p) != 0)
	    goto invalid_kind;
	  OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
	  break;

	case 'r':
	  if (strcmp ("runtime", p) != 0)
	    goto invalid_kind;
	  OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
	  break;

	default:
	  goto invalid_kind;
	}
    }
  else if (c_parser_next_token_is_keyword (parser, RID_STATIC))
    OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
  else if (c_parser_next_token_is_keyword (parser, RID_AUTO))
    OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
  else
    goto invalid_kind;

  c_parser_consume_token (parser);
  if (c_parser_next_token_is (parser, CPP_COMMA))
    {
      location_t here;
      c_parser_consume_token (parser);

      here = c_parser_peek_token (parser)->location;
      t = c_parser_expr_no_commas (parser, NULL).value;

      if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
	error_at (here, "schedule %<runtime%> does not take "
		  "a %<chunk_size%> parameter");
      else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
	error_at (here,
		  "schedule %<auto%> does not take "
		  "a %<chunk_size%> parameter");
      else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
	OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
      else
	c_parser_error (parser, "expected integer expression");

      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
    }
  else
    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
			       "expected %<,%> or %<)%>");

  check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
  OMP_CLAUSE_CHAIN (c) = list;
  return c;

 invalid_kind:
  c_parser_error (parser, "invalid schedule kind");
  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
  return list;
}

/* OpenMP 2.5:
   shared ( variable-list ) */

static tree
c_parser_omp_clause_shared (c_parser *parser, tree list)
{
  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list);
}

/* OpenMP 3.0:
   untied */

static tree
c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
{
  tree c;

  /* FIXME: Should we allow duplicates?  */
  check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied");

  c = build_omp_clause (OMP_CLAUSE_UNTIED);
  OMP_CLAUSE_CHAIN (c) = list;
  return c;
}

/* Parse all OpenMP clauses.  The set clauses allowed by the directive
   is a bitmask in MASK.  Return the list of clauses found; the result
   of clause default goes in *pdefault.  */

static tree
c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
			  const char *where)
{
  tree clauses = NULL;
  bool first = true;

  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
    {
      location_t here;
      pragma_omp_clause c_kind;
      const char *c_name;
      tree prev = clauses;

      if (!first && c_parser_next_token_is (parser, CPP_COMMA))
	c_parser_consume_token (parser);

      first = false;
      here = c_parser_peek_token (parser)->location;
      c_kind = c_parser_omp_clause_name (parser);

      switch (c_kind)
	{
	case PRAGMA_OMP_CLAUSE_COLLAPSE:
	  clauses = c_parser_omp_clause_collapse (parser, clauses);
	  c_name = "collapse";
	  break;
	case PRAGMA_OMP_CLAUSE_COPYIN:
	  clauses = c_parser_omp_clause_copyin (parser, clauses);
	  c_name = "copyin";
	  break;
	case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
	  clauses = c_parser_omp_clause_copyprivate (parser, clauses);
	  c_name = "copyprivate";
	  break;
	case PRAGMA_OMP_CLAUSE_DEFAULT:
	  clauses = c_parser_omp_clause_default (parser, clauses);
	  c_name = "default";
	  break;
	case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
	  c_name = "firstprivate";
	  break;
	case PRAGMA_OMP_CLAUSE_IF:
	  clauses = c_parser_omp_clause_if (parser, clauses);
	  c_name = "if";
	  break;
	case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
	  clauses = c_parser_omp_clause_lastprivate (parser, clauses);
	  c_name = "lastprivate";
	  break;
	case PRAGMA_OMP_CLAUSE_NOWAIT:
	  clauses = c_parser_omp_clause_nowait (parser, clauses);
	  c_name = "nowait";
	  break;
	case PRAGMA_OMP_CLAUSE_NUM_THREADS:
	  clauses = c_parser_omp_clause_num_threads (parser, clauses);
	  c_name = "num_threads";
	  break;
	case PRAGMA_OMP_CLAUSE_ORDERED:
	  clauses = c_parser_omp_clause_ordered (parser, clauses);
	  c_name = "ordered";
	  break;
	case PRAGMA_OMP_CLAUSE_PRIVATE:
	  clauses = c_parser_omp_clause_private (parser, clauses);
	  c_name = "private";
	  break;
	case PRAGMA_OMP_CLAUSE_REDUCTION:
	  clauses = c_parser_omp_clause_reduction (parser, clauses);
	  c_name = "reduction";
	  break;
	case PRAGMA_OMP_CLAUSE_SCHEDULE:
	  clauses = c_parser_omp_clause_schedule (parser, clauses);
	  c_name = "schedule";
	  break;
	case PRAGMA_OMP_CLAUSE_SHARED:
	  clauses = c_parser_omp_clause_shared (parser, clauses);
	  c_name = "shared";
	  break;
	case PRAGMA_OMP_CLAUSE_UNTIED:
	  clauses = c_parser_omp_clause_untied (parser, clauses);
	  c_name = "untied";
	  break;
	default:
	  c_parser_error (parser, "expected %<#pragma omp%> clause");
	  goto saw_error;
	}

      if (((mask >> c_kind) & 1) == 0 && !parser->error)
	{
	  /* Remove the invalid clause(s) from the list to avoid
	     confusing the rest of the compiler.  */
	  clauses = prev;
	  error_at (here, "%qs is not valid for %qs", c_name, where);
	}
    }

 saw_error:
  c_parser_skip_to_pragma_eol (parser);

  return c_finish_omp_clauses (clauses);
}

/* OpenMP 2.5:
   structured-block:
     statement

   In practice, we're also interested in adding the statement to an
   outer node.  So it is convenient if we work around the fact that
   c_parser_statement calls add_stmt.  */

static tree
c_parser_omp_structured_block (c_parser *parser)
{
  tree stmt = push_stmt_list ();
  c_parser_statement (parser);
  return pop_stmt_list (stmt);
}

/* OpenMP 2.5:
   # pragma omp atomic new-line
     expression-stmt

   expression-stmt:
     x binop= expr | x++ | ++x | x-- | --x
   binop:
     +, *, -, /, &, ^, |, <<, >>

  where x is an lvalue expression with scalar type.  */

static void
c_parser_omp_atomic (c_parser *parser)
{
  tree lhs, rhs;
  tree stmt;
  enum tree_code code;
  struct c_expr rhs_expr;

  c_parser_skip_to_pragma_eol (parser);

  lhs = c_parser_unary_expression (parser).value;
  switch (TREE_CODE (lhs))
    {
    case ERROR_MARK:
    saw_error:
      c_parser_skip_to_end_of_block_or_statement (parser);
      return;

    case PREINCREMENT_EXPR:
    case POSTINCREMENT_EXPR:
      lhs = TREE_OPERAND (lhs, 0);
      code = PLUS_EXPR;
      rhs = integer_one_node;
      break;

    case PREDECREMENT_EXPR:
    case POSTDECREMENT_EXPR:
      lhs = TREE_OPERAND (lhs, 0);
      code = MINUS_EXPR;
      rhs = integer_one_node;
      break;

    default:
      switch (c_parser_peek_token (parser)->type)
	{
	case CPP_MULT_EQ:
	  code = MULT_EXPR;
	  break;
	case CPP_DIV_EQ:
	  code = TRUNC_DIV_EXPR;
	  break;
	case CPP_PLUS_EQ:
	  code = PLUS_EXPR;
	  break;
	case CPP_MINUS_EQ:
	  code = MINUS_EXPR;
	  break;
	case CPP_LSHIFT_EQ:
	  code = LSHIFT_EXPR;
	  break;
	case CPP_RSHIFT_EQ:
	  code = RSHIFT_EXPR;
	  break;
	case CPP_AND_EQ:
	  code = BIT_AND_EXPR;
	  break;
	case CPP_OR_EQ:
	  code = BIT_IOR_EXPR;
	  break;
	case CPP_XOR_EQ:
	  code = BIT_XOR_EXPR;
	  break;
	default:
	  c_parser_error (parser,
			  "invalid operator for %<#pragma omp atomic%>");
	  goto saw_error;
	}

      c_parser_consume_token (parser);
      rhs_expr = c_parser_expression (parser);
      rhs_expr = default_function_array_conversion (rhs_expr);
      rhs = rhs_expr.value;
      break;
    }
  stmt = c_finish_omp_atomic (code, lhs, rhs);
  if (stmt != error_mark_node)
    add_stmt (stmt);
  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}


/* OpenMP 2.5:
   # pragma omp barrier new-line
*/

static void
c_parser_omp_barrier (c_parser *parser)
{
  c_parser_consume_pragma (parser);
  c_parser_skip_to_pragma_eol (parser);

  c_finish_omp_barrier ();
}

/* OpenMP 2.5:
   # pragma omp critical [(name)] new-line
     structured-block
*/

static tree
c_parser_omp_critical (c_parser *parser)
{
  tree stmt, name = NULL;

  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    {
      c_parser_consume_token (parser);
      if (c_parser_next_token_is (parser, CPP_NAME))
	{
	  name = c_parser_peek_token (parser)->value;
	  c_parser_consume_token (parser);
	  c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
	}
      else
	c_parser_error (parser, "expected identifier");
    }
  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
    c_parser_error (parser, "expected %<(%> or end of line");
  c_parser_skip_to_pragma_eol (parser);

  stmt = c_parser_omp_structured_block (parser);
  return c_finish_omp_critical (stmt, name);
}

/* OpenMP 2.5:
   # pragma omp flush flush-vars[opt] new-line

   flush-vars:
     ( variable-list ) */

static void
c_parser_omp_flush (c_parser *parser)
{
  c_parser_consume_pragma (parser);
  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
    c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
    c_parser_error (parser, "expected %<(%> or end of line");
  c_parser_skip_to_pragma_eol (parser);

  c_finish_omp_flush ();
}

/* Parse the restricted form of the for statement allowed by OpenMP.
   The real trick here is to determine the loop control variable early
   so that we can push a new decl if necessary to make it private.  */

static tree
c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
{
  tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
  tree declv, condv, incrv, initv, for_block = NULL, ret = NULL;
  location_t loc;
  bool fail = false, open_brace_parsed = false;
  int i, collapse = 1, nbraces = 0;

  for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
    if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
      collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);

  gcc_assert (collapse >= 1);

  declv = make_tree_vec (collapse);
  initv = make_tree_vec (collapse);
  condv = make_tree_vec (collapse);
  incrv = make_tree_vec (collapse);

  if (!c_parser_next_token_is_keyword (parser, RID_FOR))
    {
      c_parser_error (parser, "for statement expected");
      return NULL;
    }
  loc = c_parser_peek_token (parser)->location;
  c_parser_consume_token (parser);

  for (i = 0; i < collapse; i++)
    {
      int bracecount = 0;

      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
	goto pop_scopes;

      /* Parse the initialization declaration or expression.  */
      if (c_parser_next_token_starts_declspecs (parser))
	{
	  if (i > 0)
	    for_block
	      = tree_cons (NULL, c_begin_compound_stmt (true), for_block);
	  c_parser_declaration_or_fndef (parser, true, true, true, true);
	  decl = check_for_loop_decls ();
	  if (decl == NULL)
	    goto error_init;
	  if (DECL_INITIAL (decl) == error_mark_node)
	    decl = error_mark_node;
	  init = decl;
	}
      else if (c_parser_next_token_is (parser, CPP_NAME)
	       && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
	{
	  struct c_expr init_exp;
	  location_t init_loc;

	  decl = c_parser_postfix_expression (parser).value;

	  c_parser_require (parser, CPP_EQ, "expected %<=%>");
	  init_loc = c_parser_peek_token (parser)->location;

	  init_exp = c_parser_expr_no_commas (parser, NULL);
	  init_exp = default_function_array_conversion (init_exp);
	  init = build_modify_expr (init_loc,
				    decl, NOP_EXPR, init_exp.value);
	  init = c_process_expr_stmt (init);

	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
	}
      else
	{
	error_init:
	  c_parser_error (parser,
			  "expected iteration declaration or initialization");
	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
				     "expected %<)%>");
	  fail = true;
	  goto parse_next;
	}

      /* Parse the loop condition.  */
      cond = NULL_TREE;
      if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
	{
	  location_t cond_loc = c_parser_peek_token (parser)->location;

	  cond = c_parser_expression_conv (parser).value;
	  cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
	  protected_set_expr_location (cond, cond_loc);
	}
      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");

      /* Parse the increment expression.  */
      incr = NULL_TREE;
      if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
	{
	  location_t incr_loc = c_parser_peek_token (parser)->location;

	  incr = c_process_expr_stmt (c_parser_expression (parser).value);
	  protected_set_expr_location (incr, incr_loc);
	}
      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");

      if (decl == NULL || decl == error_mark_node || init == error_mark_node)
	fail = true;
      else
	{
	  TREE_VEC_ELT (declv, i) = decl;
	  TREE_VEC_ELT (initv, i) = init;
	  TREE_VEC_ELT (condv, i) = cond;
	  TREE_VEC_ELT (incrv, i) = incr;
	}

    parse_next:
      if (i == collapse - 1)
	break;

      /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
	 in between the collapsed for loops to be still considered perfectly
	 nested.  Hopefully the final version clarifies this.
	 For now handle (multiple) {'s and empty statements.  */
      do
	{
	  if (c_parser_next_token_is_keyword (parser, RID_FOR))
	    {
	      c_parser_consume_token (parser);
	      break;
	    }
	  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
	    {
	      c_parser_consume_token (parser);
	      bracecount++;
	    }
	  else if (bracecount
		   && c_parser_next_token_is (parser, CPP_SEMICOLON))
	    c_parser_consume_token (parser);
	  else
	    {
	      c_parser_error (parser, "not enough perfectly nested loops");
	      if (bracecount)
		{
		  open_brace_parsed = true;
		  bracecount--;
		}
	      fail = true;
	      collapse = 0;
	      break;
	    }
	}
      while (1);

      nbraces += bracecount;
    }

  save_break = c_break_label;
  c_break_label = size_one_node;
  save_cont = c_cont_label;
  c_cont_label = NULL_TREE;
  body = push_stmt_list ();

  if (open_brace_parsed)
    {
      stmt = c_begin_compound_stmt (true);
      c_parser_compound_statement_nostart (parser);
      add_stmt (c_end_compound_stmt (stmt, true));
    }
  else
    add_stmt (c_parser_c99_block_statement (parser));
  if (c_cont_label)
    add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label));

  body = pop_stmt_list (body);
  c_break_label = save_break;
  c_cont_label = save_cont;

  while (nbraces)
    {
      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	{
	  c_parser_consume_token (parser);
	  nbraces--;
	}
      else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
	c_parser_consume_token (parser);
      else
	{
	  c_parser_error (parser, "collapsed loops not perfectly nested");
	  while (nbraces)
	    {
	      stmt = c_begin_compound_stmt (true);
	      add_stmt (body);
	      c_parser_compound_statement_nostart (parser);
	      body = c_end_compound_stmt (stmt, true);
	      nbraces--;
	    }
	  goto pop_scopes;
	}
    }

  /* Only bother calling c_finish_omp_for if we haven't already generated
     an error from the initialization parsing.  */
  if (!fail)
    {
      stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
      if (stmt)
	{
	  if (par_clauses != NULL)
	    {
	      tree *c;
	      for (c = par_clauses; *c ; )
		if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
		    && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
		  c = &OMP_CLAUSE_CHAIN (*c);
		else
		  {
		    for (i = 0; i < collapse; i++)
		      if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
			break;
		    if (i == collapse)
		      c = &OMP_CLAUSE_CHAIN (*c);
		    else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
		      {
			error_at (loc,
				  "iteration variable %qD should not be firstprivate",
				  OMP_CLAUSE_DECL (*c));
			*c = OMP_CLAUSE_CHAIN (*c);
		      }
		    else
		      {
			/* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
			   change it to shared (decl) in
			   OMP_PARALLEL_CLAUSES.  */
			tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
			OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
			OMP_CLAUSE_CHAIN (l) = clauses;
			clauses = l;
			OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
		      }
		  }
	    }
	  OMP_FOR_CLAUSES (stmt) = clauses;
	}
      ret = stmt;
    }
pop_scopes:
  while (for_block)
    {
      stmt = c_end_compound_stmt (TREE_VALUE (for_block), true);
      add_stmt (stmt);
      for_block = TREE_CHAIN (for_block);
    }
  return ret;
}

/* OpenMP 2.5:
   #pragma omp for for-clause[optseq] new-line
     for-loop
*/

#define OMP_FOR_CLAUSE_MASK				\
	( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
	| (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
	| (1u << PRAGMA_OMP_CLAUSE_ORDERED)		\
	| (1u << PRAGMA_OMP_CLAUSE_SCHEDULE)		\
	| (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)		\
	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))

static tree
c_parser_omp_for (c_parser *parser)
{
  tree block, clauses, ret;

  clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
				      "#pragma omp for");

  block = c_begin_compound_stmt (true);
  ret = c_parser_omp_for_loop (parser, clauses, NULL);
  block = c_end_compound_stmt (block, true);
  add_stmt (block);

  return ret;
}

/* OpenMP 2.5:
   # pragma omp master new-line
     structured-block
*/

static tree
c_parser_omp_master (c_parser *parser)
{
  c_parser_skip_to_pragma_eol (parser);
  return c_finish_omp_master (c_parser_omp_structured_block (parser));
}

/* OpenMP 2.5:
   # pragma omp ordered new-line
     structured-block
*/

static tree
c_parser_omp_ordered (c_parser *parser)
{
  c_parser_skip_to_pragma_eol (parser);
  return c_finish_omp_ordered (c_parser_omp_structured_block (parser));
}

/* OpenMP 2.5:

   section-scope:
     { section-sequence }

   section-sequence:
     section-directive[opt] structured-block
     section-sequence section-directive structured-block  */

static tree
c_parser_omp_sections_scope (c_parser *parser)
{
  tree stmt, substmt;
  bool error_suppress = false;
  location_t loc;

  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
    {
      /* Avoid skipping until the end of the block.  */
      parser->error = false;
      return NULL_TREE;
    }

  stmt = push_stmt_list ();

  loc = c_parser_peek_token (parser)->location;
  if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
    {
      substmt = push_stmt_list ();

      while (1)
	{
          c_parser_statement (parser);

	  if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
	    break;
	  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	    break;
	  if (c_parser_next_token_is (parser, CPP_EOF))
	    break;
	}

      substmt = pop_stmt_list (substmt);
      substmt = build1 (OMP_SECTION, void_type_node, substmt);
      SET_EXPR_LOCATION (substmt, loc);
      add_stmt (substmt);
    }

  while (1)
    {
      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
	break;
      if (c_parser_next_token_is (parser, CPP_EOF))
	break;

      loc = c_parser_peek_token (parser)->location;
      if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
	{
	  c_parser_consume_pragma (parser);
	  c_parser_skip_to_pragma_eol (parser);
	  error_suppress = false;
	}
      else if (!error_suppress)
	{
	  error_at (loc, "expected %<#pragma omp section%> or %<}%>");
	  error_suppress = true;
	}

      substmt = c_parser_omp_structured_block (parser);
      substmt = build1 (OMP_SECTION, void_type_node, substmt);
      SET_EXPR_LOCATION (substmt, loc);
      add_stmt (substmt);
    }
  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
			     "expected %<#pragma omp section%> or %<}%>");

  substmt = pop_stmt_list (stmt);

  stmt = make_node (OMP_SECTIONS);
  TREE_TYPE (stmt) = void_type_node;
  OMP_SECTIONS_BODY (stmt) = substmt;

  return add_stmt (stmt);
}

/* OpenMP 2.5:
   # pragma omp sections sections-clause[optseq] newline
     sections-scope
*/

#define OMP_SECTIONS_CLAUSE_MASK			\
	( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
	| (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))

static tree
c_parser_omp_sections (c_parser *parser)
{
  tree block, clauses, ret;

  clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
				      "#pragma omp sections");

  block = c_begin_compound_stmt (true);
  ret = c_parser_omp_sections_scope (parser);
  if (ret)
    OMP_SECTIONS_CLAUSES (ret) = clauses;
  block = c_end_compound_stmt (block, true);
  add_stmt (block);

  return ret;
}

/* OpenMP 2.5:
   # pragma parallel parallel-clause new-line
   # pragma parallel for parallel-for-clause new-line
   # pragma parallel sections parallel-sections-clause new-line
*/

#define OMP_PARALLEL_CLAUSE_MASK			\
	( (1u << PRAGMA_OMP_CLAUSE_IF)			\
	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
	| (1u << PRAGMA_OMP_CLAUSE_SHARED)		\
	| (1u << PRAGMA_OMP_CLAUSE_COPYIN)		\
	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
	| (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))

static tree
c_parser_omp_parallel (c_parser *parser)
{
  enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
  const char *p_name = "#pragma omp parallel";
  tree stmt, clauses, par_clause, ws_clause, block;
  unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;

  if (c_parser_next_token_is_keyword (parser, RID_FOR))
    {
      c_parser_consume_token (parser);
      p_kind = PRAGMA_OMP_PARALLEL_FOR;
      p_name = "#pragma omp parallel for";
      mask |= OMP_FOR_CLAUSE_MASK;
      mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
    }
  else if (c_parser_next_token_is (parser, CPP_NAME))
    {
      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
      if (strcmp (p, "sections") == 0)
	{
	  c_parser_consume_token (parser);
	  p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
	  p_name = "#pragma omp parallel sections";
	  mask |= OMP_SECTIONS_CLAUSE_MASK;
	  mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
	}
    }

  clauses = c_parser_omp_all_clauses (parser, mask, p_name);

  switch (p_kind)
    {
    case PRAGMA_OMP_PARALLEL:
      block = c_begin_omp_parallel ();
      c_parser_statement (parser);
      stmt = c_finish_omp_parallel (clauses, block);
      break;

    case PRAGMA_OMP_PARALLEL_FOR:
      block = c_begin_omp_parallel ();
      c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
      c_parser_omp_for_loop (parser, ws_clause, &par_clause);
      stmt = c_finish_omp_parallel (par_clause, block);
      OMP_PARALLEL_COMBINED (stmt) = 1;
      break;

    case PRAGMA_OMP_PARALLEL_SECTIONS:
      block = c_begin_omp_parallel ();
      c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
      stmt = c_parser_omp_sections_scope (parser);
      if (stmt)
	OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
      stmt = c_finish_omp_parallel (par_clause, block);
      OMP_PARALLEL_COMBINED (stmt) = 1;
      break;

    default:
      gcc_unreachable ();
    }

  return stmt;
}

/* OpenMP 2.5:
   # pragma omp single single-clause[optseq] new-line
     structured-block
*/

#define OMP_SINGLE_CLAUSE_MASK				\
	( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
	| (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))

static tree
c_parser_omp_single (c_parser *parser)
{
  tree stmt = make_node (OMP_SINGLE);
  TREE_TYPE (stmt) = void_type_node;

  OMP_SINGLE_CLAUSES (stmt)
    = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
				"#pragma omp single");
  OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);

  return add_stmt (stmt);
}

/* OpenMP 3.0:
   # pragma omp task task-clause[optseq] new-line
*/

#define OMP_TASK_CLAUSE_MASK				\
	( (1u << PRAGMA_OMP_CLAUSE_IF)			\
	| (1u << PRAGMA_OMP_CLAUSE_UNTIED)		\
	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
	| (1u << PRAGMA_OMP_CLAUSE_SHARED))

static tree
c_parser_omp_task (c_parser *parser)
{
  tree clauses, block;

  clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
				      "#pragma omp task");

  block = c_begin_omp_task ();
  c_parser_statement (parser);
  return c_finish_omp_task (clauses, block);
}

/* OpenMP 3.0:
   # pragma omp taskwait new-line
*/

static void
c_parser_omp_taskwait (c_parser *parser)
{
  c_parser_consume_pragma (parser);
  c_parser_skip_to_pragma_eol (parser);

  c_finish_omp_taskwait ();
}

/* Main entry point to parsing most OpenMP pragmas.  */

static void
c_parser_omp_construct (c_parser *parser)
{
  enum pragma_kind p_kind;
  location_t loc;
  tree stmt;

  loc = c_parser_peek_token (parser)->location;
  p_kind = c_parser_peek_token (parser)->pragma_kind;
  c_parser_consume_pragma (parser);

  /* For all constructs below except #pragma omp atomic
     MUST_NOT_THROW catch handlers are needed when exceptions
     are enabled.  */
  if (p_kind != PRAGMA_OMP_ATOMIC)
    c_maybe_initialize_eh ();

  switch (p_kind)
    {
    case PRAGMA_OMP_ATOMIC:
      c_parser_omp_atomic (parser);
      return;
    case PRAGMA_OMP_CRITICAL:
      stmt = c_parser_omp_critical (parser);
      break;
    case PRAGMA_OMP_FOR:
      stmt = c_parser_omp_for (parser);
      break;
    case PRAGMA_OMP_MASTER:
      stmt = c_parser_omp_master (parser);
      break;
    case PRAGMA_OMP_ORDERED:
      stmt = c_parser_omp_ordered (parser);
      break;
    case PRAGMA_OMP_PARALLEL:
      stmt = c_parser_omp_parallel (parser);
      break;
    case PRAGMA_OMP_SECTIONS:
      stmt = c_parser_omp_sections (parser);
      break;
    case PRAGMA_OMP_SINGLE:
      stmt = c_parser_omp_single (parser);
      break;
    case PRAGMA_OMP_TASK:
      stmt = c_parser_omp_task (parser);
      break;
    default:
      gcc_unreachable ();
    }

  if (stmt)
    SET_EXPR_LOCATION (stmt, loc);
}


/* OpenMP 2.5:
   # pragma omp threadprivate (variable-list) */

static void
c_parser_omp_threadprivate (c_parser *parser)
{
  tree vars, t;

  c_parser_consume_pragma (parser);
  vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);

  /* Mark every variable in VARS to be assigned thread local storage.  */
  for (t = vars; t; t = TREE_CHAIN (t))
    {
      tree v = TREE_PURPOSE (t);

      /* If V had already been marked threadprivate, it doesn't matter
	 whether it had been used prior to this point.  */
      if (TREE_CODE (v) != VAR_DECL)
	error ("%qD is not a variable", v);
      else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v))
	error ("%qE declared %<threadprivate%> after first use", v);
      else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
	error ("automatic variable %qE cannot be %<threadprivate%>", v);
      else if (TREE_TYPE (v) == error_mark_node)
	;
      else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
	error ("%<threadprivate%> %qE has incomplete type", v);
      else
	{
	  if (! DECL_THREAD_LOCAL_P (v))
	    {
	      DECL_TLS_MODEL (v) = decl_default_tls_model (v);
	      /* If rtl has been already set for this var, call
		 make_decl_rtl once again, so that encode_section_info
		 has a chance to look at the new decl flags.  */
	      if (DECL_RTL_SET_P (v))
		make_decl_rtl (v);
	    }
	  C_DECL_THREADPRIVATE_P (v) = 1;
	}
    }

  c_parser_skip_to_pragma_eol (parser);
}


/* Parse a single source file.  */

void
c_parse_file (void)
{
  /* Use local storage to begin.  If the first token is a pragma, parse it.
     If it is #pragma GCC pch_preprocess, then this will load a PCH file
     which will cause garbage collection.  */
  c_parser tparser;

  memset (&tparser, 0, sizeof tparser);
  the_parser = &tparser;

  if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
    c_parser_pragma_pch_preprocess (&tparser);

  the_parser = GGC_NEW (c_parser);
  *the_parser = tparser;

  c_parser_translation_unit (the_parser);
  the_parser = NULL;
}

#include "gt-c-parser.h"