]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/d/d-frontend.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / d / d-frontend.cc
CommitLineData
b4c522fa 1/* d-frontend.cc -- D frontend interface to the gcc back-end.
8d9254fc 2 Copyright (C) 2013-2020 Free Software Foundation, Inc.
b4c522fa
IB
3
4GCC is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 3, or (at your option)
7any later version.
8
9GCC is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with GCC; see the file COPYING3. If not see
16<http://www.gnu.org/licenses/>. */
17
18#include "config.h"
19#include "system.h"
20#include "coretypes.h"
21
22#include "dmd/aggregate.h"
23#include "dmd/compiler.h"
24#include "dmd/declaration.h"
25#include "dmd/errors.h"
26#include "dmd/expression.h"
27#include "dmd/identifier.h"
28#include "dmd/module.h"
29#include "dmd/mtype.h"
30#include "dmd/scope.h"
31#include "dmd/statement.h"
32#include "dmd/target.h"
33
34#include "tree.h"
35#include "options.h"
36#include "fold-const.h"
37#include "diagnostic.h"
38#include "stor-layout.h"
39
40#include "d-tree.h"
41
42
43/* Implements the Global interface defined by the frontend.
44 Used for managing the state of the current compilation. */
45
46Global global;
47
48void
49Global::_init (void)
50{
51 this->mars_ext = "d";
52 this->hdr_ext = "di";
53 this->doc_ext = "html";
54 this->ddoc_ext = "ddoc";
55 this->json_ext = "json";
56 this->obj_ext = "o";
57
58 this->run_noext = true;
59 this->version = "v"
60#include "verstr.h"
61 ;
62
63 this->stdmsg = stderr;
64 this->errorLimit = flag_max_errors;
65}
66
67/* Start gagging. Return the current number of gagged errors. */
68
69unsigned
70Global::startGagging (void)
71{
72 this->gag++;
73 return this->gaggedErrors;
74}
75
76/* End gagging, restoring the old gagged state. Return true if errors
77 occured while gagged. */
78
79bool
80Global::endGagging (unsigned oldGagged)
81{
82 bool anyErrs = (this->gaggedErrors != oldGagged);
83 this->gag--;
84
85 /* Restore the original state of gagged errors; set total errors
86 to be original errors + new ungagged errors. */
87 this->errors -= (this->gaggedErrors - oldGagged);
88 this->gaggedErrors = oldGagged;
89
90 return anyErrs;
91}
92
93/* Increment the error count to record that an error has occured in the
94 current context. An error message may or may not have been printed. */
95
96void
97Global::increaseErrorCount (void)
98{
99 if (gag)
100 this->gaggedErrors++;
101
102 this->errors++;
103}
104
105
106/* Implements the Loc interface defined by the frontend.
107 Used for keeping track of current file/line position in code. */
108
109Loc::Loc (const char *filename, unsigned linnum, unsigned charnum)
110{
111 this->linnum = linnum;
112 this->charnum = charnum;
113 this->filename = filename;
114}
115
116const char *
117Loc::toChars (void) const
118{
119 OutBuffer buf;
120
121 if (this->filename)
122 buf.printf ("%s", this->filename);
123
124 if (this->linnum)
125 {
126 buf.printf (":%u", this->linnum);
127 if (this->charnum)
128 buf.printf (":%u", this->charnum);
129 }
130
131 return buf.extractString ();
132}
133
134bool
135Loc::equals (const Loc& loc)
136{
137 if (this->linnum != loc.linnum || this->charnum != loc.charnum)
138 return false;
139
140 if (!FileName::equals (this->filename, loc.filename))
141 return false;
142
143 return true;
144}
145
146
147/* Implements the Port interface defined by the frontend.
148 A mini library for doing compiler/system specific things. */
149
150/* Compare the first N bytes of S1 and S2 without regard to the case. */
151
152int
153Port::memicmp (const char *s1, const char *s2, size_t n)
154{
155 int result = 0;
156
157 for (size_t i = 0; i < n; i++)
158 {
159 char c1 = s1[i];
160 char c2 = s2[i];
161
162 result = c1 - c2;
163 if (result)
164 {
165 result = TOUPPER (c1) - TOUPPER (c2);
166 if (result)
167 break;
168 }
169 }
170
171 return result;
172}
173
174/* Convert all characters in S to uppercase. */
175
176char *
177Port::strupr (char *s)
178{
179 char *t = s;
180
181 while (*s)
182 {
183 *s = TOUPPER (*s);
184 s++;
185 }
186
187 return t;
188}
189
190/* Return true if the real_t value from string BUFFER overflows
191 as a result of rounding down to float mode. */
192
193bool
194Port::isFloat32LiteralOutOfRange (const char *buffer)
195{
196 real_t r;
197
198 real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
199
200 return r == Target::RealProperties::infinity;
201}
202
203/* Return true if the real_t value from string BUFFER overflows
204 as a result of rounding down to double mode. */
205
206bool
207Port::isFloat64LiteralOutOfRange (const char *buffer)
208{
209 real_t r;
210
211 real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
212
213 return r == Target::RealProperties::infinity;
214}
215
216/* Fetch a little-endian 16-bit value from BUFFER. */
217
218unsigned
219Port::readwordLE (void *buffer)
220{
221 unsigned char *p = (unsigned char*) buffer;
222
223 return ((unsigned) p[1] << 8) | (unsigned) p[0];
224}
225
226/* Fetch a big-endian 16-bit value from BUFFER. */
227
228unsigned
229Port::readwordBE (void *buffer)
230{
231 unsigned char *p = (unsigned char*) buffer;
232
233 return ((unsigned) p[0] << 8) | (unsigned) p[1];
234}
235
236/* Fetch a little-endian 32-bit value from BUFFER. */
237
238unsigned
239Port::readlongLE (void *buffer)
240{
241 unsigned char *p = (unsigned char*) buffer;
242
243 return (((unsigned) p[3] << 24)
244 | ((unsigned) p[2] << 16)
245 | ((unsigned) p[1] << 8)
246 | (unsigned) p[0]);
247}
248
249/* Fetch a big-endian 32-bit value from BUFFER. */
250
251unsigned
252Port::readlongBE (void *buffer)
253{
254 unsigned char *p = (unsigned char*) buffer;
255
256 return (((unsigned) p[0] << 24)
257 | ((unsigned) p[1] << 16)
258 | ((unsigned) p[2] << 8)
259 | (unsigned) p[3]);
260}
261
262/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
263
264void
265Port::valcpy (void *buffer, uint64_t value, size_t sz)
266{
267 switch (sz)
268 {
269 case 1:
270 *(uint8_t *) buffer = (uint8_t) value;
271 break;
272
273 case 2:
274 *(uint16_t *) buffer = (uint16_t) value;
275 break;
276
277 case 4:
278 *(uint32_t *) buffer = (uint32_t) value;
279 break;
280
281 case 8:
282 *(uint64_t *) buffer = (uint64_t) value;
283 break;
284
285 default:
286 gcc_unreachable ();
287 }
288}
289
290
291/* Implements the CTFloat interface defined by the frontend.
292 Compile-time floating-pointer helper functions. */
293
294/* Return the absolute value of R. */
295
296real_t
297CTFloat::fabs (real_t r)
298{
299 real_t x;
300 real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL);
301 return x.normalize ();
302}
303
304/* Return the value of R * 2 ^^ EXP. */
305
306real_t
307CTFloat::ldexp (real_t r, int exp)
308{
309 real_t x;
310 real_ldexp (&x.rv (), &r.rv (), exp);
311 return x.normalize ();
312}
313
314/* Return true if longdouble value X is identical to Y. */
315
316bool
317CTFloat::isIdentical (real_t x, real_t y)
318{
319 real_value rx = x.rv ();
320 real_value ry = y.rv ();
321 return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
322 || real_identical (&rx, &ry);
323}
324
325/* Return true if real_t value R is NaN. */
326
327bool
328CTFloat::isNaN (real_t r)
329{
330 return REAL_VALUE_ISNAN (r.rv ());
331}
332
333/* Same as isNaN, but also check if is signalling. */
334
335bool
336CTFloat::isSNaN (real_t r)
337{
338 return REAL_VALUE_ISSIGNALING_NAN (r.rv ());
339}
340
341/* Return true if real_t value is +Inf. */
342
343bool
344CTFloat::isInfinity (real_t r)
345{
346 return REAL_VALUE_ISINF (r.rv ());
347}
348
349/* Return a real_t value from string BUFFER rounded to long double mode. */
350
351real_t
352CTFloat::parse (const char *buffer, bool *overflow)
353{
354 real_t r;
355 real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
356
357 /* Front-end checks overflow to see if the value is representable. */
358 if (overflow && r == Target::RealProperties::infinity)
359 *overflow = true;
360
361 return r;
362}
363
364/* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
365 converting the result to uppercase if FMT requests it. */
366
367int
368CTFloat::sprint (char *buffer, char fmt, real_t r)
369{
370 if (fmt == 'a' || fmt == 'A')
371 {
372 /* Converting to a hexadecimal string. */
373 real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
374 int buflen;
375
376 switch (fmt)
377 {
378 case 'A':
379 buflen = strlen (buffer);
380 for (int i = 0; i < buflen; i++)
381 buffer[i] = TOUPPER (buffer[i]);
382
383 return buflen;
384
385 case 'a':
386 return strlen (buffer);
387
388 default:
389 gcc_unreachable ();
390 }
391 }
392 else
393 {
394 /* Note: restricting the precision of significant digits to 18. */
395 real_to_decimal (buffer, &r.rv (), 32, 18, 1);
396 return strlen (buffer);
397 }
398}
399
400/* Return a hash value for real_t value R. */
401
402size_t
403CTFloat::hash (real_t r)
404{
405 return real_hash (&r.rv ());
406}
407
408/* Implements the Compiler interface used by the frontend. */
409
410/* Generate C main() in response to seeing D main(). This used to be in
411 libdruntime, but contained a reference to _Dmain which didn't work when
412 druntime was made into a shared library and was linked to a program, such
413 as a C++ program, that didn't have a _Dmain. */
414
415void
416Compiler::genCmain (Scope *sc)
417{
418 static bool initialized = false;
419
420 if (initialized)
421 return;
422
423 /* The D code to be generated is provided by __entrypoint.di, try to load it,
424 but don't fail if unfound. */
425 unsigned errors = global.startGagging ();
426 Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint"));
427
428 if (global.endGagging (errors))
429 m = NULL;
430
431 if (m != NULL)
432 {
433 m->importedFrom = m;
434 m->importAll (NULL);
435 m->semantic (NULL);
436 m->semantic2 (NULL);
437 m->semantic3 (NULL);
438 d_add_entrypoint_module (m, sc->_module);
439 }
440
441 initialized = true;
442}
443
444/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
445 The front end should have already ensured that EXPR is a constant,
446 so we just lower the value to GCC and return the converted CST. */
447
448Expression *
255b2d91 449Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
b4c522fa
IB
450{
451 /* We support up to 512-bit values. */
452 unsigned char buffer[64];
453 tree cst;
454
455 Type *tb = type->toBasetype ();
456
457 if (expr->type->isintegral ())
458 cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
459 else if (expr->type->isfloating ())
460 cst = build_float_cst (expr->toReal (), expr->type);
461 else if (expr->op == TOKarrayliteral)
462 {
463 /* Build array as VECTOR_CST, assumes EXPR is constant. */
464 Expressions *elements = ((ArrayLiteralExp *) expr)->elements;
465 vec<constructor_elt, va_gc> *elms = NULL;
466
467 vec_safe_reserve (elms, elements->dim);
468 for (size_t i = 0; i < elements->dim; i++)
469 {
470 Expression *e = (*elements)[i];
471 if (e->type->isintegral ())
472 {
473 tree value = build_integer_cst (e->toInteger (),
474 build_ctype (e->type));
475 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
476 }
477 else if (e->type->isfloating ())
478 {
479 tree value = build_float_cst (e->toReal (), e->type);
480 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
481 }
482 else
483 gcc_unreachable ();
484 }
485
486 /* Build vector type. */
487 int nunits = ((TypeSArray *) expr->type)->dim->toUInteger ();
488 Type *telem = expr->type->nextOf ();
489 tree vectype = build_vector_type (build_ctype (telem), nunits);
490
491 cst = build_vector_from_ctor (vectype, elms);
492 }
493 else
494 gcc_unreachable ();
495
496 /* Encode CST to buffer. */
497 int len = native_encode_expr (cst, buffer, sizeof (buffer));
498
499 if (tb->ty == Tsarray)
500 {
501 /* Interpret value as a vector of the same size,
502 then return the array literal. */
503 int nunits = ((TypeSArray *) type)->dim->toUInteger ();
504 Type *elem = type->nextOf ();
505 tree vectype = build_vector_type (build_ctype (elem), nunits);
506
507 cst = native_interpret_expr (vectype, buffer, len);
508
509 Expression *e = d_eval_constant_expression (cst);
510 gcc_assert (e != NULL && e->op == TOKvector);
511
512 return ((VectorExp *) e)->e1;
513 }
514 else
515 {
516 /* Normal interpret cast. */
517 cst = native_interpret_expr (build_ctype (type), buffer, len);
518
519 Expression *e = d_eval_constant_expression (cst);
520 gcc_assert (e != NULL);
521
522 return e;
523 }
524}
525
526/* Check imported module M for any special processing.
527 Modules we look out for are:
528 - object: For D runtime type information.
529 - gcc.builtins: For all gcc builtins.
530 - core.stdc.*: For all gcc library builtins. */
531
532void
533Compiler::loadModule (Module *m)
534{
535 ModuleDeclaration *md = m->md;
536
537 if (!md || !md->id || !md->packages)
538 {
539 Identifier *id = (md && md->id) ? md->id : m->ident;
540 if (!strcmp (id->toChars (), "object"))
541 create_tinfo_types (m);
542 }
543 else if (md->packages->dim == 1)
544 {
545 if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
546 && !strcmp (md->id->toChars (), "builtins"))
547 d_build_builtins_module (m);
548 }
549 else if (md->packages->dim == 2)
550 {
551 if (!strcmp ((*md->packages)[0]->toChars (), "core")
552 && !strcmp ((*md->packages)[1]->toChars (), "stdc"))
553 d_add_builtin_module (m);
554 }
555}
556
557/* Implements back-end specific interfaces used by the frontend. */
558
559/* Determine return style of function - whether in registers or through a
560 hidden pointer to the caller's stack. */
561
562RET
563retStyle (TypeFunction *)
564{
565 /* Need the backend type to determine this, but this is called from the
566 frontend before semantic processing is finished. An accurate value
567 is not currently needed anyway. */
568 return RETstack;
569}
570
571/* Determine if function FD is a builtin one that we can evaluate in CTFE. */
572
573BUILTIN
574isBuiltin (FuncDeclaration *fd)
575{
576 if (fd->builtin != BUILTINunknown)
577 return fd->builtin;
578
579 maybe_set_intrinsic (fd);
580
581 return fd->builtin;
582}
583
584/* Evaluate builtin D function FD whose argument list is ARGUMENTS.
585 Return result; NULL if cannot evaluate it. */
586
587Expression *
588eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
589{
590 if (fd->builtin != BUILTINyes)
591 return NULL;
592
593 tree decl = get_symbol_decl (fd);
594 gcc_assert (fndecl_built_in_p (decl)
595 || DECL_INTRINSIC_CODE (decl) != INTRINSIC_NONE);
596
597 TypeFunction *tf = (TypeFunction *) fd->type;
598 Expression *e = NULL;
599 input_location = make_location_t (loc);
600
601 tree result = d_build_call (tf, decl, NULL, arguments);
602 result = fold (result);
603
604 /* Builtin should be successfully evaluated.
605 Will only return NULL if we can't convert it. */
606 if (TREE_CONSTANT (result) && TREE_CODE (result) != CALL_EXPR)
607 e = d_eval_constant_expression (result);
608
609 return e;
610}
611
612/* Build and return typeinfo type for TYPE. */
613
614Type *
c0aebc60 615getTypeInfoType (Loc loc, Type *type, Scope *sc)
b4c522fa 616{
c0aebc60
IB
617 if (!global.params.useTypeInfo)
618 {
619 /* Even when compiling without RTTI we should still be able to evaluate
620 TypeInfo at compile-time, just not at run-time. */
621 if (!sc || !(sc->flags & SCOPEctfe))
622 {
623 static int warned = 0;
624
625 if (!warned)
626 {
627 error_at (make_location_t (loc),
a9c697b8 628 "%<object.TypeInfo%> cannot be used with %<-fno-rtti%>");
c0aebc60
IB
629 warned = 1;
630 }
631 }
632 }
633
634 if (Type::dtypeinfo == NULL
635 || (Type::dtypeinfo->storage_class & STCtemp))
636 {
637 /* If TypeInfo has not been declared, warn about each location once. */
638 static Loc warnloc;
639
640 if (!loc.equals (warnloc))
641 {
642 error_at (make_location_t (loc),
643 "%<object.TypeInfo%> could not be found, "
644 "but is implicitly used");
645 warnloc = loc;
646 }
647 }
648
b4c522fa
IB
649 gcc_assert (type->ty != Terror);
650 create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
651 return type->vtinfo->type;
652}
653
654/* Return an inlined copy of a default argument for a function parameter. */
655
656Expression *
657inlineCopy (Expression *e, Scope *)
658{
659 return e->copy ();
660}