1 /* VMS specific, C compiler specific functions.
2    Copyright (C) 2011-2018 Free Software Foundation, Inc.
3    Contributed by Tristan Gingold (gingold@adacore.com).
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #define IN_TARGET_CODE 1
22 
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "c-family/c-common.h"
29 #include "c/c-tree.h"
30 #include "memmodel.h"
31 #include "tm_p.h"
32 #include "c-family/c-pragma.h"
33 #include "toplev.h"
34 #include "incpath.h"
35 
36 /* '#pragma __nostandard' is simply ignored.  */
37 
38 static void
vms_pragma_nostandard(cpp_reader * pfile ATTRIBUTE_UNUSED)39 vms_pragma_nostandard (cpp_reader *pfile ATTRIBUTE_UNUSED)
40 {
41   tree x;
42 
43   if (pragma_lex (&x) != CPP_EOF)
44     warning (OPT_Wpragmas, "junk at end of #pragma __nostandard");
45 }
46 
47 /* '#pragma __standard' is simply ignored.  */
48 
49 static void
vms_pragma_standard(cpp_reader * pfile ATTRIBUTE_UNUSED)50 vms_pragma_standard (cpp_reader *pfile ATTRIBUTE_UNUSED)
51 {
52   tree x;
53 
54   if (pragma_lex (&x) != CPP_EOF)
55     warning (OPT_Wpragmas, "junk at end of #pragma __standard");
56 }
57 
58 /* Saved member alignment.  */
59 static int saved_member_alignment;
60 
61 /* Handle '#pragma member_alignment'.  */
62 
63 static void
vms_pragma_member_alignment(cpp_reader * pfile ATTRIBUTE_UNUSED)64 vms_pragma_member_alignment (cpp_reader *pfile ATTRIBUTE_UNUSED)
65 {
66   tree x;
67   int tok;
68   const char *arg;
69 
70   tok = pragma_lex (&x);
71 
72   if (tok == CPP_EOF)
73     {
74       /* Disable packing.  */
75       maximum_field_alignment = initial_max_fld_align;
76       return;
77     }
78   if (tok != CPP_NAME)
79     {
80       warning (OPT_Wpragmas, "malformed '#pragma member_alignment', ignoring");
81       return;
82     }
83 
84   arg = IDENTIFIER_POINTER (x);
85   /* Accept '__' prefix.  */
86   if (arg[0] == '_' && arg[1] == '_')
87     arg += 2;
88 
89   if (strcmp (arg, "save") == 0)
90     saved_member_alignment = maximum_field_alignment;
91   else if (strcmp (arg, "restore") == 0)
92     maximum_field_alignment = saved_member_alignment;
93   else
94     {
95       error ("unknown '#pragma member_alignment' name %s", arg);
96       return;
97     }
98   if (pragma_lex (&x) != CPP_EOF)
99     {
100       error ("malformed '#pragma member_alignment'");
101       return;
102     }
103 }
104 
105 /* Handle '#pragma nomember_alignment'.  */
106 
107 static void
vms_pragma_nomember_alignment(cpp_reader * pfile ATTRIBUTE_UNUSED)108 vms_pragma_nomember_alignment (cpp_reader *pfile ATTRIBUTE_UNUSED)
109 {
110   tree x;
111   int tok;
112 
113   tok = pragma_lex (&x);
114   if (tok == CPP_NAME)
115     {
116       const char *arg = IDENTIFIER_POINTER (x);
117 
118       /* Accept '__' prefix.  */
119       if (arg[0] == '_' && arg[1] == '_')
120         arg += 2;
121 
122       if (strcmp (arg, "byte") == 0)
123         maximum_field_alignment = 1 * BITS_PER_UNIT;
124       else if (strcmp (arg, "word") == 0)
125         maximum_field_alignment = 2 * BITS_PER_UNIT;
126       else if (strcmp (arg, "longword") == 0)
127         maximum_field_alignment = 4 * BITS_PER_UNIT;
128       else if (strcmp (arg, "quadword") == 0)
129         maximum_field_alignment = 8 * BITS_PER_UNIT;
130       else if (strcmp (arg, "octaword") == 0)
131         maximum_field_alignment = 16 * BITS_PER_UNIT;
132       else
133         {
134           error ("unhandled alignment for '#pragma nomember_alignment'");
135         }
136 
137       tok = pragma_lex (&x);
138     }
139   else
140     {
141       /* Enable packing.  */
142       maximum_field_alignment = BITS_PER_UNIT;
143     }
144 
145   if (tok != CPP_EOF)
146     {
147       error ("garbage at end of '#pragma nomember_alignment'");
148       return;
149     }
150 }
151 
152 /* The 'extern model' for public data.  This drives how the following
153    declarations are handled:
154    1) extern int name;
155    2) int name;
156    3) int name = 5;
157    See below for the behavior as implemented by the native compiler.
158 */
159 
160 enum extern_model_kind
161 {
162   /* Create one overlaid section per variable.  All the above declarations (1,
163       2 and 3) are handled the same way: they create an overlaid section named
164       NAME (and initialized only for 3).  No global symbol is created.
165       This is the VAX C behavior.  */
166   extern_model_common_block,
167 
168   /* Like unix: multiple not-initialized declarations are allowed.
169      Only one initialized definition (case 3) is allows, but multiple
170      uninitialize definition (case 2) are allowed.
171      For case 2, this creates both a section named NAME and a global symbol.
172      For case 3, this creates a conditional global symbol defenition and a
173      conditional section definition.
174      This is the traditional UNIX C behavior.  */
175   extern_model_relaxed_refdef,
176 
177   /* Like -fno-common.  Only one definition (cases 2 and 3) are allowed.
178      This is the ANSI-C model.  */
179   extern_model_strict_refdef,
180 
181   /* Declarations creates symbols without storage.  */
182   extern_model_globalvalue
183 };
184 
185 /* Current and saved extern model.  */
186 static enum extern_model_kind current_extern_model;
187 static enum extern_model_kind saved_extern_model;
188 
189 /* Partial handling of '#pragma extern_model'.  */
190 
191 static void
vms_pragma_extern_model(cpp_reader * pfile ATTRIBUTE_UNUSED)192 vms_pragma_extern_model (cpp_reader *pfile ATTRIBUTE_UNUSED)
193 {
194   tree x;
195   int tok;
196   const char *arg;
197 
198   tok = pragma_lex (&x);
199 
200   if (tok != CPP_NAME)
201     {
202       warning (OPT_Wpragmas, "malformed '#pragma extern_model', ignoring");
203       return;
204     }
205 
206   arg = IDENTIFIER_POINTER (x);
207   /* Accept "__" prefix.  */
208   if (arg[0] == '_' && arg[1] == '_')
209     arg += 2;
210 
211   if (strcmp (arg, "save") == 0)
212     saved_extern_model = current_extern_model;
213   else if (strcmp (arg, "restore") == 0)
214     current_extern_model = saved_extern_model;
215   else if (strcmp (arg, "relaxed_refdef") == 0)
216     current_extern_model = extern_model_relaxed_refdef;
217   else if (strcmp (arg, "strict_refdef") == 0)
218     current_extern_model = extern_model_strict_refdef;
219   else if (strcmp (arg, "common_block") == 0)
220     current_extern_model = extern_model_common_block;
221   else if (strcmp (arg, "globalvalue") == 0)
222     {
223       sorry ("extern model globalvalue");
224       return;
225     }
226   else
227     {
228       error ("unknown '#pragma extern_model' model '%s'", arg);
229       return;
230     }
231 #if 0
232   if (pragma_lex (&x) != CPP_EOF)
233     {
234       permerror (input_location, "junk at end of '#pragma extern_model'");
235       return;
236     }
237 #endif
238 }
239 
240 /* Ignore '#pragma message'.  */
241 
242 static void
vms_pragma_message(cpp_reader * pfile ATTRIBUTE_UNUSED)243 vms_pragma_message (cpp_reader *pfile ATTRIBUTE_UNUSED)
244 {
245   /* Completly ignored.  */
246 #if 0
247   pedwarn (input_location, OPT_Wpragmas,
248            "vms '#pragma __message' is ignored");
249 #endif
250 }
251 
252 /* Handle '#pragma __extern_prefix'  */
253 
254 static GTY(()) tree saved_extern_prefix;
255 
256 static void
vms_pragma_extern_prefix(cpp_reader * ARG_UNUSED (dummy))257 vms_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy))
258 {
259   enum cpp_ttype tok;
260   tree x;
261 
262   tok = pragma_lex (&x);
263   if (tok == CPP_NAME)
264     {
265       const char *op = IDENTIFIER_POINTER (x);
266 
267       if (!strcmp (op, "__save"))
268         saved_extern_prefix = pragma_extern_prefix;
269       else if (!strcmp (op, "__restore"))
270         pragma_extern_prefix = saved_extern_prefix;
271       else
272         warning (OPT_Wpragmas,
273                  "malformed '#pragma __extern_prefix', ignoring");
274       return;
275     }
276   else if (tok != CPP_STRING)
277     {
278       warning (OPT_Wpragmas,
279                "malformed '#pragma __extern_prefix', ignoring");
280     }
281   else
282     {
283       /* Note that the length includes the null terminator.  */
284       pragma_extern_prefix = (TREE_STRING_LENGTH (x) > 1 ? x : NULL);
285     }
286 }
287 
288 /* #pragma __pointer_size  */
289 
290 static machine_mode saved_pointer_mode;
291 
292 static void
handle_pragma_pointer_size(const char * pragma_name)293 handle_pragma_pointer_size (const char *pragma_name)
294 {
295   enum cpp_ttype tok;
296   tree x;
297 
298   tok = pragma_lex (&x);
299   if (tok == CPP_NAME)
300     {
301       const char *op = IDENTIFIER_POINTER (x);
302 
303       if (!strcmp (op, "__save"))
304         saved_pointer_mode = c_default_pointer_mode;
305       else if (!strcmp (op, "__restore"))
306         c_default_pointer_mode = saved_pointer_mode;
307       else if (!strcmp (op, "__short"))
308         c_default_pointer_mode = SImode;
309       else if (!strcmp (op, "__long"))
310         c_default_pointer_mode = DImode;
311       else
312         error ("malformed %<#pragma %s%>, ignoring", pragma_name);
313     }
314   else if (tok == CPP_NUMBER)
315     {
316       int val;
317 
318       if (TREE_CODE (x) == INTEGER_CST)
319         val = TREE_INT_CST_LOW (x);
320       else
321         val = -1;
322 
323       if (val == 32)
324         c_default_pointer_mode = SImode;
325       else if (val == 64)
326         c_default_pointer_mode = DImode;
327       else
328         error ("invalid constant in %<#pragma %s%>", pragma_name);
329     }
330   else
331     {
332       error ("malformed %<#pragma %s%>, ignoring", pragma_name);
333     }
334 }
335 
336 static void
vms_pragma_pointer_size(cpp_reader * ARG_UNUSED (dummy))337 vms_pragma_pointer_size (cpp_reader * ARG_UNUSED (dummy))
338 {
339   /* Ignore if no -mpointer-size option.  */
340   if (flag_vms_pointer_size == VMS_POINTER_SIZE_NONE)
341     return;
342 
343   handle_pragma_pointer_size ("pointer_size");
344 }
345 
346 static void
vms_pragma_required_pointer_size(cpp_reader * ARG_UNUSED (dummy))347 vms_pragma_required_pointer_size (cpp_reader * ARG_UNUSED (dummy))
348 {
349   handle_pragma_pointer_size ("required_pointer_size");
350 }
351 
352 /* Add vms-specific pragma.  */
353 
354 void
vms_c_register_pragma(void)355 vms_c_register_pragma (void)
356 {
357   c_register_pragma (NULL, "__nostandard", vms_pragma_nostandard);
358   c_register_pragma (NULL, "nostandard", vms_pragma_nostandard);
359   c_register_pragma (NULL, "__standard", vms_pragma_standard);
360   c_register_pragma (NULL, "standard", vms_pragma_standard);
361   c_register_pragma (NULL, "__member_alignment", vms_pragma_member_alignment);
362   c_register_pragma (NULL, "member_alignment", vms_pragma_member_alignment);
363   c_register_pragma_with_expansion (NULL, "__nomember_alignment",
364                                     vms_pragma_nomember_alignment);
365   c_register_pragma_with_expansion (NULL, "nomember_alignment",
366                                     vms_pragma_nomember_alignment);
367   c_register_pragma (NULL, "__pointer_size",
368                      vms_pragma_pointer_size);
369   c_register_pragma (NULL, "__required_pointer_size",
370                      vms_pragma_required_pointer_size);
371   c_register_pragma (NULL, "__extern_model", vms_pragma_extern_model);
372   c_register_pragma (NULL, "extern_model", vms_pragma_extern_model);
373   c_register_pragma (NULL, "__message", vms_pragma_message);
374   c_register_pragma (NULL, "__extern_prefix", vms_pragma_extern_prefix);
375 }
376 
377 /* Canonicalize the filename (remove directory prefix, force the .h extension),
378    and append it to the directory to create the path, but don't
379    turn / into // or // into ///; // may be a namespace escape.  */
380 
381 static char *
vms_construct_include_filename(const char * fname,cpp_dir * dir)382 vms_construct_include_filename (const char *fname, cpp_dir *dir)
383 {
384   size_t dlen, flen;
385   char *path;
386   const char *fbasename = lbasename (fname);
387   size_t i;
388 
389   dlen = dir->len;
390   flen = strlen (fbasename) + 2;
391   path = XNEWVEC (char, dlen + 1 + flen + 1);
392   memcpy (path, dir->name, dlen);
393   if (dlen && !IS_DIR_SEPARATOR (path[dlen - 1]))
394     path[dlen++] = '/';
395   for (i = 0; i < flen; i++)
396     if (fbasename[i] == '.')
397       break;
398     else
399       path[dlen + i] = TOLOWER (fbasename[i]);
400   path[dlen + i + 0] = '.';
401   path[dlen + i + 1] = 'h';
402   path[dlen + i + 2] = 0;
403 
404   return path;
405 }
406 
407 /* Standard modules list.  */
408 static const char * const vms_std_modules[] = { "rtldef", "starlet_c", NULL };
409 
410 /* Find include modules in the include path.  */
411 
412 void
vms_c_register_includes(const char * sysroot,const char * iprefix ATTRIBUTE_UNUSED,int stdinc)413 vms_c_register_includes (const char *sysroot,
414                          const char *iprefix ATTRIBUTE_UNUSED, int stdinc)
415 {
416   static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
417   struct cpp_dir *dir;
418 
419   /* Add on standard include pathes.  */
420   if (!stdinc)
421     return;
422 
423   for (dir = get_added_cpp_dirs (INC_SYSTEM); dir != NULL; dir = dir->next)
424     {
425       const char * const *lib;
426       for (lib = vms_std_modules; *lib != NULL; lib++)
427         {
428           char *path;
429           struct stat st;
430 
431           if (sysroot != NULL)
432             path = concat (sysroot, dir->name, dir_separator_str, *lib, NULL);
433           else
434             path = concat (dir->name, dir_separator_str, *lib, NULL);
435 
436           if (stat (path, &st) == 0 && S_ISDIR (st.st_mode))
437             {
438               cpp_dir *p;
439 
440               p = XNEW (cpp_dir);
441               p->next = NULL;
442               p->name = path;
443               p->sysp = 1;
444               p->construct = vms_construct_include_filename;
445               p->user_supplied_p = 0;
446               add_cpp_dir_path (p, INC_SYSTEM);
447             }
448           else
449             free (path);
450         }
451     }
452 }
453 
454 void
vms_c_common_override_options(void)455 vms_c_common_override_options (void)
456 {
457   /* Allow variadic functions without parameters (as declared in starlet).  */
458   flag_allow_parameterless_variadic_functions = TRUE;
459 
460   /* Initialize c_default_pointer_mode.  */
461   switch (flag_vms_pointer_size)
462     {
463     case VMS_POINTER_SIZE_NONE:
464       break;
465     case VMS_POINTER_SIZE_32:
466       c_default_pointer_mode = SImode;
467       break;
468     case VMS_POINTER_SIZE_64:
469       c_default_pointer_mode = DImode;
470       break;
471     }
472 }
473 
474 /* The default value for _CRTL_VER macro.  */
475 
476 int
vms_c_get_crtl_ver(void)477 vms_c_get_crtl_ver (void)
478 {
479   return VMS_DEFAULT_CRTL_VER;
480 }
481 
482 /* The default value for _VMS_VER macro.  */
483 
484 int
vms_c_get_vms_ver(void)485 vms_c_get_vms_ver (void)
486 {
487   return VMS_DEFAULT_VMS_VER;
488 }
489