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