"cast(Foo) foo" gets a maybe type only if Foo is a class
[delight/core.git] / d-builtins2.cc
blob1438fa9d9e75525dead42ec216d58ba6bbb8d79c
1 /* GDC -- D front-end for GCC
2 Copyright (C) 2004 David Friedman
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "d-gcc-includes.h"
20 #include "d-lang.h"
21 #include "total.h"
22 #include "attrib.h"
23 #include "template.h"
24 #include "symbol.h"
25 #include "d-codegen.h"
27 static ListMaker bi_fn_list;
29 // Necessary for built-in struct types
30 static Array builtin_converted_types;
31 static Array builtin_converted_decls;
33 static Type * gcc_type_to_d_type(tree t);
35 Type * d_gcc_builtin_va_list_d_type;
37 void
38 d_bi_init(int nt, int nb)
40 // assumes va_list_type_node already built
41 d_gcc_builtin_va_list_d_type = gcc_type_to_d_type(va_list_type_node);
42 if (! d_gcc_builtin_va_list_d_type) {
43 // fallback to array of byte of the same size?
44 error("cannot represent built in va_list type in D");
45 abort();
47 if (! d_gcc_builtin_va_list_d_type->ctype)
48 d_gcc_builtin_va_list_d_type->toCtype();
52 Set ctype directly for complex types to save toCtype() the work.
53 For others, it is not useful or, in the cast of (C char) -> (D char),
54 will cause errors. This also means char* ...
56 NOTE: We cannot always use type->pointerTo (in V2, at least) because
57 (explanation TBD -- see TypeFunction::semantic and
58 TypePointer::semantic: {deco = NULL;} .)
61 static Type *
62 gcc_type_to_d_type(tree t)
64 Type *d;
65 switch (TREE_CODE(t)) {
66 case POINTER_TYPE:
67 // Check for strings first. There are currently no 'char' arguments
68 // for built-in functions, so this is all that needs to be done for
69 // chars/string.
70 if (TYPE_MAIN_VARIANT(TREE_TYPE(t)) == char_type_node)
71 return Type::tchar->pointerTo();
72 d = gcc_type_to_d_type(TREE_TYPE(t));
73 if (d)
75 if (d->ty == Tfunction)
76 return new TypePointer(d);
77 else
78 return d->pointerTo();
80 break;
81 case REFERENCE_TYPE:
82 d = gcc_type_to_d_type(TREE_TYPE(t));
83 if (d) {
84 // Want to assign ctype directly so that the REFERENCE_TYPE
85 // code can be turned into an InOut argument below. Can't use
86 // pointerTo(), because that Type is shared.
87 d = new TypePointer(d);
88 d->ctype = t;
89 return d;
91 break;
92 case INTEGER_TYPE:
94 unsigned sz = tree_low_cst( TYPE_SIZE_UNIT( t ), 1 );
95 bool unsgn = TREE_UNSIGNED( t );
97 // This search assumes that integer types come before char and bit...
98 for (int i = 0; i < (int) TMAX; i++) {
99 d = Type::basic[i];
100 if (d && d->isintegral() && d->size() == sz &&
101 (d->isunsigned()?true:false) == unsgn) {
102 return d;
106 break;
107 case REAL_TYPE:
109 // Double and long double may be the same size
110 if (t == double_type_node)
111 return Type::tfloat64;
112 else if (t == long_double_type_node)
113 return Type::tfloat80;
115 unsigned sz = tree_low_cst( TYPE_SIZE_UNIT( t ), 1 );
116 for (int i = 0; i < (int) TMAX; i++) {
117 d = Type::basic[i];
118 if (d && d->isfloating() && ! d->iscomplex() && ! d->isimaginary() &&
119 d->size() == sz) {
120 return d;
124 break;
125 case COMPLEX_TYPE:
127 unsigned sz = tree_low_cst( TYPE_SIZE_UNIT( t ), 1 );
128 for (int i = 0; i < (int) TMAX; i++) {
129 d = Type::basic[i];
130 if (d && d->iscomplex() && d->size() == sz) {
131 return d;
135 break;
136 case VOID_TYPE:
137 return Type::tvoid;
138 case ARRAY_TYPE:
139 d = gcc_type_to_d_type(TREE_TYPE(t));
140 if (d) {
141 tree index = TYPE_DOMAIN (t);
142 tree ub = TYPE_MAX_VALUE (index);
143 tree lb = TYPE_MIN_VALUE (index);
144 tree length
145 = size_binop (PLUS_EXPR, size_one_node,
146 convert (sizetype,
147 fold (build (MINUS_EXPR,
148 TREE_TYPE (lb),
149 ub, lb))));
150 d = new TypeSArray(d,
151 new IntegerExp(0, gen.getTargetSizeConst(length),
152 Type::tindex));
153 d->ctype = t;
154 return d;
156 break;
157 case RECORD_TYPE:
159 for (unsigned i = 0; i < builtin_converted_types.dim; i += 2)
161 tree ti = (tree) builtin_converted_types.data[i];
162 if (ti == t)
163 return (Type *) builtin_converted_types.data[i + 1];
166 const char * name;
167 char name_buf[64];
168 static int serial;
170 if ( TYPE_NAME(t) )
171 name = IDENTIFIER_POINTER( DECL_NAME( TYPE_NAME( t )));
172 else
174 snprintf(name_buf, sizeof(name_buf), "__bi_type_%d", ++serial);
175 name = name_buf;
178 StructDeclaration * sd = new StructDeclaration(0, Lexer::idPool(name));
179 /* The gcc.builtins module may not exist yet, so cannot set
180 sd->parent here. If it is va_list, the parent needs to
181 be set to the object module which will not exist when
182 this is called. */
183 sd->structsize = int_size_in_bytes( t );
184 sd->alignsize = TYPE_ALIGN_UNIT( t );
185 sd->sizeok = 1;
187 d = new TypeStruct(sd);
188 sd->type = d;
189 sd->handle = new TypePointer(d);
191 /* Does not seem necessary to convert fields, but the
192 members field must be non-null for the above size
193 setting to stick. */
194 sd->members = new Array;
196 d->ctype = t;
198 builtin_converted_types.push(t);
199 builtin_converted_types.push(d);
200 builtin_converted_decls.push(sd);
202 return d;
203 case FUNCTION_TYPE:
205 Type * ret = gcc_type_to_d_type(TREE_TYPE(t));
206 if (! ret)
207 return NULL;
209 tree t_arg_types = TYPE_ARG_TYPES(t);
210 int varargs = t_arg_types != NULL_TREE;
211 Arguments * args = new Arguments;
212 args->reserve(list_length(t_arg_types));
213 for (tree tl = t_arg_types; tl != NULL_TREE; tl = TREE_CHAIN(tl))
215 tree ta = TREE_VALUE(tl);
216 if (ta != void_type_node)
218 unsigned io = STCin;
220 if ( TREE_CODE( ta ) == REFERENCE_TYPE )
222 ta = TREE_TYPE( ta );
223 io = STCref;
226 Type * d_arg_type = gcc_type_to_d_type(ta);
227 if (! d_arg_type)
228 return NULL;
229 args->push(new Argument(io, d_arg_type, NULL, NULL));
231 else
232 varargs = 0;
234 d = new TypeFunction(args, ret, varargs, LINKc);
235 return d;
236 Lfail:
237 delete args;
239 break;
240 default:
241 break;
243 return NULL;
246 void
247 d_bi_builtin_func(tree decl)
249 bi_fn_list.cons(NULL_TREE, decl);
255 // std.stdarg is different: it expects pointer types (i.e. _argptr)
257 We can make it work fine as long as the argument to va_varg is _argptr,
258 we just call va_arg on the hidden va_list. As long _argptr is not
259 otherwise modified, it will work. */
261 static void
262 d_gcc_magic_stdarg_module(Module *m, bool is_c_std_arg)
264 Array * members = m->members;
265 Identifier * id = Lexer::idPool("va_arg");
266 Identifier * id_start = Lexer::idPool("va_start");
267 for (unsigned i = 0; i < members->dim; i++) {
268 TemplateDeclaration * td =
269 ((Dsymbol *) members->data[i])->isTemplateDeclaration();
270 if (td) {
271 if (td->ident == id) {
272 if (is_c_std_arg)
273 IRState::setCStdArgArg(td);
274 else
275 IRState::setStdArg(td);
276 } else if (td->ident == id_start && is_c_std_arg) {
277 IRState::setCStdArgStart(td);
278 } else
279 continue;
281 if ( TREE_CODE( va_list_type_node ) == ARRAY_TYPE ) {
282 /* For GCC, a va_list can be an array. D static arrays are
283 automatically passed by reference, but the 'inout'
284 modifier is not allowed. */
285 assert(td->members);
286 for (unsigned j = 0; j < td->members->dim; j++) {
287 FuncDeclaration * fd =
288 ((Dsymbol *) td->members->data[j])->isFuncDeclaration();
289 if (fd && (fd->ident == id || fd->ident == id_start)) {
290 TypeFunction * tf;
292 // Should have nice error message instead of ICE in case some tries
293 // to tweak the file.
294 assert( ! fd->parameters );
295 tf = (TypeFunction *) fd->type;
296 assert( tf->ty == Tfunction &&
297 tf->parameters && tf->parameters->dim >= 1 );
298 ((Argument*) tf->parameters->data[0])->storageClass &= ~(STCin|STCout|STCref);
299 ((Argument*) tf->parameters->data[0])->storageClass |= STCin;
307 static void
308 d_gcc_magic_builtins_module(Module *m)
310 Array * funcs = new Array;
312 for (tree n = bi_fn_list.head; n; n = TREE_CHAIN(n))
314 tree decl = TREE_VALUE(n);
315 const char * name = IDENTIFIER_POINTER(DECL_NAME(decl));
316 TypeFunction * dtf = (TypeFunction *) gcc_type_to_d_type(TREE_TYPE(decl));
317 if (! dtf)
319 //warning("cannot create built in function type for %s", name);
320 continue;
322 if (dtf->parameters && dtf->parameters->dim == 0 && dtf->varargs)
324 //warning("one-arg va problem: %s", name);
325 continue;
327 FuncDeclaration * func = new FuncDeclaration(0, 0,
328 Lexer::idPool(name), STCextern, dtf);
329 func->isym = new Symbol;
330 func->isym->Stree = decl;
332 funcs->push( func );
335 for (unsigned i = 0; i < builtin_converted_decls.dim ; ++i)
337 Dsymbol * sym = (Dsymbol *) builtin_converted_decls.data[i];
339 /* va_list is a pain. It can be referenced without importing
340 gcc.builtins so it really needs to go in the object module. */
341 if (! sym->parent) {
342 Declaration * decl = sym->isDeclaration();
343 if (! decl || decl->type != d_gcc_builtin_va_list_d_type) {
344 sym->parent = m;
345 /* Currently, there is no need to run semantic, but we do
346 want to output inits, etc. */
347 funcs->push( sym );
352 Type * d = gcc_type_to_d_type(va_list_type_node);
353 if (d) {
354 funcs->push( new AliasDeclaration(0,
355 Lexer::idPool("__builtin_va_list"), d) );
358 /* Provide access to target-specific integer types. */
360 d = gcc_type_to_d_type(long_integer_type_node);
361 if (d)
362 funcs->push( new AliasDeclaration(0,
363 Lexer::idPool("__builtin_Clong"), d) );
364 d = gcc_type_to_d_type(long_unsigned_type_node);
365 if (d)
366 funcs->push( new AliasDeclaration(0,
367 Lexer::idPool("__builtin_Culong"), d) );
368 d = gcc_type_to_d_type(d_type_for_mode(word_mode, 0));
369 if (d)
370 funcs->push( new AliasDeclaration(0,
371 Lexer::idPool("__builtin_machine_int"), d) );
372 d = gcc_type_to_d_type(d_type_for_mode(word_mode, 1));
373 if (d)
374 funcs->push( new AliasDeclaration(0,
375 Lexer::idPool("__builtin_machine_uint"), d) );
376 d = gcc_type_to_d_type(d_type_for_mode(ptr_mode, 0));
377 if (d)
378 funcs->push( new AliasDeclaration(0,
379 Lexer::idPool("__builtin_pointer_int"), d) );
380 d = gcc_type_to_d_type(d_type_for_mode(ptr_mode, 1));
381 if (d)
382 funcs->push( new AliasDeclaration(0,
383 Lexer::idPool("__builtin_pointer_uint"), d) );
385 m->members->push( new LinkDeclaration(LINKc, funcs) );
389 void d_gcc_magic_module(Module *m)
391 ModuleDeclaration * md = m->md;
392 if (md && md->packages && md->id) {
393 if (md->packages->dim == 1 &&
394 ! strcmp( ((Identifier *) md->packages->data[0])->string, "gcc" ) &&
395 ! strcmp( md->id->string, "builtins" )) {
396 d_gcc_magic_builtins_module(m);
397 } else if (md->packages->dim >= 1 &&
398 ! strcmp( ((Identifier *) md->packages->data[0])->string, "std" )) {
400 if (! strcmp( md->id->string, "stdarg" )) {
401 if (md->packages->dim == 1) {
402 d_gcc_magic_stdarg_module(m, false);
403 } else if (md->packages->dim == 2 &&
404 ! strcmp( ((Identifier *) md->packages->data[1])->string, "c" )) {
405 d_gcc_magic_stdarg_module(m, true);
407 } else if (! strcmp( md->id->string, "intrinsic") &&
408 md->packages->dim == 1) {
409 IRState::setIntrinsicModule(m);