Files
ldc/mtype.c
Alexey Prokhin f2237662df Squashed 'dmd2/' changes from 10017d5..3443f38
3443f38 Fix issue 7493  Initialization of void[][N]
0b371da foreach can run semantic again
7216e2a fix Issue 7735 - Functions with variadic void[][]... arguments corrupt passed data
4fb2b2a Merge pull request #850 from 9rnsr/fix7773
9c59931 Merge pull request #851 from donc/ctfe7785pointerToVar
407f7e4 Merge pull request #852 from donc/segfault7639
9370f83 Fix issue 7380 Crash trying to use address of variable in struct constructor at module level
240866b Fix issue 7639 Undefined enum AA key crashes compiler
19b7096 Fix issue 7785 [CTFE] ICE when slicing pointer to variable
d9b11f6 fix Issue 7773 - UCFS syntax on built-in attributes too?
296d812 Merge pull request #846 from donc/ctfe7781segfault
65aca2d Merge pull request #848 from donc/regression7751
5576737 Merge pull request #849 from donc/bug7794
0310838 Merge pull request #828 from 9rnsr/fix7751
4027e4f Fix issue 7794 Sea of errors when calling regex() after compile error
59cc12d Fix issue 7781 [CTFE] Segmentation fault on 'mixin({return;}());'
3430947 fix seg fault in fail91.d
948274e Merge pull request #824 from donc/regression7745
22ac4b1 Merge pull request #826 from 9rnsr/fix6659
1c15841 Merge pull request #823 from redstar/mscclean
5f54752 Merge pull request #827 from 9rnsr/fix7694
399e4a3 Merge pull request #844 from donc/regression7782
516f49b Fix issue 7789 [CTFE] null pointer exception on setting array length
d74b354 Fix issue 7782 Regression: ICE with wrong import syntax
0269194 Fix issue 7751 [ICE] (Regression 2.059head) From auto and forward reference
42ad236 Merge pull request #830 from 9rnsr/fix_ufcs
67bf025 Merge pull request #832 from 9rnsr/fix7608
d13f107 Merge pull request #829 from 9rnsr/fix7754
e25cbe2 Merge pull request #834 from 9rnsr/fix2367
7fac235 merge D2 pull #842
c836773 Merge pull request #836 from 9rnsr/fix7757
a2754c5 Merge pull request #839 from 9rnsr/fix7768
4948836 fix Issue 7694 - Internal error: e2ir.c 1251 when calling member function inside struct via alias param
9f23335 Merge pull request #838 from 9rnsr/fix7621
92eba60 Merge pull request #840 from 9rnsr/fix7769
8fae3c2 fix issue 7742 - 'More initializers than fields' error with correct number of fields
6c2d706 to enum
35e4f08 fix Issue 7769 - relax inout rule doesn't work for template function
96a0105 fix Issue 7768 - More readable template error messages
8012d58 Merge pull request #831 from 9rnsr/fix7743
9c0cbdd fix Issue 7621 - Immutable type equivalence problem
f67f313 Merge pull request #833 from 9rnsr/fix7731
29754dd Merge pull request #837 from braddr/cleanup-backend2
374109a restore original binary() function and re-fix the new version
78c04aa fix Issue 7757 - Inout function with lazy inout parameter doesn't compile
50c34e9 fix Issue 7754 - static this() in template is stripped during header gen
11acdff Fix auto tester breaking.
f0b7157 fix Issue 7755 - regression(2.059head): ICE in glue.c
cfceb77 fix Issue 7751 - [ICE] From auto and forward reference
7a86807 fix Issue 2367 - Overloading error with string literals
6039c40 fix Issue 7731 - Assertion failure: 't' on line 7911 in file 'mtype.c'
aea3a39 fix Issue 7608 - __traits(allMembers) is broken
f46f07a fix Issue 7743 - Parsing problem with nothrow delegate
fa9d29f Revert "Revert "Refactor for UFCS property getter/setter resolution.""
d9698d8 Revert "Revert "fix Issue 7722 - Refuse normal functions to be used as properties""
0fbc772 Revert "Revert "Allow property function has two arguments""
07a3b09 fix Issue 6659 - Destructor in range foreach called after initialization
e499d4d Fix issue 7745 Regression(2.059beta) Methods defined in external object files when a pointer to it is taken
79a74e1 Fixes an unknown pragma warning.
2b12052 Fix issue 176 [module] message "module and package have the same name"
90e89a4 Merge pull request #814 from 9rnsr/fix7713
3ab0e79 Merge pull request #818 from donc/assoc7732
b3360e9 Fix issue 7732 [CTFE] wrong code for a struct called AssociativeArray
05f0b08 Merge pull request #779 from 9rnsr/fix7534
867e567 Revert "Allow property function has two arguments"
9171aeb Revert "fix Issue 7722 - Refuse normal functions to be used as properties"
989ced7 Revert "Refactor for UFCS property getter/setter resolution."
e9b5292 Refactor for UFCS property getter/setter resolution.
761d000 fix Issue 7722 - Refuse normal functions to be used as properties
9f5956b Allow property function has two arguments
1a11862 Revert "Allow property function has two arguments"
32f57e5 Revert "fix Issue 7722 - Refuse normal functions to be used as properties"
6489bb4 Revert "Refactor for UFCS property getter/setter resolution."
214296f Merge pull request #817 from 9rnsr/fix_ufcs
c3c7f2a Merge pull request #816 from donc/voidctfe6438
185d031 Refactor for UFCS property getter/setter resolution.
08bf89d fix Issue 7722 - Refuse normal functions to be used as properties
f0e3433 Allow property function has two arguments
1b67ac9 Direct check by Type::reliesOnTident
a3cd7d9 fix Issue 7713 - lambda inference doesn't work on template function argument
1762112 Fix issue 6438 - [CTFE] wrong error "value used before set" when slicing =void array
ace1eca fix complex constant folding
76f9b22 Consider return type covariance.
f700dbc fix Issue 7534 - Allow attribute-overloading of an overridden method
cba8f5c Merge pull request #763 from 9rnsr/fix7578
392d93f Merge pull request #815 from dawgfoto/fixSegFault
e48aba2 merge part of pull #769
d72a17e revert dd5a543
24d860b error(Loc loc,) doesn't abort program
4c79117 Use correct opcodes for moving cfloat from st->xmm and xmm->st
af875ff Merge pull request #785 from braddr/cleanup-backend2
9d3021a remove debugging printfs
b3df5ee Merge pull request #807 from dawgfoto/fix7698
f005537 Merge pull request #802 from dawgfoto/fixVC
65a145d Merge pull request #803 from donc/ctfeunion6681yebblies
1cf39ca Merge pull request #812 from 9rnsr/fix_ufcs
d846c3c Merge pull request #808 from 9rnsr/fix7702
fd0a492 fix Issue 7670 - UFCS problem with @property and structs
1ad35b2 Fix for UFCS with property syntax, and add exhaustive test
96f15a1 Resolve broken build after merging
4712aab fix regression
4e05482 Merge pull request #805 from donc/regression7681
245a107 dt_ functions aren't x86 specific
b35f43a another missing loc in an error() call
001addb minor cleanups
2fb1e46 make util_assert take a const string
907da39 cleanup whitespace in binary(), add binary() that takes the length of the string to search for
59d0425 Merge pull request #804 from braddr/nearsighted
d725eed Merge pull request #806 from donc/ctfe7633equalmsg
12a5c26 Merge pull request #811 from donc/bug7699
4279d5e revert the revert
c895c3b revert pull #809
865fb20 fix Issue 5733 - Calling opDispatch As Template Results in Compiler Infinite Loop
96e16d3 fix Issue 7702 - opDispatch goes into infinite loop
5e343c0 Remove special case for DotIdExp and opDispatch semantic, it isn't need anymore
1a9d607 Fix issue 7699 - Cannot get frame pointer to in contract when compiling with -inline
d1476eb Merge pull request #809 from 9rnsr/fix_funclit
afc7c60 allow out-of-order semantic analysis of fields
17da3a0 fix Issue 7705 - lambda syntax doesn't allow some valid signatures
e29d06d fix issue 7698
911d053 Fix issue 7633 - Missing CTFE error message
3802dde Fix issue 7681 Regression(2.059head):ICE:opCatAssign(delegate) to undefined identifier
8da4121 near-ectomy
cd6dc83 fix Library::error()s format string to take a const char*
f3f03c6 switch to apply()
faf873a fix Issue 3510 - Cannot forward reference a templated type from within a template mixin
23aa2be fix Issue 3509 - Cannot forward reference a template mixin's members in a compile-time context
e81309b Add missing 'loc' to error message.
b6898e3 Fix issue 6681 - struct constructor call is converted to struct literal that breaks union initialization
b79afba long double => longdouble
e48c319 Merge pull request #742 from yebblies/issue5879
d74485a Merge pull request #787 from eco/ddoc-srcfilename
3038cb9 Merge pull request #795 from dawgfoto/fixComment
89a039a Merge pull request #801 from dawgfoto/fix4507
c17c2d8 fix issue 4507
dd86c72 Merge pull request #796 from dawgfoto/fixVC
a516588 Merge pull request #797 from 9rnsr/fix7682
1b9839a Merge pull request #799 from 9rnsr/fix6982
4596774 Merge pull request #800 from 9rnsr/fix_type_deduction
b68d546 forgot about @system
bfe1083 add attributes to toHash
8f819d6 Stop special case in mutableOf/makeMutable with inout type.
319b1a3 Fix the lacks of type merging in Type::mutableOf() and uhSharedOf()
cfe7450 fix Issue 7671 - Broken inout deduction of shared(inout(T[n])) from immutable(int[3])
aca5c37 Stop too eager call of TypeAArray::getImpl() When implicitConvTo(non aa Tstruct => Taarray)
50b2a97 fix Issue 6982 - immutability isn't respected on associative array assignment
a5daa5e fix Issue 7684 - IFTI and shared overload doesn't work
e43fbac fix Issue 7682 - shared array type and "cast() is not an lvalue" error
8191801 cpp_prettyident only needed for C++
4487f75 fix ldval
525647c tparam is the specialization
f893925 fix issue 7592 d847c1c2dd
108b25d Merge pull request #780 from 9rnsr/fix7641
105a51f Merge pull request #784 from 9rnsr/fix7110
8b5b67f Merge pull request #792 from donc/bug7667
f72f237 fix Issue 3682 - Regression(2.038) is expression fails to match types
436b711 Fix issue 7667. ICE(interpret.c): 'ctfeStack.stackPointer() == 0'
9005276 Merge pull request #679 from yebblies/issue783
350a3ce Merge pull request #582 from 9rnsr/fix3382_ufcs
5f020c3 Merge pull request #788 from braddr/cleanup-backend3
6aa91cf Merge pull request #790 from p0nce/master
351d595 remove tls bracketing
a137d72 Fix bug #6391
6ce219c remove some of the bracketing
aec4c13 fix Issue 7578 - ICE on indexing result of vararg opDispatch
95e3dc1 Fix unintended infinite loop in Phobos build
b66196a fix Issue 3382 - [tdpl] Implement uniform function call syntax
ee2fe6c Fix 977 is with counting end-of-lines towards msot advanced lexer peeking
7790b16 fix Issue 7650 - Bad lambda inference in associative array literal
c03484e fix Issue 7649 - Bad lambda inference in default function argument
f293a10 fix Issue 7499 - [ICE] ('cast.c line 1495) with lambda array
9f0622c Expression::inferType() and remove FuncExp::setType()
cfc67b7 refactor lambda inference process
6d49586 more de-TX86'ing in relation to a bunch of OP codes
2efbf6a TX86-ectomy in evalu8.c
953f6d7 rip TX86 conditionals out of el.c
d5663c7 fix Issue 7595 - Data being overwritten.
449c165 Add predefined Ddoc macro SRCFILENAME
5c5da66 fix uninitialized field
29cde54 Merge pull request #783 from 9rnsr/fix7038
06d65ab fix Issue 7038 - Type mismatch with const struct
b77e2c9 fix Issue 7110 - opSlice() & opIndex functions works unstable as template arguments
a65f02f Merge pull request #781 from braddr/fix
08d6cd5 Merge pull request #782 from braddr/fixiasm
2492332 fix latent bug with Lexer::peek and recently introduced bug in Lexer::scan
ec1888e initialize popndTmp rather than rely on carefulness when usNumops == 0 and emitting a vector instruction, popndTmp is left uninitialized and is later dereferenced.
1d4a742 Merge pull request #766 from 9rnsr/fix7563
e1cd535 refactor
90f8dcf fix Issue 7641 - std.typecons.Proxy incorrectly allows implicit conversion to class
83a93cf Merge pull request #778 from dawgfoto/MoreSpellCorrection
7f0bcde 2nd go at fix issue 5590
567d7df fix Issue 5590 - Regression(2.036) ICE(e2ir.c): when using .values on enum which is associative array
48ea951 fix Issue 4820 - Regression(1.058, 2.044) in DStress caused by changeset 452
e8f9f3b more spell correction
afd9a45 fix Issue 7618 - delegate/function pointer call bypass parameter storage class
dabcdfb Merge pull request #773 from 9rnsr/fix7583
9846bb2 Merge pull request #774 from donc/ctfe7568
8c20445 Merge pull request #775 from donc/_error6785
d41e58e Avoiding shallow copy is more better.
cccef09 Revert "fix Issue 7585 - functions in templates inferred as delegate"
fc8dfc0 6785 Wrong error message from pragma(msg) of failed instantiation
61ec04d 7568 pragma(msg) segfaults with an aggregate including a class.
4d86d39 Merge pull request #767 from 9rnsr/fix7585
207d351 fix Issue 7583 - [CTFE] ICE with tuple and alias this
53bafa2 fix Issue 7411 - Deduce base type from vector types in templates
5ab1bd9 fix Issue 7518 - std.array.empty doesn't work for shared arrays
a1030d3 fix Issue 7554 - Immutable function pointer arguments too
5e96900 Merge pull request #771 from donc/bug7589
2287ebc fix Issue 7547 - -deps output lists object as a top level module
e611781 7589 __traits(compiles) does not work with a template that fails to compile
0113cde fix Issue 7585 - functions in templates inferred as delegate
4b978d5 fix Issue 7563 - Class members with default template arguments have no type
4d68981 fix Issue 7500 - [ICE] (template.c line 5287) with immutable lambda function
1a39c3c missed a line
6dd89ca Merge pull request #765 from 9rnsr/fix7525
8d6dcac fix Issue 7502 - 2.056 regression: Assigning .init takes forever to compile for large structs
042096e fix Issue 7525 - Broken return type inference for delegate returns
c5affa5 fix Issue 7582 - Untyped nested delegate literals don't compile
121677c fix Issue 7580 - Identity assignment of Nullable crashes dmd
adc0502 Small refactoring to resolve alias this.
1f52383 Merge pull request #671 from yebblies/issue4958
2a12345 fix build breakage
8755819 fix build
ba86204 fix vcbuild
464c664 fix linux build
31197c8 tweaked command line moved some inline asm to C-function to not interfere with optimizations build with VS2011
4dcdc9c increase stack size for win64 build
77262aa add missing include to root
56afe3f batch to build through win32.mak
5a0fd30 build through win32.mak
a5b5190 long_double -> longdouble remove C99 printf add Win64 support
9640110 vcbuild
b619171 Merge pull request #761 from donc/ctfe7473structref
7756328 Merge pull request #725 from kennytm/bug7399-import-too-fatal
bbac9e4 Merge pull request #759 from yebblies/issue1149
d1ff23b 7473 [CTFE] Non-ref argument behaves as if it's a ref argument
ab5cb18 Fix OPmsw codegen - integer only is too restrictive.
a00833b Merge pull request #743 from yebblies/issue3354
b006e11 Merge pull request #757 from 9rnsr/fix7562
3bccbb0 fix Issue 7562 - DMD crashes by using TemplateThisParameter
a7dc50e Merge pull request #749 from yebblies/issue1149
a873c5f Merge pull request #758 from 9rnsr/fix5525
5d639ec fix Issue 5525 - Eponymous templates should allow for overloaded eponymous members
f50852c Merge pull request #729 from donc/gag4269
de02523 fix Issue 3927 - array.length++; is an error, but ++array.length compiles
1dc5bfd Merge pull request #680 from yebblies/issue3812
cf887ba move errors to Dsymbol
fc4acf5 Merge pull request #755 from donc/seaOfErrors7557
be2f3a9 7557b soldier on through dottemplate expressions
8cec825 7557 Sea of errors after template failure
37ec6d6 A small fixup to call Type::defaultInitLiteral
7b5e2cb Revert "Revert "Merge pull request #41 from 9rnsr/rvalue-struct-literal""
3d8f09a Merge branch 'master' of github.com:D-Programming-Language/dmd
7dfb4cc Merge pull request #752 from braddr/cleanup-backend2
1b28f51 Merge branch 'master' of github.com:D-Programming-Language/dmd
31ad73c Merge pull request #746 from yebblies/issue5554
25f770d Change lexer to support # as a token, preserving #line's original behavior
dd8d20a Revert "Merge pull request #41 from 9rnsr/rvalue-struct-literal"
ee2fdf9 Merge pull request #41 from 9rnsr/rvalue-struct-literal
f94fdbf Merge pull request #750 from yebblies/issue3630
61f5fcf Improve codegen for OPmsw
05a3fa4 Merge pull request #744 from Safety0ff/avx-fix
0231d6a Merge pull request #748 from 9rnsr/fix7552
9a97979 Merge pull request #751 from donc/ctfe7536
e091e6e 7536 ctfeAdrOnStack triggered
c9edaf4 fix Issue 7552 - Cannot get and combine a part of overloaded functions
1edeba9 Fix Issue 3630 - bad error location in "has no effect in expression" error
7d0fb72 Fix Issue 5554 - [qtd] Covariance detection failure
4f36aca fix Issue 7550 - Missing AVX instruction VPMULDQ
0b82dfe Fix Issue 5879 - Not all frontend errors use stderr
963a41a Merge pull request #695 from yebblies/refactor_expression
3f06690 Fix Issue 3354 - asm fld x, ST(6); accepted
713f69f Merge pull request #677 from yebblies/issue4241
cf22ce3 Merge pull request #711 from yebblies/issue3559
56ca73c Merge pull request #700 from kennytm/bug7452_lazy_safe
c4dc723 Merge pull request #736 from ibuclaw/in_gcc
121c9b9 Merge pull request #737 from yebblies/issue7544
cedcb3c Merge pull request #740 from yebblies/issue7545
fb3e8f2 Merge pull request #741 from dawgfoto/DMCWarning
5d26c1e Merge pull request #735 from 9rnsr/fix7105
734a921 dmc warning
1e1cfbc Fix Issue 7545 - ICE(cast.c) Merge integral types through alias this
6b135be Fix Issue 7544 - ICE(interpret.c) Catching an exception with a null catch block
c5336f9 Update already existing gdc-specific code, harmonise headers.
44b8d59 Merge pull request #703 from kennytm/bug435_template_ctor
6b368e1 Merge pull request #707 from yebblies/issue3822
8439e07 Merge pull request #717 from yebblies/issue6611
2b4502e fix Issue 7105 - relax inout rules
ac4463a wildsubparam isn't need anymore, because it works properly.
f77879a Issue 6611 - better error message for array post increment/decrement
7393395 Merge pull request #716 from yebblies/issue6685
77568f0 Merge pull request #719 from yebblies/issue4536
9accb04 tired of tdata()
5fbd5a2 Merge pull request #732 from dawgfoto/fix5412
41a901a Revert "hide private/package module level symbols"
23d5e14 Merge pull request #733 from dawgfoto/HideModuleMembers
e2f8a23 hide private/package module level symbols
ae75287 detect collisions with renamed imports
75a2442 fix Dsymbol::search_correct
50e122a Merge pull request #723 from kennytm/bug7504_null_array
c5b7601 Revert "fix 7494 - selective imports in function scope"
aa6f4d9 Revert "fix Protection"
5be660e Revert "fix Imports"
040371b Revert "detect collisions with renamed imports"
0159818 Revert "find private symbols during spell correction"
0c95c45 find private symbols during spell correction
ca22fb2 detect collisions with renamed imports
0dca0af fix Imports
37d4fda fix Protection
16a2e7e fix 7494 - selective imports in function scope
c16f5b2 Merge pull request #667 from 9rnsr/fix7406
f776617 explanatory comments belong in the code, not bugzilla
bfa2060 Merge pull request #704 from donc/_error6699
f46705c fix fail222 regression
28d9635 Merge pull request #708 from donc/soldieron7481
2c2a7af Merge pull request #715 from 9rnsr/fix6738
98cfa64 Merge pull request #722 from 9rnsr/fix7353
b040567 revert pull 724
0e84f63 revert part of pull 724
400f702 Merge pull request #724 from yebblies/issue3632
d82cc74 Merge pull request #720 from yebblies/issue3279
2da3bed Merge pull request #718 from yebblies/fixdebugmsg
f6627ec 7527 [CTFE] Segfault when slicing a pointer at compile time
c8f09bf 4269a Regression(2.031): invalid type accepted if evaluated while errors are gagged
d10fba0 implement const/purity/nothrow/@safe inheritance
ad689fb Fix bug 7399: Broken import statement in trySemantic() causes silent compiler error
eb0c643 Add global.speculativeGag
c18220a Refactor isSpeculativeFunction into Dsymbol
f5c56d8 Issue 3632 - modify float is float to do a bitwise compare
af1cab4 Issue 7353 - NRVO not properly working with inferred return type
03ee438 Fix bug 7504: Cannot assign an object of type 'typeof(null)' to an array
dfb941c Remove debug printing in code that generates errors.
62118e3 Issue 4536 - Typetuples (T...) should have an .init member
989da7b Issue 3279 - Confusing error message when comparing types
36e8045 Issue 6685 - Allow using "with" with rvalues
60cbc6f fix issue 6738 revisited
4e20e7d Issue 3822 - Invalid optimization of alloca called with constant size
b37bf8c Fixes bug 435: Constructors should be templatized
ad8157d Issue 3559 - DMD 1.048+ fails to take function pointer from overloaded member functions
838cd06 7481 Compiler should 'soldier on' after template errors
673063e Simplify fix for 6699
1a0b199 6699a __error when instantiating function template
b6d072d 6699b __error in alias expression
df16ffa 6699c __error in synchronized error message
338f804 7462 Error message with _error_ in overridden function
0f60bd3 7463 Duplicated error message with bad template value parameter
f43e93a 6699E: _error inside error msg for bad base class
5109a5a Fixes bug 7452.
04d888f Refactor XxxAssignExp semantic
73973d6 Issue 3812 - Missing line number for implicit cast of variadic function to array
f0bbf18 Issue 3927 - array.length++; is an error, but ++array.length compiles
24576c2 Issue 783 - Cannot use an array w/ const or variable index as new[] size argument.
7e4cd4b Issue 4241 - duplicate union initialization error doesn't give a file location
9987127 Issue 4958 - Floating point enums should check for total loss of precision
60287fd Issue 7406 - tuple foreach doesn't work with mixed tuples
633d88e Issue 5889 - Struct literal/construction should be rvalue
5d5f78a Now function overloading with ref and non-ref parameter is legal for struct type

git-subtree-dir: dmd2
git-subtree-split: 3443f38fc4c17807a0f36005a05d598cfc7301db
2012-04-05 11:45:25 +04:00

9228 lines
236 KiB
C

// Compiler implementation of the D programming language
// Copyright (c) 1999-2012 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// http://www.dsource.org/projects/dmd/browser/trunk/src/mtype.c
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more
#define __USE_ISOC99 1 // so signbit() gets defined
#if (defined (__SVR4) && defined (__sun))
#include <alloca.h>
#endif
#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <float.h>
#if _MSC_VER
#include <malloc.h>
#include <complex>
#include <limits>
#elif __DMC__
#include <complex.h>
#elif __MINGW32__
#include <malloc.h>
#endif
#include "rmem.h"
#include "port.h"
#include "dsymbol.h"
#include "mtype.h"
#include "scope.h"
#include "init.h"
#include "expression.h"
#include "attrib.h"
#include "declaration.h"
#include "template.h"
#include "id.h"
#include "enum.h"
#include "import.h"
#include "aggregate.h"
#include "hdrgen.h"
FuncDeclaration *hasThis(Scope *sc);
void ObjectNotFound(Identifier *id);
#define LOGDOTEXP 0 // log ::dotExp()
#define LOGDEFAULTINIT 0 // log ::defaultInit()
// Allow implicit conversion of T[] to T*
#define IMPLICIT_ARRAY_TO_PTR global.params.useDeprecated
/* These have default values for 32 bit code, they get
* adjusted for 64 bit code.
*/
int PTRSIZE = 4;
/* REALSIZE = size a real consumes in memory
* REALPAD = 'padding' added to the CPU real size to bring it up to REALSIZE
* REALALIGNSIZE = alignment for reals
*/
#if TARGET_OSX
int REALSIZE = 16;
int REALPAD = 6;
int REALALIGNSIZE = 16;
#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
int REALSIZE = 12;
int REALPAD = 2;
int REALALIGNSIZE = 4;
#elif TARGET_WINDOS
int REALSIZE = 10;
int REALPAD = 0;
int REALALIGNSIZE = 2;
#elif IN_GCC
int REALSIZE = 0;
int REALPAD = 0;
int REALALIGNSIZE = 0;
#else
#error "fix this"
#endif
int Tsize_t = Tuns32;
int Tptrdiff_t = Tint32;
/***************************** Type *****************************/
ClassDeclaration *Type::typeinfo;
ClassDeclaration *Type::typeinfoclass;
ClassDeclaration *Type::typeinfointerface;
ClassDeclaration *Type::typeinfostruct;
ClassDeclaration *Type::typeinfotypedef;
ClassDeclaration *Type::typeinfopointer;
ClassDeclaration *Type::typeinfoarray;
ClassDeclaration *Type::typeinfostaticarray;
ClassDeclaration *Type::typeinfoassociativearray;
ClassDeclaration *Type::typeinfovector;
ClassDeclaration *Type::typeinfoenum;
ClassDeclaration *Type::typeinfofunction;
ClassDeclaration *Type::typeinfodelegate;
ClassDeclaration *Type::typeinfotypelist;
ClassDeclaration *Type::typeinfoconst;
ClassDeclaration *Type::typeinfoinvariant;
ClassDeclaration *Type::typeinfoshared;
ClassDeclaration *Type::typeinfowild;
TemplateDeclaration *Type::associativearray;
Type *Type::tvoidptr;
Type *Type::tstring;
Type *Type::basic[TMAX];
unsigned char Type::mangleChar[TMAX];
unsigned char Type::sizeTy[TMAX];
StringTable Type::stringtable;
Type::Type(TY ty)
{
this->ty = ty;
this->mod = 0;
this->deco = NULL;
#if DMDV2
this->cto = NULL;
this->ito = NULL;
this->sto = NULL;
this->scto = NULL;
this->wto = NULL;
this->swto = NULL;
#endif
this->pto = NULL;
this->rto = NULL;
this->arrayof = NULL;
this->vtinfo = NULL;
this->ctype = NULL;
}
Type *Type::syntaxCopy()
{
print();
fprintf(stdmsg, "ty = %d\n", ty);
assert(0);
return this;
}
int Type::equals(Object *o)
{ Type *t;
t = (Type *)o;
//printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
if (this == o ||
(t && deco == t->deco) && // deco strings are unique
deco != NULL) // and semantic() has been run
{
//printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
return 1;
}
//if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
return 0;
}
char Type::needThisPrefix()
{
return 'M'; // name mangling prefix for functions needing 'this'
}
void Type::init()
{
stringtable.init(1543);
Lexer::initKeywords();
for (size_t i = 0; i < TMAX; i++)
sizeTy[i] = sizeof(TypeBasic);
sizeTy[Tsarray] = sizeof(TypeSArray);
sizeTy[Tarray] = sizeof(TypeDArray);
sizeTy[Taarray] = sizeof(TypeAArray);
sizeTy[Tpointer] = sizeof(TypePointer);
sizeTy[Treference] = sizeof(TypeReference);
sizeTy[Tfunction] = sizeof(TypeFunction);
sizeTy[Tdelegate] = sizeof(TypeDelegate);
sizeTy[Tident] = sizeof(TypeIdentifier);
sizeTy[Tinstance] = sizeof(TypeInstance);
sizeTy[Ttypeof] = sizeof(TypeTypeof);
sizeTy[Tenum] = sizeof(TypeEnum);
sizeTy[Ttypedef] = sizeof(TypeTypedef);
sizeTy[Tstruct] = sizeof(TypeStruct);
sizeTy[Tclass] = sizeof(TypeClass);
sizeTy[Ttuple] = sizeof(TypeTuple);
sizeTy[Tslice] = sizeof(TypeSlice);
sizeTy[Treturn] = sizeof(TypeReturn);
sizeTy[Terror] = sizeof(TypeError);
sizeTy[Tnull] = sizeof(TypeNull);
mangleChar[Tarray] = 'A';
mangleChar[Tsarray] = 'G';
mangleChar[Taarray] = 'H';
mangleChar[Tpointer] = 'P';
mangleChar[Treference] = 'R';
mangleChar[Tfunction] = 'F';
mangleChar[Tident] = 'I';
mangleChar[Tclass] = 'C';
mangleChar[Tstruct] = 'S';
mangleChar[Tenum] = 'E';
mangleChar[Ttypedef] = 'T';
mangleChar[Tdelegate] = 'D';
mangleChar[Tnone] = 'n';
mangleChar[Tvoid] = 'v';
mangleChar[Tint8] = 'g';
mangleChar[Tuns8] = 'h';
mangleChar[Tint16] = 's';
mangleChar[Tuns16] = 't';
mangleChar[Tint32] = 'i';
mangleChar[Tuns32] = 'k';
mangleChar[Tint64] = 'l';
mangleChar[Tuns64] = 'm';
mangleChar[Tfloat32] = 'f';
mangleChar[Tfloat64] = 'd';
mangleChar[Tfloat80] = 'e';
mangleChar[Timaginary32] = 'o';
mangleChar[Timaginary64] = 'p';
mangleChar[Timaginary80] = 'j';
mangleChar[Tcomplex32] = 'q';
mangleChar[Tcomplex64] = 'r';
mangleChar[Tcomplex80] = 'c';
mangleChar[Tbool] = 'b';
mangleChar[Tascii] = 'a';
mangleChar[Twchar] = 'u';
mangleChar[Tdchar] = 'w';
// '@' shouldn't appear anywhere in the deco'd names
mangleChar[Tinstance] = '@';
mangleChar[Terror] = '@';
mangleChar[Ttypeof] = '@';
mangleChar[Ttuple] = 'B';
mangleChar[Tslice] = '@';
mangleChar[Treturn] = '@';
mangleChar[Tvector] = '@';
mangleChar[Tnull] = 'n'; // same as TypeNone
for (size_t i = 0; i < TMAX; i++)
{ if (!mangleChar[i])
fprintf(stdmsg, "ty = %llu\n", (ulonglong)i);
assert(mangleChar[i]);
}
// Set basic types
static TY basetab[] =
{ Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
Tfloat32, Tfloat64, Tfloat80,
Timaginary32, Timaginary64, Timaginary80,
Tcomplex32, Tcomplex64, Tcomplex80,
Tbool,
Tascii, Twchar, Tdchar };
for (size_t i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++)
{ Type *t = new TypeBasic(basetab[i]);
t = t->merge();
basic[basetab[i]] = t;
}
basic[Terror] = new TypeError();
tnull = new TypeNull();
tnull->deco = tnull->merge()->deco;
tvoidptr = tvoid->pointerTo();
tstring = tchar->invariantOf()->arrayOf();
if (global.params.is64bit)
{
PTRSIZE = 8;
if (global.params.isLinux || global.params.isFreeBSD || global.params.isSolaris)
{
REALSIZE = 16;
REALPAD = 6;
REALALIGNSIZE = 16;
}
Tsize_t = Tuns64;
Tptrdiff_t = Tint64;
}
else
{
PTRSIZE = 4;
#if TARGET_OSX
REALSIZE = 16;
REALPAD = 6;
#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
REALSIZE = 12;
REALPAD = 2;
#else
REALSIZE = 10;
REALPAD = 0;
#endif
Tsize_t = Tuns32;
Tptrdiff_t = Tint32;
}
}
d_uns64 Type::size()
{
return size(0);
}
d_uns64 Type::size(Loc loc)
{
error(loc, "no size for type %s", toChars());
return 1;
}
unsigned Type::alignsize()
{
return size(0);
}
Type *Type::semantic(Loc loc, Scope *sc)
{
return merge();
}
Type *Type::trySemantic(Loc loc, Scope *sc)
{
//printf("+trySemantic(%s) %d\n", toChars(), global.errors);
unsigned errors = global.startGagging();
Type *t = semantic(loc, sc);
if (global.endGagging(errors)) // if any errors happened
{
t = NULL;
}
//printf("-trySemantic(%s) %d\n", toChars(), global.errors);
return t;
}
/********************************
* Convert to 'const'.
*/
Type *Type::constOf()
{
//printf("Type::constOf() %p %s\n", this, toChars());
if (mod == MODconst)
return this;
if (cto)
{ assert(cto->mod == MODconst);
return cto;
}
Type *t = makeConst();
t = t->merge();
t->fixTo(this);
//printf("-Type::constOf() %p %s\n", t, t->toChars());
return t;
}
/********************************
* Convert to 'immutable'.
*/
Type *Type::invariantOf()
{
//printf("Type::invariantOf() %p %s\n", this, toChars());
if (isImmutable())
{
return this;
}
if (ito)
{
assert(ito->isImmutable());
return ito;
}
Type *t = makeInvariant();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
/********************************
* Make type mutable.
*/
Type *Type::mutableOf()
{
//printf("Type::mutableOf() %p, %s\n", this, toChars());
Type *t = this;
if (isConst())
{ if (isShared())
t = sto; // shared const => shared
else
t = cto; // const => naked
assert(!t || t->isMutable());
}
else if (isImmutable())
{ t = ito; // immutable => naked
assert(!t || (t->isMutable() && !t->isShared()));
}
else if (isWild())
{
if (isShared())
t = sto; // shared wild => shared
else
t = wto; // wild => naked
assert(!t || t->isMutable());
}
if (!t)
{
t = makeMutable();
t = t->merge();
t->fixTo(this);
}
else
t = t->merge();
assert(t->isMutable());
return t;
}
Type *Type::sharedOf()
{
//printf("Type::sharedOf() %p, %s\n", this, toChars());
if (mod == MODshared)
{
return this;
}
if (sto)
{
assert(sto->isShared());
return sto;
}
Type *t = makeShared();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
Type *Type::sharedConstOf()
{
//printf("Type::sharedConstOf() %p, %s\n", this, toChars());
if (mod == (MODshared | MODconst))
{
return this;
}
if (scto)
{
assert(scto->mod == (MODshared | MODconst));
return scto;
}
Type *t = makeSharedConst();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
/********************************
* Make type unshared.
* 0 => 0
* const => const
* immutable => immutable
* shared => 0
* shared const => const
* wild => wild
* shared wild => wild
*/
Type *Type::unSharedOf()
{
//printf("Type::unSharedOf() %p, %s\n", this, toChars());
Type *t = this;
if (isShared())
{
if (isConst())
t = cto; // shared const => const
else if (isWild())
t = wto; // shared wild => wild
else
t = sto;
assert(!t || !t->isShared());
}
if (!t)
{
unsigned sz = sizeTy[ty];
t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = mod & ~MODshared;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t = t->merge();
t->fixTo(this);
}
else
t = t->merge();
assert(!t->isShared());
return t;
}
/********************************
* Convert to 'wild'.
*/
Type *Type::wildOf()
{
//printf("Type::wildOf() %p %s\n", this, toChars());
if (mod == MODwild)
{
return this;
}
if (wto)
{
assert(wto->isWild());
return wto;
}
Type *t = makeWild();
t = t->merge();
t->fixTo(this);
//printf("\t%p %s\n", t, t->toChars());
return t;
}
Type *Type::sharedWildOf()
{
//printf("Type::sharedWildOf() %p, %s\n", this, toChars());
if (mod == (MODshared | MODwild))
{
return this;
}
if (swto)
{
assert(swto->mod == (MODshared | MODwild));
return swto;
}
Type *t = makeSharedWild();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
/**********************************
* For our new type 'this', which is type-constructed from t,
* fill in the cto, ito, sto, scto, wto shortcuts.
*/
void Type::fixTo(Type *t)
{
ito = t->ito;
#if 0
/* Cannot do these because these are not fully transitive:
* there can be a shared ptr to immutable, for example.
* Immutable subtypes are always immutable, though.
*/
cto = t->cto;
sto = t->sto;
scto = t->scto;
#endif
assert(mod != t->mod);
#define X(m, n) (((m) << 4) | (n))
switch (X(mod, t->mod))
{
case X(0, MODconst):
cto = t;
break;
case X(0, MODimmutable):
ito = t;
break;
case X(0, MODshared):
sto = t;
break;
case X(0, MODshared | MODconst):
scto = t;
break;
case X(0, MODwild):
wto = t;
break;
case X(0, MODshared | MODwild):
swto = t;
break;
case X(MODconst, 0):
cto = NULL;
goto L2;
case X(MODconst, MODimmutable):
ito = t;
goto L2;
case X(MODconst, MODshared):
sto = t;
goto L2;
case X(MODconst, MODshared | MODconst):
scto = t;
goto L2;
case X(MODconst, MODwild):
wto = t;
goto L2;
case X(MODconst, MODshared | MODwild):
swto = t;
L2:
t->cto = this;
break;
case X(MODimmutable, 0):
ito = NULL;
goto L3;
case X(MODimmutable, MODconst):
cto = t;
goto L3;
case X(MODimmutable, MODshared):
sto = t;
goto L3;
case X(MODimmutable, MODshared | MODconst):
scto = t;
goto L3;
case X(MODimmutable, MODwild):
wto = t;
goto L3;
case X(MODimmutable, MODshared | MODwild):
swto = t;
L3:
t->ito = this;
if (t->cto) t->cto->ito = this;
if (t->sto) t->sto->ito = this;
if (t->scto) t->scto->ito = this;
if (t->wto) t->wto->ito = this;
if (t->swto) t->swto->ito = this;
break;
case X(MODshared, 0):
sto = NULL;
goto L4;
case X(MODshared, MODconst):
cto = t;
goto L4;
case X(MODshared, MODimmutable):
ito = t;
goto L4;
case X(MODshared, MODshared | MODconst):
scto = t;
goto L4;
case X(MODshared, MODwild):
wto = t;
goto L4;
case X(MODshared, MODshared | MODwild):
swto = t;
L4:
t->sto = this;
break;
case X(MODshared | MODconst, 0):
scto = NULL;
goto L5;
case X(MODshared | MODconst, MODconst):
cto = t;
goto L5;
case X(MODshared | MODconst, MODimmutable):
ito = t;
goto L5;
case X(MODshared | MODconst, MODwild):
wto = t;
goto L5;
case X(MODshared | MODconst, MODshared):
sto = t;
goto L5;
case X(MODshared | MODconst, MODshared | MODwild):
swto = t;
L5:
t->scto = this;
break;
case X(MODwild, 0):
wto = NULL;
goto L6;
case X(MODwild, MODconst):
cto = t;
goto L6;
case X(MODwild, MODimmutable):
ito = t;
goto L6;
case X(MODwild, MODshared):
sto = t;
goto L6;
case X(MODwild, MODshared | MODconst):
scto = t;
goto L6;
case X(MODwild, MODshared | MODwild):
swto = t;
L6:
t->wto = this;
break;
case X(MODshared | MODwild, 0):
swto = NULL;
goto L7;
case X(MODshared | MODwild, MODconst):
cto = t;
goto L7;
case X(MODshared | MODwild, MODimmutable):
ito = t;
goto L7;
case X(MODshared | MODwild, MODshared):
sto = t;
goto L7;
case X(MODshared | MODwild, MODshared | MODconst):
scto = t;
goto L7;
case X(MODshared | MODwild, MODwild):
wto = t;
L7:
t->swto = this;
break;
default:
assert(0);
}
#undef X
check();
t->check();
//printf("fixTo: %s, %s\n", toChars(), t->toChars());
}
/***************************
* Look for bugs in constructing types.
*/
void Type::check()
{
switch (mod)
{
case 0:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (swto) assert(swto->mod == (MODshared | MODwild));
break;
case MODconst:
if (cto) assert(cto->mod == 0);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (swto) assert(swto->mod == (MODshared | MODwild));
break;
case MODimmutable:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == 0);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (swto) assert(swto->mod == (MODshared | MODwild));
break;
case MODshared:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == 0);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (swto) assert(swto->mod == (MODshared | MODwild));
break;
case MODshared | MODconst:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == 0);
if (wto) assert(wto->mod == MODwild);
if (swto) assert(swto->mod == (MODshared | MODwild));
break;
case MODwild:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == 0);
if (swto) assert(swto->mod == (MODshared | MODwild));
break;
case MODshared | MODwild:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (swto) assert(swto->mod == 0);
break;
default:
assert(0);
}
Type *tn = nextOf();
if (tn && ty != Tfunction && tn->ty != Tfunction)
{ // Verify transitivity
switch (mod)
{
case 0:
break;
case MODconst:
assert(tn->mod & MODimmutable || tn->mod & MODconst);
break;
case MODimmutable:
assert(tn->mod == MODimmutable);
break;
case MODshared:
assert(tn->mod & MODimmutable || tn->mod & MODshared);
break;
case MODshared | MODconst:
assert(tn->mod & MODimmutable || tn->mod & (MODshared | MODconst));
break;
case MODwild:
assert(tn->mod);
break;
case MODshared | MODwild:
assert(tn->mod == MODimmutable || tn->mod == (MODshared | MODconst) || tn->mod == (MODshared | MODwild));
break;
default:
assert(0);
}
tn->check();
}
}
Type *Type::makeConst()
{
//printf("Type::makeConst() %p, %s\n", this, toChars());
if (cto)
return cto;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODconst;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
//printf("-Type::makeConst() %p, %s\n", t, toChars());
return t;
}
Type *Type::makeInvariant()
{
if (ito)
return ito;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODimmutable;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
return t;
}
Type *Type::makeShared()
{
if (sto)
return sto;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODshared;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
return t;
}
Type *Type::makeSharedConst()
{
if (scto)
return scto;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODshared | MODconst;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
return t;
}
Type *Type::makeWild()
{
if (wto)
return wto;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODwild;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
return t;
}
Type *Type::makeSharedWild()
{
if (swto)
return swto;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODshared | MODwild;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
return t;
}
Type *Type::makeMutable()
{
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = mod & MODshared;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->swto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
return t;
}
/*************************************
* Apply STCxxxx bits to existing type.
* Use *before* semantic analysis is run.
*/
Type *Type::addSTC(StorageClass stc)
{ Type *t = this;
if (stc & STCconst)
{ if (t->isShared())
t = t->makeSharedConst();
else
t = t->makeConst();
}
if (stc & STCimmutable)
t = t->makeInvariant();
if (stc & STCshared)
{ if (t->isConst())
t = t->makeSharedConst();
else
t = t->makeShared();
}
if (stc & STCwild)
{ if (t->isShared())
t = t->makeSharedWild();
else
t = t->makeWild();
}
return t;
}
/************************************
* Apply MODxxxx bits to existing type.
*/
Type *Type::castMod(unsigned mod)
{ Type *t;
switch (mod)
{
case 0:
t = unSharedOf()->mutableOf();
break;
case MODconst:
t = unSharedOf()->constOf();
break;
case MODimmutable:
t = invariantOf();
break;
case MODshared:
t = mutableOf()->sharedOf();
break;
case MODshared | MODconst:
t = sharedConstOf();
break;
case MODwild:
t = unSharedOf()->wildOf();
break;
case MODshared | MODwild:
t = sharedWildOf();
break;
default:
assert(0);
}
return t;
}
/************************************
* Add MODxxxx bits to existing type.
* We're adding, not replacing, so adding const to
* a shared type => "shared const"
*/
Type *Type::addMod(unsigned mod)
{ Type *t = this;
/* Add anything to immutable, and it remains immutable
*/
if (!t->isImmutable())
{
//printf("addMod(%x) %s\n", mod, toChars());
switch (mod)
{
case 0:
break;
case MODconst:
if (isShared())
t = sharedConstOf();
else
t = constOf();
break;
case MODimmutable:
t = invariantOf();
break;
case MODshared:
if (isConst())
t = sharedConstOf();
else if (isWild())
t = sharedWildOf();
else
t = sharedOf();
break;
case MODshared | MODconst:
t = sharedConstOf();
break;
case MODwild:
if (isConst())
;
else if (isShared())
t = sharedWildOf();
else
t = wildOf();
break;
case MODshared | MODwild:
if (isConst())
t = sharedConstOf();
else
t = sharedWildOf();
break;
default:
assert(0);
}
}
return t;
}
/************************************
* Add storage class modifiers to type.
*/
Type *Type::addStorageClass(StorageClass stc)
{
/* Just translate to MOD bits and let addMod() do the work
*/
unsigned mod = 0;
if (stc & STCimmutable)
mod = MODimmutable;
else
{ if (stc & (STCconst | STCin))
mod = MODconst;
else if (stc & STCwild) // const takes precedence over wild
mod |= MODwild;
if (stc & STCshared)
mod |= MODshared;
}
return addMod(mod);
}
Type *Type::pointerTo()
{
if (ty == Terror)
return this;
if (!pto)
{ Type *t;
t = new TypePointer(this);
pto = t->merge();
}
return pto;
}
Type *Type::referenceTo()
{
if (ty == Terror)
return this;
if (!rto)
{ Type *t;
t = new TypeReference(this);
rto = t->merge();
}
return rto;
}
Type *Type::arrayOf()
{
if (ty == Terror)
return this;
if (!arrayof)
{ Type *t;
t = new TypeDArray(this);
arrayof = t->merge();
}
return arrayof;
}
Type *Type::aliasthisOf()
{
AggregateDeclaration *ad = NULL;
if (ty == Tclass)
{
ad = ((TypeClass *)this)->sym;
goto L1;
}
else if (ty == Tstruct)
{
ad = ((TypeStruct *)this)->sym;
L1:
if (!ad->aliasthis)
return NULL;
Declaration *d = ad->aliasthis->isDeclaration();
if (d)
{ assert(d->type);
Type *t = d->type;
if (d->isVarDeclaration() && d->needThis())
{
t = t->addMod(this->mod);
}
else if (d->isFuncDeclaration())
{
FuncDeclaration *fd = (FuncDeclaration *)d;
Expression *ethis = this->defaultInit(0);
fd = fd->overloadResolve(0, ethis, NULL);
if (fd)
{ TypeFunction *tf = (TypeFunction *)fd->type;
if (!tf->next && fd->inferRetType)
{
TemplateInstance *spec = fd->isSpeculative();
int olderrs = global.errors;
fd->semantic3(fd->scope);
// Update the template instantiation with the number
// of errors which occured.
if (spec && global.errors != olderrs)
spec->errors = global.errors - olderrs;
}
t = ((TypeFunction *)fd->type)->next;
}
}
return t;
}
EnumDeclaration *ed = ad->aliasthis->isEnumDeclaration();
if (ed)
{
Type *t = ed->type;
return t;
}
TemplateDeclaration *td = ad->aliasthis->isTemplateDeclaration();
if (td)
{ assert(td->scope);
Expression *ethis = defaultInit(0);
FuncDeclaration *fd = td->deduceFunctionTemplate(td->scope, 0, NULL, ethis, NULL, 1);
if (fd)
{
//if (!fd->type->nextOf() && fd->inferRetType)
{
TemplateInstance *spec = fd->isSpeculative();
int olderrs = global.errors;
fd->semantic3(fd->scope);
// Update the template instantiation with the number
// of errors which occured.
if (spec && global.errors != olderrs)
spec->errors = global.errors - olderrs;
}
if (!global.errors)
{
Type *t = fd->type->nextOf();
t = t->substWildTo(mod == 0 ? MODmutable : mod);
return t;
}
}
return Type::terror;
}
//printf("%s\n", ad->aliasthis->kind());
}
return NULL;
}
Dsymbol *Type::toDsymbol(Scope *sc)
{
return NULL;
}
/*******************************
* If this is a shell around another type,
* get that other type.
*/
Type *Type::toBasetype()
{
return this;
}
/***************************
* Return !=0 if modfrom can be implicitly converted to modto
*/
int MODimplicitConv(unsigned char modfrom, unsigned char modto)
{
if (modfrom == modto)
return 1;
//printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
#define X(m, n) (((m) << 4) | (n))
switch (X(modfrom, modto))
{
case X(0, MODconst):
case X(MODimmutable, MODconst):
case X(MODwild, MODconst):
case X(MODimmutable, MODconst | MODshared):
case X(MODshared, MODconst | MODshared):
case X(MODwild | MODshared, MODconst | MODshared):
return 1;
default:
return 0;
}
#undef X
}
/***************************
* Return !=0 if a method of type '() modfrom' can call a method of type '() modto'.
*/
int MODmethodConv(unsigned char modfrom, unsigned char modto)
{
if (MODimplicitConv(modfrom, modto))
return 1;
#define X(m, n) (((m) << 4) | (n))
switch (X(modfrom, modto))
{
case X(0, MODwild):
case X(MODimmutable, MODwild):
case X(MODconst, MODwild):
case X(MODshared, MODshared|MODwild):
case X(MODshared|MODimmutable, MODshared|MODwild):
case X(MODshared|MODconst, MODshared|MODwild):
return 1;
default:
return 0;
}
#undef X
}
/***************************
* Merge mod bits to form common mod.
*/
int MODmerge(unsigned char mod1, unsigned char mod2)
{
if (mod1 == mod2)
return mod1;
//printf("MODmerge(1 = %x, 2 = %x)\n", modfrom, modto);
#define X(m, n) (((m) << 4) | (n))
// cases are commutative
#define Y(m, n) X(m, n): case X(n, m)
switch (X(mod1, mod2))
{
#if 0
case X(0, 0):
case X(MODconst, MODconst):
case X(MODimmutable, MODimmutable):
case X(MODshared, MODshared):
case X(MODshared | MODconst, MODshared | MODconst):
case X(MODwild, MODwild):
case X(MODshared | MODwild, MODshared | MODwild):
#endif
case Y(0, MODconst):
case Y(0, MODimmutable):
case Y(MODconst, MODimmutable):
case Y(MODconst, MODwild):
case Y(0, MODwild):
case Y(MODimmutable, MODwild):
return MODconst;
case Y(0, MODshared):
return MODshared;
case Y(0, MODshared | MODconst):
case Y(MODconst, MODshared):
case Y(MODconst, MODshared | MODconst):
case Y(MODimmutable, MODshared):
case Y(MODimmutable, MODshared | MODconst):
case Y(MODshared, MODshared | MODconst):
case Y(0, MODshared | MODwild):
case Y(MODconst, MODshared | MODwild):
case Y(MODimmutable, MODshared | MODwild):
case Y(MODshared, MODwild):
case Y(MODshared, MODshared | MODwild):
case Y(MODshared | MODconst, MODwild):
case Y(MODshared | MODconst, MODshared | MODwild):
return MODshared | MODconst;
case Y(MODwild, MODshared | MODwild):
return MODshared | MODwild;
default:
assert(0);
}
#undef Y
#undef X
assert(0);
return 0;
}
/*********************************
* Mangling for mod.
*/
void MODtoDecoBuffer(OutBuffer *buf, unsigned char mod)
{
switch (mod)
{ case 0:
break;
case MODconst:
buf->writeByte('x');
break;
case MODimmutable:
buf->writeByte('y');
break;
case MODshared:
buf->writeByte('O');
break;
case MODshared | MODconst:
buf->writestring("Ox");
break;
case MODwild:
buf->writestring("Ng");
break;
case MODshared | MODwild:
buf->writestring("ONg");
break;
default:
assert(0);
}
}
/*********************************
* Name for mod.
*/
void MODtoBuffer(OutBuffer *buf, unsigned char mod)
{
switch (mod)
{ case 0:
break;
case MODimmutable:
buf->writestring(Token::tochars[TOKimmutable]);
break;
case MODshared:
buf->writestring(Token::tochars[TOKshared]);
break;
case MODshared | MODconst:
buf->writestring(Token::tochars[TOKshared]);
buf->writeByte(' ');
case MODconst:
buf->writestring(Token::tochars[TOKconst]);
break;
case MODshared | MODwild:
buf->writestring(Token::tochars[TOKshared]);
buf->writeByte(' ');
case MODwild:
buf->writestring(Token::tochars[TOKwild]);
break;
default:
assert(0);
}
}
/********************************
* Name mangling.
* Input:
* flag 0x100 do not do const/invariant
*/
void Type::toDecoBuffer(OutBuffer *buf, int flag)
{
if (flag != mod && flag != 0x100)
{
MODtoDecoBuffer(buf, mod);
}
buf->writeByte(mangleChar[ty]);
}
/********************************
* For pretty-printing a type.
*/
char *Type::toChars()
{ OutBuffer *buf;
HdrGenState hgs;
buf = new OutBuffer();
toCBuffer(buf, NULL, &hgs);
return buf->toChars();
}
void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
{
toCBuffer2(buf, hgs, 0);
if (ident)
{ buf->writeByte(' ');
buf->writestring(ident->toChars());
}
}
void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(toChars());
}
void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{
if (!(mod & MODshared) && (this->mod & MODshared))
{
MODtoBuffer(buf, this->mod & MODshared);
buf->writeByte('(');
}
int m1 = this->mod & ~MODshared;
int m2 = (mod ^ m1) & m1;
if (m2)
{
MODtoBuffer(buf, m2);
buf->writeByte('(');
toCBuffer2(buf, hgs, this->mod);
buf->writeByte(')');
}
else
toCBuffer2(buf, hgs, this->mod);
if (!(mod & MODshared) && (this->mod & MODshared))
{
buf->writeByte(')');
}
}
}
void Type::modToBuffer(OutBuffer *buf)
{
if (mod)
{
buf->writeByte(' ');
MODtoBuffer(buf, mod);
}
}
/************************************
*/
Type *Type::merge()
{
if (ty == Terror) return this;
if (ty == Ttypeof) return this;
if (ty == Tident) return this;
if (ty == Tinstance) return this;
if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco)
return this;
if (nextOf() && !nextOf()->merge()->deco)
return this;
//printf("merge(%s)\n", toChars());
Type *t = this;
assert(t);
if (!deco)
{
OutBuffer buf;
StringValue *sv;
//if (next)
//next = next->merge();
toDecoBuffer(&buf);
sv = stringtable.update((char *)buf.data, buf.offset);
if (sv->ptrvalue)
{ t = (Type *) sv->ptrvalue;
#ifdef DEBUG
if (!t->deco)
printf("t = %s\n", t->toChars());
#endif
assert(t->deco);
//printf("old value, deco = '%s' %p\n", t->deco, t->deco);
}
else
{
sv->ptrvalue = this;
deco = sv->lstring.string;
//printf("new value, deco = '%s' %p\n", t->deco, t->deco);
}
}
return t;
}
/*************************************
* This version does a merge even if the deco is already computed.
* Necessary for types that have a deco, but are not merged.
*/
Type *Type::merge2()
{
//printf("merge2(%s)\n", toChars());
Type *t = this;
assert(t);
if (!t->deco)
return t->merge();
StringValue *sv = stringtable.lookup((char *)t->deco, strlen(t->deco));
if (sv && sv->ptrvalue)
{ t = (Type *) sv->ptrvalue;
assert(t->deco);
}
else
assert(0);
return t;
}
int Type::isintegral()
{
return FALSE;
}
int Type::isfloating()
{
return FALSE;
}
int Type::isreal()
{
return FALSE;
}
int Type::isimaginary()
{
return FALSE;
}
int Type::iscomplex()
{
return FALSE;
}
int Type::isscalar()
{
return FALSE;
}
int Type::isunsigned()
{
return FALSE;
}
ClassDeclaration *Type::isClassHandle()
{
return NULL;
}
int Type::isscope()
{
return FALSE;
}
int Type::isString()
{
return FALSE;
}
/**************************
* Given:
* T a, b;
* Can we assign:
* a = b;
* ?
*/
int Type::isAssignable()
{
return TRUE;
}
int Type::checkBoolean()
{
return isscalar();
}
/********************************
* TRUE if when type goes out of scope, it needs a destructor applied.
* Only applies to value types, not ref types.
*/
int Type::needsDestruction()
{
return FALSE;
}
/*********************************
* Check type to see if it is based on a deprecated symbol.
*/
void Type::checkDeprecated(Loc loc, Scope *sc)
{
Dsymbol *s = toDsymbol(sc);
if (s)
s->checkDeprecated(loc, sc);
}
Expression *Type::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("Type::defaultInit() '%s'\n", toChars());
#endif
return NULL;
}
/***************************************
* Use when we prefer the default initializer to be a literal,
* rather than a global immutable variable.
*/
Expression *Type::defaultInitLiteral(Loc loc)
{
#if LOGDEFAULTINIT
printf("Type::defaultInitLiteral() '%s'\n", toChars());
#endif
return defaultInit(loc);
}
int Type::isZeroInit(Loc loc)
{
return 0; // assume not
}
int Type::isBaseOf(Type *t, int *poffset)
{
return 0; // assume not
}
/********************************
* Determine if 'this' can be implicitly converted
* to type 'to'.
* Returns:
* MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact
*/
MATCH Type::implicitConvTo(Type *to)
{
//printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
//printf("from: %s\n", toChars());
//printf("to : %s\n", to->toChars());
if (this == to)
return MATCHexact;
return MATCHnomatch;
}
/*******************************
* Determine if converting 'this' to 'to' is an identity operation,
* a conversion to const operation, or the types aren't the same.
* Returns:
* MATCHexact 'this' == 'to'
* MATCHconst 'to' is const
* MATCHnomatch conversion to mutable or invariant
*/
MATCH Type::constConv(Type *to)
{
//printf("Type::constConv(this = %s, to = %s)\n", toChars(), to->toChars());
if (equals(to))
return MATCHexact;
if (ty == to->ty && MODimplicitConv(mod, to->mod))
return MATCHconst;
return MATCHnomatch;
}
/***************************************
* Return MOD bits matching this type to wild parameter type (tprm).
*/
unsigned Type::wildConvTo(Type *tprm)
{
//printf("Type::wildConvTo this = '%s', tprm = '%s'\n", toChars(), tprm->toChars());
if (tprm->isWild() && implicitConvTo(tprm->substWildTo(MODconst)))
{
if (isWild())
return MODwild;
else if (isConst())
return MODconst;
else if (isImmutable())
return MODimmutable;
else if (isMutable())
return MODmutable;
else
assert(0);
}
return 0;
}
Type *Type::substWildTo(unsigned mod)
{
//printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
Type *t;
if (nextOf())
{
t = nextOf()->substWildTo(mod);
if (t == nextOf())
t = this;
else
{
if (ty == Tpointer)
t = t->pointerTo();
else if (ty == Tarray)
t = t->arrayOf();
else if (ty == Tsarray)
t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy());
else if (ty == Taarray)
{
t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy());
((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
}
else
assert(0);
t = t->merge();
}
}
else
t = this;
if (isWild())
{
if (mod & MODconst)
t = isShared() ? t->sharedConstOf() : t->constOf();
else if (mod & MODimmutable)
t = t->invariantOf();
else if (mod & MODwild)
t = isShared() ? t->sharedWildOf() : t->wildOf();
else
t = isShared() ? t->sharedOf() : t->mutableOf();
}
//printf("-Type::substWildTo t = %s\n", t->toChars());
return t;
}
/**************************
* Return type with the top level of it being mutable.
*/
Type *Type::toHeadMutable()
{
if (!mod)
return this;
return mutableOf();
}
Expression *Type::getProperty(Loc loc, Identifier *ident)
{ Expression *e;
#if LOGDOTEXP
printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
#endif
if (ident == Id::__sizeof)
{
e = new IntegerExp(loc, size(loc), Type::tsize_t);
}
else if (ident == Id::size)
{
error(loc, ".size property should be replaced with .sizeof");
e = new ErrorExp();
}
else if (ident == Id::__xalignof)
{
e = new IntegerExp(loc, alignsize(), Type::tsize_t);
}
else if (ident == Id::typeinfo)
{
if (!global.params.useDeprecated)
error(loc, ".typeinfo deprecated, use typeid(type)");
e = getTypeInfo(NULL);
}
else if (ident == Id::init)
{
if (ty == Tvoid)
error(loc, "void does not have an initializer");
if (ty == Tfunction)
error(loc, "function does not have an initializer");
e = defaultInitLiteral(loc);
}
else if (ident == Id::mangleof)
{ const char *s;
if (!deco)
{ s = toChars();
error(loc, "forward reference of type %s.mangleof", s);
}
else
s = deco;
e = new StringExp(loc, (char *)s, strlen(s), 'c');
Scope sc;
e = e->semantic(&sc);
}
else if (ident == Id::stringof)
{ char *s = toChars();
e = new StringExp(loc, s, strlen(s), 'c');
Scope sc;
e = e->semantic(&sc);
}
else
{
Dsymbol *s = NULL;
if (ty == Tstruct || ty == Tclass || ty == Tenum || ty == Ttypedef)
s = toDsymbol(NULL);
if (s)
s = s->search_correct(ident);
if (this != Type::terror)
{
if (s)
error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars());
else
error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
}
e = new ErrorExp();
}
return e;
}
Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident)
{ VarDeclaration *v = NULL;
#if LOGDOTEXP
printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (e->op == TOKdotvar)
{
DotVarExp *dv = (DotVarExp *)e;
v = dv->var->isVarDeclaration();
}
else if (e->op == TOKvar)
{
VarExp *ve = (VarExp *)e;
v = ve->var->isVarDeclaration();
}
if (v)
{
if (ident == Id::offset)
{
if (!global.params.useDeprecated)
error(e->loc, ".offset deprecated, use .offsetof");
goto Loffset;
}
else if (ident == Id::offsetof)
{
Loffset:
if (v->storage_class & STCfield)
{
e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
return e;
}
}
else if (ident == Id::init)
{
e = defaultInitLiteral(e->loc);
goto Lreturn;
}
}
if (ident == Id::typeinfo)
{
if (!global.params.useDeprecated)
error(e->loc, ".typeinfo deprecated, use typeid(type)");
e = getTypeInfo(sc);
}
else if (ident == Id::stringof)
{ /* Bugzilla 3796: this should demangle e->type->deco rather than
* pretty-printing the type.
*/
char *s = e->toChars();
e = new StringExp(e->loc, s, strlen(s), 'c');
}
else
e = getProperty(e->loc, ident);
Lreturn:
e = e->semantic(sc);
return e;
}
/***************************************
* Figures out what to do with an undefined member reference
* for classes and structs.
*/
Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident)
{
assert(ty == Tstruct || ty == Tclass);
AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration();
assert(sym);
if (ident != Id::__sizeof &&
ident != Id::__xalignof &&
ident != Id::init &&
ident != Id::mangleof &&
ident != Id::stringof &&
ident != Id::offsetof)
{
/* Look for overloaded opDot() to see if we should forward request
* to it.
*/
Dsymbol *fd = search_function(sym, Id::opDot);
if (fd)
{ /* Rewrite e.ident as:
* e.opDot().ident
*/
e = build_overload(e->loc, sc, e, NULL, fd);
e = new DotIdExp(e->loc, e, ident);
return e->semantic(sc);
}
/* Look for overloaded opDispatch to see if we should forward request
* to it.
*/
fd = search_function(sym, Id::opDispatch);
if (fd)
{
/* Rewrite e.ident as:
* e.opDispatch!("ident")
*/
TemplateDeclaration *td = fd->isTemplateDeclaration();
if (!td)
{
fd->error("must be a template opDispatch(string s), not a %s", fd->kind());
return new ErrorExp();
}
StringExp *se = new StringExp(e->loc, ident->toChars());
Objects *tiargs = new Objects();
tiargs->push(se);
e = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs);
((DotTemplateInstanceExp *)e)->ti->tempdecl = td;
e = e->semantic(sc);
return e;
}
/* See if we should forward to the alias this.
*/
if (sym->aliasthis)
{ /* Rewrite e.ident as:
* e.aliasthis.ident
*/
e = resolveAliasThis(sc, e);
e = new DotIdExp(e->loc, e, ident);
return e->semantic(sc);
}
}
return Type::dotExp(sc, e, ident);
}
unsigned Type::memalign(unsigned salign)
{
return salign;
}
void Type::error(Loc loc, const char *format, ...)
{
va_list ap;
va_start(ap, format);
::verror(loc, format, ap);
va_end( ap );
}
void Type::warning(Loc loc, const char *format, ...)
{
va_list ap;
va_start(ap, format);
::vwarning(loc, format, ap);
va_end( ap );
}
Identifier *Type::getTypeInfoIdent(int internal)
{
// _init_10TypeInfo_%s
OutBuffer buf;
Identifier *id;
char *name;
int len;
if (internal)
{ buf.writeByte(mangleChar[ty]);
if (ty == Tarray)
buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]);
}
else
toDecoBuffer(&buf);
len = buf.offset;
name = (char *)alloca(19 + sizeof(len) * 3 + len + 1);
buf.writeByte(0);
#if TARGET_OSX
// The LINKc will prepend the _
sprintf(name, "D%dTypeInfo_%s6__initZ", 9 + len, buf.data);
#else
sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data);
#endif
if (global.params.isWindows)
name++; // C mangling will add it back in
//printf("name = %s\n", name);
id = Lexer::idPool(name);
return id;
}
TypeBasic *Type::isTypeBasic()
{
return NULL;
}
void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("Type::resolve() %s, %d\n", toChars(), ty);
Type *t = semantic(loc, sc);
*pt = t;
*pe = NULL;
*ps = NULL;
}
/*******************************
* tparams == NULL:
* If one of the subtypes of this type is a TypeIdentifier,
* i.e. it's an unresolved type, return that type.
* tparams != NULL:
* Only when the TypeIdentifier is one of template parameters,
* return that type.
*/
Type *Type::reliesOnTident(TemplateParameters *tparams)
{
return NULL;
}
/***************************************
* Return !=0 if the type or any of its subtypes is wild.
*/
int Type::hasWild()
{
return mod & MODwild;
}
/********************************
* We've mistakenly parsed this as a type.
* Redo it as an Expression.
* NULL if cannot.
*/
Expression *Type::toExpression()
{
return NULL;
}
/***************************************
* Return !=0 if type has pointers that need to
* be scanned by the GC during a collection cycle.
*/
int Type::hasPointers()
{
//printf("Type::hasPointers() %s, %d\n", toChars(), ty);
return FALSE;
}
/*************************************
* If this is a type of something, return that something.
*/
Type *Type::nextOf()
{
return NULL;
}
/****************************************
* Return the mask that an integral type will
* fit into.
*/
uinteger_t Type::sizemask()
{ uinteger_t m;
switch (toBasetype()->ty)
{
case Tbool: m = 1; break;
case Tchar:
case Tint8:
case Tuns8: m = 0xFF; break;
case Twchar:
case Tint16:
case Tuns16: m = 0xFFFFUL; break;
case Tdchar:
case Tint32:
case Tuns32: m = 0xFFFFFFFFUL; break;
case Tint64:
case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break;
default:
assert(0);
}
return m;
}
/* ============================= TypeError =========================== */
TypeError::TypeError()
: Type(Terror)
{
}
Type *TypeError::syntaxCopy()
{
// No semantic analysis done, no need to copy
return this;
}
void TypeError::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
{
buf->writestring("_error_");
}
d_uns64 TypeError::size(Loc loc) { return 1; }
Expression *TypeError::getProperty(Loc loc, Identifier *ident) { return new ErrorExp(); }
Expression *TypeError::dotExp(Scope *sc, Expression *e, Identifier *ident) { return new ErrorExp(); }
Expression *TypeError::defaultInit(Loc loc) { return new ErrorExp(); }
Expression *TypeError::defaultInitLiteral(Loc loc) { return new ErrorExp(); }
/* ============================= TypeNext =========================== */
TypeNext::TypeNext(TY ty, Type *next)
: Type(ty)
{
this->next = next;
}
void TypeNext::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
assert(next != this);
//printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty);
next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
void TypeNext::checkDeprecated(Loc loc, Scope *sc)
{
Type::checkDeprecated(loc, sc);
if (next) // next can be NULL if TypeFunction and auto return type
next->checkDeprecated(loc, sc);
}
Type *TypeNext::reliesOnTident(TemplateParameters *tparams)
{
return next->reliesOnTident(tparams);
}
int TypeNext::hasWild()
{
return mod & MODwild || (next && next->hasWild());
}
/*******************************
* For TypeFunction, nextOf() can return NULL if the function return
* type is meant to be inferred, and semantic() hasn't yet ben run
* on the function. After semantic(), it must no longer be NULL.
*/
Type *TypeNext::nextOf()
{
return next;
}
Type *TypeNext::makeConst()
{
//printf("TypeNext::makeConst() %p, %s\n", this, toChars());
if (cto)
{ assert(cto->mod == MODconst);
return cto;
}
TypeNext *t = (TypeNext *)Type::makeConst();
if (ty != Tfunction && next->ty != Tfunction &&
//(next->deco || next->ty == Tfunction) &&
!next->isImmutable() && !next->isConst())
{ if (next->isShared())
t->next = next->sharedConstOf();
else
t->next = next->constOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
//printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeInvariant()
{
//printf("TypeNext::makeInvariant() %s\n", toChars());
if (ito)
{ assert(ito->isImmutable());
return ito;
}
TypeNext *t = (TypeNext *)Type::makeInvariant();
if (ty != Tfunction && next->ty != Tfunction &&
//(next->deco || next->ty == Tfunction) &&
!next->isImmutable())
{ t->next = next->invariantOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
return t;
}
Type *TypeNext::makeShared()
{
//printf("TypeNext::makeShared() %s\n", toChars());
if (sto)
{ assert(sto->mod == MODshared);
return sto;
}
TypeNext *t = (TypeNext *)Type::makeShared();
if (ty != Tfunction && next->ty != Tfunction &&
//(next->deco || next->ty == Tfunction) &&
!next->isImmutable() && !next->isShared())
{
if (next->isConst())
t->next = next->sharedConstOf();
else if (next->isWild())
t->next = next->sharedWildOf();
else
t->next = next->sharedOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
//printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeSharedConst()
{
//printf("TypeNext::makeSharedConst() %s\n", toChars());
if (scto)
{ assert(scto->mod == (MODshared | MODconst));
return scto;
}
TypeNext *t = (TypeNext *)Type::makeSharedConst();
if (ty != Tfunction && next->ty != Tfunction &&
//(next->deco || next->ty == Tfunction) &&
!next->isImmutable() && !next->isSharedConst())
{
t->next = next->sharedConstOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
//printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeWild()
{
//printf("TypeNext::makeWild() %s\n", toChars());
if (wto)
{ assert(wto->mod == MODwild);
return wto;
}
TypeNext *t = (TypeNext *)Type::makeWild();
if (ty != Tfunction && next->ty != Tfunction &&
//(next->deco || next->ty == Tfunction) &&
!next->isImmutable() && !next->isConst() && !next->isWild())
{
if (next->isShared())
t->next = next->sharedWildOf();
else
t->next = next->wildOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
//printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeSharedWild()
{
//printf("TypeNext::makeSharedWild() %s\n", toChars());
if (swto)
{ assert(swto->isSharedWild());
return swto;
}
TypeNext *t = (TypeNext *)Type::makeSharedWild();
if (ty != Tfunction && next->ty != Tfunction &&
//(next->deco || next->ty == Tfunction) &&
!next->isImmutable() && !next->isSharedConst())
{
if (next->isConst())
t->next = next->sharedConstOf();
else
t->next = next->sharedWildOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
//printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeMutable()
{
//printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
TypeNext *t = (TypeNext *)Type::makeMutable();
if (ty == Tsarray)
{
t->next = next->mutableOf();
}
if (ty == Taarray)
{
((TypeAArray *)t)->impl = NULL; // lazily recompute it
}
//printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars());
return t;
}
MATCH TypeNext::constConv(Type *to)
{
//printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars());
if (equals(to))
return MATCHexact;
if (!(ty == to->ty && MODimplicitConv(mod, to->mod)))
return MATCHnomatch;
Type *tn = to->nextOf();
if (!(tn && next->ty == tn->ty))
return MATCHnomatch;
MATCH m;
if (to->isConst()) // whole tail const conversion
{ // Recursive shared level check
m = next->constConv(tn);
if (m == MATCHexact)
m = MATCHconst;
}
else
{ //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars());
m = next->equals(tn) ? MATCHconst : MATCHnomatch;
}
return m;
}
unsigned TypeNext::wildConvTo(Type *tprm)
{
if (ty == Tfunction)
return 0;
unsigned mod = 0;
Type *tn = tprm->nextOf();
if (!tn)
return 0;
mod = next->wildConvTo(tn);
if (!mod)
mod = Type::wildConvTo(tprm);
return mod;
}
void TypeNext::transitive()
{
/* Invoke transitivity of type attributes
*/
next = next->addMod(mod);
}
/* ============================= TypeBasic =========================== */
TypeBasic::TypeBasic(TY ty)
: Type(ty)
{ const char *d;
unsigned flags;
#define TFLAGSintegral 1
#define TFLAGSfloating 2
#define TFLAGSunsigned 4
#define TFLAGSreal 8
#define TFLAGSimaginary 0x10
#define TFLAGScomplex 0x20
#define TFLAGSvector 0x40 // valid for a SIMD vector type
flags = 0;
switch (ty)
{
case Tvoid: d = Token::toChars(TOKvoid);
flags |= TFLAGSvector;
break;
case Tint8: d = Token::toChars(TOKint8);
flags |= TFLAGSintegral | TFLAGSvector;
break;
case Tuns8: d = Token::toChars(TOKuns8);
flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector;
break;
case Tint16: d = Token::toChars(TOKint16);
flags |= TFLAGSintegral | TFLAGSvector;
break;
case Tuns16: d = Token::toChars(TOKuns16);
flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector;
break;
case Tint32: d = Token::toChars(TOKint32);
flags |= TFLAGSintegral | TFLAGSvector;
break;
case Tuns32: d = Token::toChars(TOKuns32);
flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector;
break;
case Tfloat32: d = Token::toChars(TOKfloat32);
flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector;
break;
case Tint64: d = Token::toChars(TOKint64);
flags |= TFLAGSintegral | TFLAGSvector;
break;
case Tuns64: d = Token::toChars(TOKuns64);
flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector;
break;
case Tfloat64: d = Token::toChars(TOKfloat64);
flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector;
break;
case Tfloat80: d = Token::toChars(TOKfloat80);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Timaginary32: d = Token::toChars(TOKimaginary32);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Timaginary64: d = Token::toChars(TOKimaginary64);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Timaginary80: d = Token::toChars(TOKimaginary80);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Tcomplex32: d = Token::toChars(TOKcomplex32);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tcomplex64: d = Token::toChars(TOKcomplex64);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tcomplex80: d = Token::toChars(TOKcomplex80);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tbool: d = "bool";
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tascii: d = Token::toChars(TOKchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Twchar: d = Token::toChars(TOKwchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tdchar: d = Token::toChars(TOKdchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
default: assert(0);
}
this->dstring = d;
this->flags = flags;
merge();
}
Type *TypeBasic::syntaxCopy()
{
// No semantic analysis done on basic types, no need to copy
return this;
}
char *TypeBasic::toChars()
{
return Type::toChars();
}
void TypeBasic::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeBasic::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod);
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(dstring);
}
d_uns64 TypeBasic::size(Loc loc)
{ unsigned size;
//printf("TypeBasic::size()\n");
switch (ty)
{
case Tint8:
case Tuns8: size = 1; break;
case Tint16:
case Tuns16: size = 2; break;
case Tint32:
case Tuns32:
case Tfloat32:
case Timaginary32:
size = 4; break;
case Tint64:
case Tuns64:
case Tfloat64:
case Timaginary64:
size = 8; break;
case Tfloat80:
case Timaginary80:
size = REALSIZE; break;
case Tcomplex32:
size = 8; break;
case Tcomplex64:
size = 16; break;
case Tcomplex80:
size = REALSIZE * 2; break;
case Tvoid:
//size = Type::size(); // error message
size = 1;
break;
case Tbool: size = 1; break;
case Tascii: size = 1; break;
case Twchar: size = 2; break;
case Tdchar: size = 4; break;
default:
assert(0);
break;
}
//printf("TypeBasic::size() = %d\n", size);
return size;
}
unsigned TypeBasic::alignsize()
{ unsigned sz;
switch (ty)
{
case Tfloat80:
case Timaginary80:
case Tcomplex80:
sz = REALALIGNSIZE;
break;
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
case Tint64:
case Tuns64:
sz = global.params.is64bit ? 8 : 4;
break;
case Tfloat64:
case Timaginary64:
sz = global.params.is64bit ? 8 : 4;
break;
case Tcomplex32:
sz = 4;
break;
case Tcomplex64:
sz = global.params.is64bit ? 8 : 4;
break;
#endif
default:
sz = size(0);
break;
}
return sz;
}
Expression *TypeBasic::getProperty(Loc loc, Identifier *ident)
{
Expression *e;
d_int64 ivalue;
#ifdef IN_GCC
real_t fvalue;
#else
d_float80 fvalue;
#endif
//printf("TypeBasic::getProperty('%s')\n", ident->toChars());
if (ident == Id::max)
{
switch (ty)
{
case Tint8: ivalue = 0x7F; goto Livalue;
case Tuns8: ivalue = 0xFF; goto Livalue;
case Tint16: ivalue = 0x7FFFUL; goto Livalue;
case Tuns16: ivalue = 0xFFFFUL; goto Livalue;
case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue;
case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue;
case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue;
case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue;
case Tbool: ivalue = 1; goto Livalue;
case Tchar: ivalue = 0xFF; goto Livalue;
case Twchar: ivalue = 0xFFFFUL; goto Livalue;
case Tdchar: ivalue = 0x10FFFFUL; goto Livalue;
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_MAX; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_MAX; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = Port::ldbl_max; goto Lfvalue;
}
}
else if (ident == Id::min)
{
switch (ty)
{
case Tint8: ivalue = -128; goto Livalue;
case Tuns8: ivalue = 0; goto Livalue;
case Tint16: ivalue = -32768; goto Livalue;
case Tuns16: ivalue = 0; goto Livalue;
case Tint32: ivalue = -2147483647L - 1; goto Livalue;
case Tuns32: ivalue = 0; goto Livalue;
case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue;
case Tuns64: ivalue = 0; goto Livalue;
case Tbool: ivalue = 0; goto Livalue;
case Tchar: ivalue = 0; goto Livalue;
case Twchar: ivalue = 0; goto Livalue;
case Tdchar: ivalue = 0; goto Livalue;
case Tcomplex32:
case Timaginary32:
case Tfloat32:
case Tcomplex64:
case Timaginary64:
case Tfloat64:
case Tcomplex80:
case Timaginary80:
case Tfloat80:
// For backwards compatibility - eventually, deprecate
goto Lmin_normal;
}
}
else if (ident == Id::min_normal)
{
Lmin_normal:
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_MIN; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_MIN; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue;
}
}
else if (ident == Id::nan)
{
switch (ty)
{
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
{
fvalue = Port::nan;
goto Lfvalue;
}
}
}
else if (ident == Id::infinity)
{
switch (ty)
{
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
fvalue = Port::infinity;
goto Lfvalue;
}
}
else if (ident == Id::dig)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_DIG; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_DIG; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_DIG; goto Lint;
}
}
else if (ident == Id::epsilon)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue;
}
}
else if (ident == Id::mant_dig)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint;
}
}
else if (ident == Id::max_10_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint;
}
}
else if (ident == Id::max_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint;
}
}
else if (ident == Id::min_10_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint;
}
}
else if (ident == Id::min_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint;
}
}
return Type::getProperty(loc, ident);
Livalue:
e = new IntegerExp(loc, ivalue, this);
return e;
Lfvalue:
if (isreal() || isimaginary())
e = new RealExp(loc, fvalue, this);
else
{
complex_t cvalue;
#if __DMC__
//((real_t *)&cvalue)[0] = fvalue;
//((real_t *)&cvalue)[1] = fvalue;
cvalue = fvalue + fvalue * I;
#else
cvalue.re = fvalue;
cvalue.im = fvalue;
#endif
//for (int i = 0; i < 20; i++)
// printf("%02x ", ((unsigned char *)&cvalue)[i]);
//printf("\n");
e = new ComplexExp(loc, cvalue, this);
}
return e;
Lint:
e = new IntegerExp(loc, ivalue, Type::tint32);
return e;
}
Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
Type *t;
if (ident == Id::re)
{
switch (ty)
{
case Tcomplex32: t = tfloat32; goto L1;
case Tcomplex64: t = tfloat64; goto L1;
case Tcomplex80: t = tfloat80; goto L1;
L1:
e = e->castTo(sc, t);
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
break;
case Timaginary32: t = tfloat32; goto L2;
case Timaginary64: t = tfloat64; goto L2;
case Timaginary80: t = tfloat80; goto L2;
L2:
e = new RealExp(e->loc, ldouble(0.0), t);
break;
default:
e = Type::getProperty(e->loc, ident);
break;
}
}
else if (ident == Id::im)
{ Type *t2;
switch (ty)
{
case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3;
case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3;
case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3;
L3:
e = e->castTo(sc, t);
e->type = t2;
break;
case Timaginary32: t = tfloat32; goto L4;
case Timaginary64: t = tfloat64; goto L4;
case Timaginary80: t = tfloat80; goto L4;
L4:
e = e->copy();
e->type = t;
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
e = new RealExp(e->loc, ldouble(0.0), this);
break;
default:
e = Type::getProperty(e->loc, ident);
break;
}
}
else
{
return Type::dotExp(sc, e, ident);
}
e = e->semantic(sc);
return e;
}
Expression *TypeBasic::defaultInit(Loc loc)
{ dinteger_t value = 0;
#if SNAN_DEFAULT_INIT
/*
* Use a payload which is different from the machine NaN,
* so that uninitialised variables can be
* detected even if exceptions are disabled.
*/
union
{ unsigned short us[8];
longdouble ld;
} snan = {{ 0, 0, 0, 0xA000, 0x7FFF }};
/*
* Although long doubles are 10 bytes long, some
* C ABIs pad them out to 12 or even 16 bytes, so
* leave enough space in the snan array.
*/
assert(REALSIZE <= sizeof(snan));
d_float80 fvalue = snan.ld;
#endif
#if LOGDEFAULTINIT
printf("TypeBasic::defaultInit() '%s'\n", toChars());
#endif
switch (ty)
{
case Tchar:
value = 0xFF;
break;
case Twchar:
case Tdchar:
value = 0xFFFF;
break;
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
#if SNAN_DEFAULT_INIT
return new RealExp(loc, fvalue, this);
#else
return getProperty(loc, Id::nan);
#endif
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
#if SNAN_DEFAULT_INIT
{ // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
complex_t cvalue;
((real_t *)&cvalue)[0] = fvalue;
((real_t *)&cvalue)[1] = fvalue;
return new ComplexExp(loc, cvalue, this);
}
#else
return getProperty(loc, Id::nan);
#endif
case Tvoid:
error(loc, "void does not have a default initializer");
return new ErrorExp();
}
return new IntegerExp(loc, value, this);
}
int TypeBasic::isZeroInit(Loc loc)
{
switch (ty)
{
case Tchar:
case Twchar:
case Tdchar:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
return 0; // no
}
return 1; // yes
}
int TypeBasic::isintegral()
{
//printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
return flags & TFLAGSintegral;
}
int TypeBasic::isfloating()
{
return flags & TFLAGSfloating;
}
int TypeBasic::isreal()
{
return flags & TFLAGSreal;
}
int TypeBasic::isimaginary()
{
return flags & TFLAGSimaginary;
}
int TypeBasic::iscomplex()
{
return flags & TFLAGScomplex;
}
int TypeBasic::isunsigned()
{
return flags & TFLAGSunsigned;
}
int TypeBasic::isscalar()
{
return flags & (TFLAGSintegral | TFLAGSfloating);
}
MATCH TypeBasic::implicitConvTo(Type *to)
{
//printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
#if DMDV2
if (ty == to->ty)
{
if (mod == to->mod)
return MATCHexact;
else if (MODimplicitConv(mod, to->mod))
return MATCHconst;
else if (!((mod ^ to->mod) & MODshared)) // for wild matching
return MATCHconst;
else
return MATCHconvert;
}
#endif
if (ty == Tvoid || to->ty == Tvoid)
return MATCHnomatch;
if (to->ty == Tbool)
return MATCHnomatch;
TypeBasic *tob;
if (to->ty == Tvector)
{
TypeVector *tv = (TypeVector *)to;
tob = tv->elementType();
}
else
tob = to->isTypeBasic();
if (!tob)
return MATCHnomatch;
if (flags & TFLAGSintegral)
{
// Disallow implicit conversion of integers to imaginary or complex
if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
return MATCHnomatch;
#if DMDV2
// If converting from integral to integral
if (tob->flags & TFLAGSintegral)
{ d_uns64 sz = size(0);
d_uns64 tosz = tob->size(0);
/* Can't convert to smaller size
*/
if (sz > tosz)
return MATCHnomatch;
/* Can't change sign if same size
*/
/*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
return MATCHnomatch;*/
}
#endif
}
else if (flags & TFLAGSfloating)
{
// Disallow implicit conversion of floating point to integer
if (tob->flags & TFLAGSintegral)
return MATCHnomatch;
assert(tob->flags & TFLAGSfloating);
// Disallow implicit conversion from complex to non-complex
if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
return MATCHnomatch;
// Disallow implicit conversion of real or imaginary to complex
if (flags & (TFLAGSreal | TFLAGSimaginary) &&
tob->flags & TFLAGScomplex)
return MATCHnomatch;
// Disallow implicit conversion to-from real and imaginary
if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
(tob->flags & (TFLAGSreal | TFLAGSimaginary)))
return MATCHnomatch;
}
return MATCHconvert;
}
TypeBasic *TypeBasic::isTypeBasic()
{
return (TypeBasic *)this;
}
/* ============================= TypeVector =========================== */
/* The basetype must be one of:
* byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
*/
TypeVector::TypeVector(Loc loc, Type *basetype)
: Type(Tvector)
{
this->basetype = basetype;
}
Type *TypeVector::syntaxCopy()
{
return new TypeVector(0, basetype->syntaxCopy());
}
Type *TypeVector::semantic(Loc loc, Scope *sc)
{
int errors = global.errors;
basetype = basetype->semantic(loc, sc);
if (errors != global.errors)
return terror;
basetype = basetype->toBasetype()->mutableOf();
if (basetype->ty != Tsarray)
{ error(loc, "T in __vector(T) must be a static array, not %s", basetype->toChars());
return terror;
}
TypeSArray *t = (TypeSArray *)basetype;
if (sc && sc->parameterSpecialization && t->dim->op == TOKvar &&
((VarExp *)t->dim)->var->storage_class & STCtemplateparameter)
{
/* It could be a template parameter N which has no value yet:
* template Foo(T : __vector(T[N]), size_t N);
*/
return this;
}
if (t->size(loc) != 16)
{ error(loc, "base type of __vector must be a 16 byte static array, not %s", t->toChars());
return terror;
}
TypeBasic *tb = t->nextOf()->isTypeBasic();
if (!tb || !(tb->flags & TFLAGSvector))
{ error(loc, "base type of __vector must be a static array of an arithmetic type, not %s", t->toChars());
return terror;
}
return merge();
}
TypeBasic *TypeVector::elementType()
{
assert(basetype->ty == Tsarray);
TypeSArray *t = (TypeSArray *)basetype;
TypeBasic *tb = t->nextOf()->isTypeBasic();
assert(tb);
return tb;
}
int TypeVector::checkBoolean()
{
return FALSE;
}
char *TypeVector::toChars()
{
return Type::toChars();
}
void TypeVector::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeVector::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod);
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring("__vector(");
basetype->toCBuffer2(buf, hgs, this->mod);
buf->writestring(")");
}
void TypeVector::toDecoBuffer(OutBuffer *buf, int flag)
{
if (flag != mod && flag != 0x100)
{
MODtoDecoBuffer(buf, mod);
}
buf->writestring("Nh");
basetype->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
d_uns64 TypeVector::size(Loc loc)
{
return 16;
}
unsigned TypeVector::alignsize()
{
return 16;
}
Expression *TypeVector::getProperty(Loc loc, Identifier *ident)
{
return basetype->getProperty(loc, ident);
}
Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::array)
{
e = e->castTo(sc, basetype);
return e;
}
return basetype->dotExp(sc, e->castTo(sc, basetype), ident);
}
Expression *TypeVector::defaultInit(Loc loc)
{
return basetype->defaultInit(loc);
}
int TypeVector::isZeroInit(Loc loc)
{
return basetype->isZeroInit(loc);
}
int TypeVector::isintegral()
{
//printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
return basetype->nextOf()->isintegral();
}
int TypeVector::isfloating()
{
return basetype->nextOf()->isfloating();
}
int TypeVector::isunsigned()
{
return basetype->nextOf()->isunsigned();
}
int TypeVector::isscalar()
{
return basetype->nextOf()->isscalar();
}
MATCH TypeVector::implicitConvTo(Type *to)
{
//printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
if (ty == to->ty)
return MATCHconvert;
return MATCHnomatch;
}
/***************************** TypeArray *****************************/
TypeArray::TypeArray(TY ty, Type *next)
: TypeNext(ty, next)
{
}
Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
Type *n = this->next->toBasetype(); // uncover any typedef's
#if LOGDOTEXP
printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (!n->isMutable())
if (ident == Id::sort || ident == Id::reverse)
error(e->loc, "can only %s a mutable array\n", ident->toChars());
if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar))
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
const char *nm;
static const char *name[2] = { "_adReverseChar", "_adReverseWchar" };
nm = name[n->ty == Twchar];
fd = FuncDeclaration::genCfunc(Type::tindex, nm);
ec = new VarExp(0, fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar))
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
const char *nm;
static const char *name[2] = { "_adSortChar", "_adSortWchar" };
nm = name[n->ty == Twchar];
fd = FuncDeclaration::genCfunc(Type::tindex, nm);
ec = new VarExp(0, fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::reverse || ident == Id::dup || ident == Id::idup)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
int size = next->size(e->loc);
int dup;
Expression *olde = e;
assert(size);
dup = (ident == Id::dup || ident == Id::idup);
fd = FuncDeclaration::genCfunc(Type::tindex, dup ? Id::adDup : Id::adReverse);
ec = new VarExp(0, fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
if (dup)
arguments->push(getTypeInfo(sc));
arguments->push(e);
if (!dup)
arguments->push(new IntegerExp(0, size, Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
if (ident == Id::idup)
{ Type *einv = next->invariantOf();
if (next->implicitConvTo(einv) < MATCHconst)
error(e->loc, "cannot implicitly convert element type %s to immutable in %s.idup",
next->toChars(), olde->toChars());
e->type = einv->arrayOf();
}
else if (ident == Id::dup)
{
Type *emut = next->mutableOf();
if (next->implicitConvTo(emut) < MATCHconst)
error(e->loc, "cannot implicitly convert element type %s to mutable in %s.dup",
next->toChars(), olde->toChars());
e->type = emut->arrayOf();
}
else
e->type = next->mutableOf()->arrayOf();
}
else if (ident == Id::sort)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
fd = FuncDeclaration::genCfunc(tint32->arrayOf(), "_adSort");
ec = new VarExp(0, fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
arguments->push(n->ty == Tsarray
? n->getTypeInfo(sc) // don't convert to dynamic array
: n->getInternalTypeInfo(sc));
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else
{
e = Type::dotExp(sc, e, ident);
}
e = e->semantic(sc);
return e;
}
/***************************** TypeSArray *****************************/
TypeSArray::TypeSArray(Type *t, Expression *dim)
: TypeArray(Tsarray, t)
{
//printf("TypeSArray(%s)\n", dim->toChars());
this->dim = dim;
}
Type *TypeSArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
Expression *e = dim->syntaxCopy();
t = new TypeSArray(t, e);
t->mod = mod;
return t;
}
d_uns64 TypeSArray::size(Loc loc)
{ dinteger_t sz;
if (!dim)
return Type::size(loc);
sz = dim->toInteger();
{ dinteger_t n, n2;
n = next->size();
n2 = n * sz;
if (n && (n2 / n) != sz)
goto Loverflow;
sz = n2;
}
return sz;
Loverflow:
error(loc, "index %lld overflow for static array", sz);
return 1;
}
unsigned TypeSArray::alignsize()
{
return next->alignsize();
}
/**************************
* This evaluates exp while setting length to be the number
* of elements in the tuple t.
*/
Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
{
if (t->ty == Ttuple)
{ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
sym->parent = sc->scopesym;
sc = sc->push(sym);
exp = exp->semantic(sc);
sc->pop();
}
else
exp = exp->semantic(sc);
return exp;
}
Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
sym->parent = sc->scopesym;
sc = sc->push(sym);
exp = exp->semantic(sc);
sc->pop();
return exp;
}
void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("TypeSArray::resolve() %s\n", toChars());
next->resolve(loc, sc, pe, pt, ps);
//printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
if (*pe)
{ // It's really an index expression
Expressions *exps = new Expressions();
exps->setDim(1);
(*exps)[0] = dim;
Expression *e = new ArrayExp(loc, *pe, exps);
*pe = e;
}
else if (*ps)
{ Dsymbol *s = *ps;
TupleDeclaration *td = s->isTupleDeclaration();
if (td)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
sym->parent = sc->scopesym;
sc = sc->push(sym);
dim = dim->semantic(sc);
dim = dim->optimize(WANTvalue | WANTinterpret);
uinteger_t d = dim->toUInteger();
sc = sc->pop();
if (d >= td->objects->dim)
{ error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim);
goto Ldefault;
}
Object *o = td->objects->tdata()[(size_t)d];
if (o->dyncast() == DYNCAST_DSYMBOL)
{
*ps = (Dsymbol *)o;
return;
}
if (o->dyncast() == DYNCAST_EXPRESSION)
{
*ps = NULL;
*pe = (Expression *)o;
return;
}
if (o->dyncast() == DYNCAST_TYPE)
{
*ps = NULL;
*pt = (Type *)o;
return;
}
/* Create a new TupleDeclaration which
* is a slice [d..d+1] out of the old one.
* Do it this way because TemplateInstance::semanticTiargs()
* can handle unresolved Objects this way.
*/
Objects *objects = new Objects;
objects->setDim(1);
objects->tdata()[0] = o;
TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
*ps = tds;
}
else
goto Ldefault;
}
else
{
Ldefault:
Type::resolve(loc, sc, pe, pt, ps);
}
}
Type *TypeSArray::semantic(Loc loc, Scope *sc)
{
//printf("TypeSArray::semantic() %s\n", toChars());
Type *t;
Expression *e;
Dsymbol *s;
next->resolve(loc, sc, &e, &t, &s);
if (dim && s && s->isTupleDeclaration())
{ TupleDeclaration *sd = s->isTupleDeclaration();
dim = semanticLength(sc, sd, dim);
dim = dim->optimize(WANTvalue | WANTinterpret);
uinteger_t d = dim->toUInteger();
if (d >= sd->objects->dim)
{ error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim);
return Type::terror;
}
Object *o = sd->objects->tdata()[(size_t)d];
if (o->dyncast() != DYNCAST_TYPE)
{ error(loc, "%s is not a type", toChars());
return Type::terror;
}
t = (Type *)o;
return t;
}
Type *tn = next->semantic(loc,sc);
if (tn->ty == Terror)
return terror;
Type *tbn = tn->toBasetype();
if (dim)
{ dinteger_t n, n2;
int errors = global.errors;
dim = semanticLength(sc, tbn, dim);
if (errors != global.errors)
goto Lerror;
dim = dim->optimize(WANTvalue);
if (sc && sc->parameterSpecialization && dim->op == TOKvar &&
((VarExp *)dim)->var->storage_class & STCtemplateparameter)
{
/* It could be a template parameter N which has no value yet:
* template Foo(T : T[N], size_t N);
*/
return this;
}
dim = dim->optimize(WANTvalue | WANTinterpret);
dinteger_t d1 = dim->toInteger();
dim = dim->implicitCastTo(sc, tsize_t);
dim = dim->optimize(WANTvalue);
dinteger_t d2 = dim->toInteger();
if (dim->op == TOKerror)
goto Lerror;
if (d1 != d2)
goto Loverflow;
if (tbn->isintegral() ||
tbn->isfloating() ||
tbn->ty == Tpointer ||
tbn->ty == Tarray ||
tbn->ty == Tsarray ||
tbn->ty == Taarray ||
tbn->ty == Tclass)
{
/* Only do this for types that don't need to have semantic()
* run on them for the size, since they may be forward referenced.
*/
n = tbn->size(loc);
n2 = n * d2;
if ((int)n2 < 0)
goto Loverflow;
if (n2 >= 0x1000000) // put a 'reasonable' limit on it
goto Loverflow;
if (n && n2 / n != d2)
{
Loverflow:
error(loc, "index %lld overflow for static array", d1);
goto Lerror;
}
}
}
switch (tbn->ty)
{
case Ttuple:
{ // Index the tuple to get the type
assert(dim);
TypeTuple *tt = (TypeTuple *)tbn;
uinteger_t d = dim->toUInteger();
if (d >= tt->arguments->dim)
{ error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim);
goto Lerror;
}
Parameter *arg = tt->arguments->tdata()[(size_t)d];
return arg->type;
}
case Tstruct:
{ TypeStruct *ts = (TypeStruct *)tbn;
if (0 && ts->sym->isnested)
{ error(loc, "cannot have static array of inner struct %s", ts->toChars());
goto Lerror;
}
break;
}
case Tfunction:
case Tnone:
error(loc, "can't have array of %s", tbn->toChars());
goto Lerror;
}
if (tbn->isscope())
{ error(loc, "cannot have array of scope %s", tbn->toChars());
goto Lerror;
}
/* Ensure things like const(immutable(T)[3]) become immutable(T[3])
* and const(T)[3] become const(T[3])
*/
next = tn;
transitive();
t = addMod(tn->mod);
return t->merge();
Lerror:
return Type::terror;
}
void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
if (dim)
buf->printf("%llu", dim->toInteger());
if (next)
/* Note that static arrays are value types, so
* for a parameter, propagate the 0x100 to the next
* level, since for T[4][3], any const should apply to the T,
* not the [4].
*/
next->toDecoBuffer(buf, (flag & 0x100) ? flag : mod);
}
void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->printf("[%s]", dim->toChars());
}
Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
e = dim;
}
else if (ident == Id::ptr)
{
e = e->castTo(sc, next->pointerTo());
}
else
{
e = TypeArray::dotExp(sc, e, ident);
}
e = e->semantic(sc);
return e;
}
int TypeSArray::isString()
{
TY nty = next->toBasetype()->ty;
return nty == Tchar || nty == Twchar || nty == Tdchar;
}
unsigned TypeSArray::memalign(unsigned salign)
{
return next->memalign(salign);
}
MATCH TypeSArray::constConv(Type *to)
{
if (to->ty == Tsarray)
{
TypeSArray *tsa = (TypeSArray *)to;
if (!dim->equals(tsa->dim))
return MATCHnomatch;
}
return TypeNext::constConv(to);
}
MATCH TypeSArray::implicitConvTo(Type *to)
{
//printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
// Allow implicit conversion of static array to pointer or dynamic array
if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
{
TypePointer *tp = (TypePointer *)to;
if (!MODimplicitConv(next->mod, tp->next->mod))
return MATCHnomatch;
if (tp->next->ty == Tvoid || next->constConv(tp->next) != MATCHnomatch)
{
return MATCHconvert;
}
return MATCHnomatch;
}
if (to->ty == Tarray)
{
TypeDArray *ta = (TypeDArray *)to;
if (!MODimplicitConv(next->mod, ta->next->mod))
return MATCHnomatch;
/* Allow conversion to void[]
*/
if (ta->next->ty == Tvoid)
{
return MATCHconvert;
}
MATCH m = next->constConv(ta->next);
if (m != MATCHnomatch)
{
return MATCHconvert;
}
return MATCHnomatch;
}
if (to->ty == Tsarray)
{
if (this == to)
return MATCHexact;
TypeSArray *tsa = (TypeSArray *)to;
if (dim->equals(tsa->dim))
{
/* Since static arrays are value types, allow
* conversions from const elements to non-const
* ones, just like we allow conversion from const int
* to int.
*/
MATCH m = next->implicitConvTo(tsa->next);
if (m >= MATCHconst)
{
if (mod != to->mod)
m = MATCHconst;
return m;
}
}
}
return MATCHnomatch;
}
Expression *TypeSArray::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeSArray::defaultInit() '%s'\n", toChars());
#endif
return next->defaultInit(loc);
}
int TypeSArray::isZeroInit(Loc loc)
{
return next->isZeroInit(loc);
}
int TypeSArray::needsDestruction()
{
return next->needsDestruction();
}
Expression *TypeSArray::defaultInitLiteral(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars());
#endif
size_t d = dim->toInteger();
Expression *elementinit = next->defaultInitLiteral(loc);
Expressions *elements = new Expressions();
elements->setDim(d);
for (size_t i = 0; i < d; i++)
elements->tdata()[i] = elementinit;
ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
ae->type = this;
return ae;
}
Expression *TypeSArray::toExpression()
{
Expression *e = next->toExpression();
if (e)
{ Expressions *arguments = new Expressions();
arguments->push(dim);
e = new ArrayExp(dim->loc, e, arguments);
}
return e;
}
int TypeSArray::hasPointers()
{
/* Don't want to do this, because:
* struct S { T* array[0]; }
* may be a variable length struct.
*/
//if (dim->toInteger() == 0)
//return FALSE;
if (next->ty == Tvoid)
// Arrays of void contain arbitrary data, which may include pointers
return TRUE;
else
return next->hasPointers();
}
/***************************** TypeDArray *****************************/
TypeDArray::TypeDArray(Type *t)
: TypeArray(Tarray, t)
{
//printf("TypeDArray(t = %p)\n", t);
}
Type *TypeDArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypeDArray(t);
t->mod = mod;
}
return t;
}
d_uns64 TypeDArray::size(Loc loc)
{
//printf("TypeDArray::size()\n");
return PTRSIZE * 2;
}
unsigned TypeDArray::alignsize()
{
// A DArray consists of two ptr-sized values, so align it on pointer size
// boundary
return PTRSIZE;
}
Type *TypeDArray::semantic(Loc loc, Scope *sc)
{ Type *tn = next;
tn = next->semantic(loc,sc);
Type *tbn = tn->toBasetype();
switch (tbn->ty)
{
case Tfunction:
case Tnone:
case Ttuple:
error(loc, "can't have array of %s", tbn->toChars());
case Terror:
return Type::terror;
case Tstruct:
{ TypeStruct *ts = (TypeStruct *)tbn;
if (0 && ts->sym->isnested)
error(loc, "cannot have dynamic array of inner struct %s", ts->toChars());
break;
}
}
if (tn->isscope())
error(loc, "cannot have array of scope %s", tn->toChars());
next = tn;
transitive();
return merge();
}
void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("TypeDArray::resolve() %s\n", toChars());
next->resolve(loc, sc, pe, pt, ps);
//printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
if (*pe)
{ // It's really a slice expression
Expression *e = new SliceExp(loc, *pe, NULL, NULL);
*pe = e;
}
else if (*ps)
{
TupleDeclaration *td = (*ps)->isTupleDeclaration();
if (td)
; // keep *ps
else
goto Ldefault;
}
else
{
Ldefault:
Type::resolve(loc, sc, pe, pt, ps);
}
}
void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
if (next)
next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
if (equals(tstring))
buf->writestring("string");
else
{ next->toCBuffer2(buf, hgs, this->mod);
buf->writestring("[]");
}
}
Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
if (e->op == TOKstring)
{ StringExp *se = (StringExp *)e;
return new IntegerExp(se->loc, se->len, Type::tindex);
}
if (e->op == TOKnull)
return new IntegerExp(e->loc, 0, Type::tindex);
e = new ArrayLengthExp(e->loc, e);
e->type = Type::tsize_t;
return e;
}
else if (ident == Id::ptr)
{
e = e->castTo(sc, next->pointerTo());
return e;
}
else
{
e = TypeArray::dotExp(sc, e, ident);
}
return e;
}
int TypeDArray::isString()
{
TY nty = next->toBasetype()->ty;
return nty == Tchar || nty == Twchar || nty == Tdchar;
}
MATCH TypeDArray::implicitConvTo(Type *to)
{
//printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
if (equals(to))
return MATCHexact;
// Allow implicit conversion of array to pointer
if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
{
TypePointer *tp = (TypePointer *)to;
/* Allow conversion to void*
*/
if (tp->next->ty == Tvoid &&
MODimplicitConv(next->mod, tp->next->mod))
{
return MATCHconvert;
}
return next->constConv(to);
}
if (to->ty == Tarray)
{
TypeDArray *ta = (TypeDArray *)to;
if (!MODimplicitConv(next->mod, ta->next->mod))
return MATCHnomatch; // not const-compatible
// Check head inout conversion:
// T [] -> inout(const(T)[])
// const(T)[] -> inout(const(T)[])
if (isMutable() && ta->isWild())
if ((next->isMutable() || next->isConst()) && ta->next->isConst())
return MATCHnomatch;
/* Allow conversion to void[]
*/
if (next->ty != Tvoid && ta->next->ty == Tvoid)
{
return MATCHconvert;
}
MATCH m = next->constConv(ta->next);
if (m != MATCHnomatch)
{
if (m == MATCHexact && mod != to->mod)
m = MATCHconst;
return m;
}
}
return Type::implicitConvTo(to);
}
Expression *TypeDArray::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeDArray::defaultInit() '%s'\n", toChars());
#endif
return new NullExp(loc, this);
}
int TypeDArray::isZeroInit(Loc loc)
{
return 1;
}
int TypeDArray::checkBoolean()
{
return TRUE;
}
int TypeDArray::hasPointers()
{
return TRUE;
}
/***************************** TypeAArray *****************************/
TypeAArray::TypeAArray(Type *t, Type *index)
: TypeArray(Taarray, t)
{
this->index = index;
this->impl = NULL;
this->loc = 0;
this->sc = NULL;
}
Type *TypeAArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
Type *ti = index->syntaxCopy();
if (t == next && ti == index)
t = this;
else
{ t = new TypeAArray(t, ti);
t->mod = mod;
}
return t;
}
d_uns64 TypeAArray::size(Loc loc)
{
return PTRSIZE /* * 2*/;
}
Type *TypeAArray::semantic(Loc loc, Scope *sc)
{
//printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
if (deco)
return this;
this->loc = loc;
this->sc = sc;
if (sc)
sc->setNoFree();
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
{
Expression *e;
Type *t;
Dsymbol *s;
index->resolve(loc, sc, &e, &t, &s);
if (e)
{ // It was an expression -
// Rewrite as a static array
TypeSArray *tsa;
tsa = new TypeSArray(next, e);
return tsa->semantic(loc,sc);
}
else if (t)
index = t;
else
{ index->error(loc, "index is not a type or an expression");
return Type::terror;
}
}
else
index = index->semantic(loc,sc);
if (index->nextOf() && !index->nextOf()->isImmutable())
{
index = index->constOf()->mutableOf();
#if 0
printf("index is %p %s\n", index, index->toChars());
index->check();
printf("index->mod = x%x\n", index->mod);
printf("index->ito = x%x\n", index->ito);
if (index->ito) {
printf("index->ito->mod = x%x\n", index->ito->mod);
printf("index->ito->ito = x%x\n", index->ito->ito);
}
#endif
}
switch (index->toBasetype()->ty)
{
case Tfunction:
case Tvoid:
case Tnone:
case Ttuple:
error(loc, "can't have associative array key of %s", index->toBasetype()->toChars());
case Terror:
return Type::terror;
}
next = next->semantic(loc,sc);
transitive();
switch (next->toBasetype()->ty)
{
case Tfunction:
case Tvoid:
case Tnone:
error(loc, "can't have associative array of %s", next->toChars());
case Terror:
return Type::terror;
}
if (next->isscope())
{ error(loc, "cannot have array of scope %s", next->toChars());
return Type::terror;
}
return merge();
}
StructDeclaration *TypeAArray::getImpl()
{
// Do it lazily
if (!impl)
{
Type *index = this->index;
Type *next = this->next;
if (index->reliesOnTident() || next->reliesOnTident())
{
error(loc, "cannot create associative array %s", toChars());
index = terror;
next = terror;
// Head off future failures
StructDeclaration *s = new StructDeclaration(0, NULL);
s->type = terror;
impl = s;
return impl;
}
/* This is really a proxy for the template instance AssocArray!(index, next)
* But the instantiation can fail if it is a template specialization field
* which has Tident's instead of real types.
*/
Objects *tiargs = new Objects();
tiargs->push(index->substWildTo(MODconst)); // hack for bug7757
tiargs->push(next ->substWildTo(MODconst)); // hack for bug7757
// Create AssociativeArray!(index, next)
#if 1
if (! Type::associativearray)
{
ObjectNotFound(Id::AssociativeArray);
}
TemplateInstance *ti = new TemplateInstance(loc, Type::associativearray, tiargs);
#else
//Expression *e = new IdentifierExp(loc, Id::object);
Expression *e = new IdentifierExp(loc, Id::empty);
//e = new DotIdExp(loc, e, Id::object);
DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(loc,
e,
Id::AssociativeArray,
tiargs);
dti->semantic(sc);
TemplateInstance *ti = dti->ti;
#endif
ti->semantic(sc);
ti->semantic2(sc);
ti->semantic3(sc);
impl = ti->toAlias()->isStructDeclaration();
#ifdef DEBUG
if (!impl)
{ Dsymbol *s = ti->toAlias();
printf("%s %s\n", s->kind(), s->toChars());
}
#endif
assert(impl);
}
return impl;
}
void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("TypeAArray::resolve() %s\n", toChars());
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
{
Expression *e;
Type *t;
Dsymbol *s;
index->resolve(loc, sc, &e, &t, &s);
if (e)
{ // It was an expression -
// Rewrite as a static array
TypeSArray *tsa = new TypeSArray(next, e);
return tsa->resolve(loc, sc, pe, pt, ps);
}
else if (t)
index = t;
else
index->error(loc, "index is not a type or an expression");
}
Type::resolve(loc, sc, pe, pt, ps);
}
Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
#if 0
if (ident == Id::length)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen);
ec = new VarExp(0, fd);
arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = ((TypeFunction *)fd->type)->next;
}
else
if (ident == Id::keys)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
int size = index->size(e->loc);
assert(size);
fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaKeys);
ec = new VarExp(0, fd);
arguments = new Expressions();
arguments->push(e);
arguments->push(new IntegerExp(0, size, Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
e->type = index->arrayOf();
}
else if (ident == Id::values)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaValues);
ec = new VarExp(0, fd);
arguments = new Expressions();
arguments->push(e);
size_t keysize = index->size(e->loc);
keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1);
arguments->push(new IntegerExp(0, keysize, Type::tsize_t));
arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::rehash)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
fd = FuncDeclaration::genCfunc(Type::tint64, Id::aaRehash);
ec = new VarExp(0, fd);
arguments = new Expressions();
arguments->push(e->addressOf(sc));
arguments->push(index->getInternalTypeInfo(sc));
e = new CallExp(e->loc, ec, arguments);
e->type = this;
}
else
#endif
if (ident != Id::__sizeof &&
ident != Id::__xalignof &&
ident != Id::init &&
ident != Id::mangleof &&
ident != Id::stringof &&
ident != Id::offsetof)
{
//printf("test1: %s, %s\n", e->toChars(), e->type->toChars());
Type *t = getImpl()->type;
//printf("test2: %s, %s\n", e->toChars(), e->type->toChars());
e->type = t;
e = t->dotExp(sc, e, ident);
//printf("test3: %s, %s\n", e->toChars(), e->type->toChars());
}
else
e = Type::dotExp(sc, e, ident);
return e;
}
void TypeAArray::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
index->toDecoBuffer(buf);
next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->writeByte('[');
index->toCBuffer2(buf, hgs, 0);
buf->writeByte(']');
}
Expression *TypeAArray::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeAArray::defaultInit() '%s'\n", toChars());
#endif
return new NullExp(loc, this);
}
int TypeAArray::isZeroInit(Loc loc)
{
return TRUE;
}
int TypeAArray::checkBoolean()
{
return TRUE;
}
Expression *TypeAArray::toExpression()
{
Expression *e = next->toExpression();
if (e)
{
Expression *ei = index->toExpression();
if (ei)
{
Expressions *arguments = new Expressions();
arguments->push(ei);
return new ArrayExp(loc, e, arguments);
}
}
return NULL;
}
int TypeAArray::hasPointers()
{
return TRUE;
}
MATCH TypeAArray::implicitConvTo(Type *to)
{
//printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
if (equals(to))
return MATCHexact;
if (to->ty == Taarray)
{ TypeAArray *ta = (TypeAArray *)to;
if (!MODimplicitConv(next->mod, ta->next->mod))
return MATCHnomatch; // not const-compatible
if (!MODimplicitConv(index->mod, ta->index->mod))
return MATCHnomatch; // not const-compatible
// Check head inout conversion:
// V [K] -> inout(const(V)[K])
// const(V)[K] -> inout(const(V)[K])
if (isMutable() && ta->isWild())
if ((next->isMutable() || next->isConst()) && ta->next->isConst())
return MATCHnomatch;
MATCH m = next->constConv(ta->next);
MATCH mi = index->constConv(ta->index);
if (m != MATCHnomatch && mi != MATCHnomatch)
{
return MODimplicitConv(mod, to->mod) ? MATCHconst : MATCHnomatch;
}
}
else if (to->ty == Tstruct && ((TypeStruct *)to)->sym->ident == Id::AssociativeArray)
{
int errs = global.startGagging();
Type *from = getImpl()->type;
if (global.endGagging(errs))
{
return MATCHnomatch;
}
return from->implicitConvTo(to);
}
return Type::implicitConvTo(to);
}
MATCH TypeAArray::constConv(Type *to)
{
if (to->ty == Taarray)
{
TypeAArray *taa = (TypeAArray *)to;
MATCH mindex = index->constConv(taa->index);
MATCH mkey = next->constConv(taa->next);
// Pick the worst match
return mkey < mindex ? mkey : mindex;
}
return Type::constConv(to);
}
/***************************** TypePointer *****************************/
TypePointer::TypePointer(Type *t)
: TypeNext(Tpointer, t)
{
}
Type *TypePointer::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypePointer(t);
t->mod = mod;
}
return t;
}
Type *TypePointer::semantic(Loc loc, Scope *sc)
{
//printf("TypePointer::semantic()\n");
if (deco)
return this;
Type *n = next->semantic(loc, sc);
switch (n->toBasetype()->ty)
{
case Ttuple:
error(loc, "can't have pointer to %s", n->toChars());
case Terror:
return Type::terror;
}
if (n != next)
{
deco = NULL;
}
next = n;
if (next->ty != Tfunction)
transitive();
return merge();
}
d_uns64 TypePointer::size(Loc loc)
{
return PTRSIZE;
}
void TypePointer::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypePointer::toCBuffer2() next = %d\n", next->ty);
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
if (next->ty != Tfunction)
buf->writeByte('*');
}
MATCH TypePointer::implicitConvTo(Type *to)
{
//printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
if (equals(to))
return MATCHexact;
if (next->ty == Tfunction)
{
if (to->ty == Tpointer)
{
TypePointer *tp = (TypePointer*)to;
if (tp->next->ty == Tfunction)
{
if (next->equals(tp->next))
return MATCHconst;
if (next->covariant(tp->next) == 1)
return MATCHconvert;
}
else if (tp->next->ty == Tvoid)
{
// Allow conversions to void*
return MATCHconvert;
}
}
return MATCHnomatch;
}
else if (to->ty == Tpointer)
{
TypePointer *tp = (TypePointer *)to;
assert(tp->next);
if (!MODimplicitConv(next->mod, tp->next->mod))
return MATCHnomatch; // not const-compatible
// Check head inout conversion:
// T * -> inout(const(T)*)
// const(T)* -> inout(const(T)*)
if (isMutable() && tp->isWild())
if ((next->isMutable() || next->isConst()) && tp->next->isConst())
return MATCHnomatch;
/* Alloc conversion to void*
*/
if (next->ty != Tvoid && tp->next->ty == Tvoid)
{
return MATCHconvert;
}
MATCH m = next->constConv(tp->next);
if (m != MATCHnomatch)
{
if (m == MATCHexact && mod != to->mod)
m = MATCHconst;
return m;
}
}
return MATCHnomatch;
}
MATCH TypePointer::constConv(Type *to)
{
if (next->ty == Tfunction)
{
if (to->nextOf() && next->equals(((TypeNext*)to)->next))
return Type::constConv(to);
else
return MATCHnomatch;
}
return TypeNext::constConv(to);
}
int TypePointer::isscalar()
{
return TRUE;
}
Expression *TypePointer::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypePointer::defaultInit() '%s'\n", toChars());
#endif
return new NullExp(loc, this);
}
int TypePointer::isZeroInit(Loc loc)
{
return 1;
}
int TypePointer::hasPointers()
{
return TRUE;
}
/***************************** TypeReference *****************************/
TypeReference::TypeReference(Type *t)
: TypeNext(Treference, t)
{
// BUG: what about references to static arrays?
}
Type *TypeReference::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypeReference(t);
t->mod = mod;
}
return t;
}
Type *TypeReference::semantic(Loc loc, Scope *sc)
{
//printf("TypeReference::semantic()\n");
Type *n = next->semantic(loc, sc);
if (n != next)
deco = NULL;
next = n;
transitive();
return merge();
}
d_uns64 TypeReference::size(Loc loc)
{
return PTRSIZE;
}
void TypeReference::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->writeByte('&');
}
Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
// References just forward things along
return next->dotExp(sc, e, ident);
}
Expression *TypeReference::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeReference::defaultInit() '%s'\n", toChars());
#endif
return new NullExp(loc, this);
}
int TypeReference::isZeroInit(Loc loc)
{
return 1;
}
/***************************** TypeFunction *****************************/
TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc)
: TypeNext(Tfunction, treturn)
{
//if (!treturn) *(char*)0=0;
// assert(treturn);
assert(0 <= varargs && varargs <= 2);
this->parameters = parameters;
this->varargs = varargs;
this->linkage = linkage;
this->inuse = 0;
this->isnothrow = false;
this->purity = PUREimpure;
this->isproperty = false;
this->isref = false;
this->iswild = false;
this->fargs = NULL;
if (stc & STCpure)
this->purity = PUREfwdref;
if (stc & STCnothrow)
this->isnothrow = true;
if (stc & STCproperty)
this->isproperty = true;
if (stc & STCref)
this->isref = true;
this->trust = TRUSTdefault;
if (stc & STCsafe)
this->trust = TRUSTsafe;
if (stc & STCsystem)
this->trust = TRUSTsystem;
if (stc & STCtrusted)
this->trust = TRUSTtrusted;
}
Type *TypeFunction::syntaxCopy()
{
Type *treturn = next ? next->syntaxCopy() : NULL;
Parameters *params = Parameter::arraySyntaxCopy(parameters);
TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
t->mod = mod;
t->isnothrow = isnothrow;
t->purity = purity;
t->isproperty = isproperty;
t->isref = isref;
t->trust = trust;
t->fargs = fargs;
return t;
}
/*******************************
* Covariant means that 'this' can substitute for 't',
* i.e. a pure function is a match for an impure type.
* Returns:
* 0 types are distinct
* 1 this is covariant with t
* 2 arguments match as far as overloading goes,
* but types are not covariant
* 3 cannot determine covariance because of forward references
* *pstc STCxxxx which would make it covariant
*/
int Type::covariant(Type *t, StorageClass *pstc)
{
#if 0
printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars());
printf("deco = %p, %p\n", deco, t->deco);
// printf("ty = %d\n", next->ty);
printf("mod = %x, %x\n", mod, t->mod);
#endif
if (pstc)
*pstc = 0;
StorageClass stc = 0;
int inoutmismatch = 0;
TypeFunction *t1;
TypeFunction *t2;
if (equals(t))
return 1; // covariant
if (ty != Tfunction || t->ty != Tfunction)
goto Ldistinct;
t1 = (TypeFunction *)this;
t2 = (TypeFunction *)t;
if (t1->varargs != t2->varargs)
goto Ldistinct;
if (t1->parameters && t2->parameters)
{
size_t dim = Parameter::dim(t1->parameters);
if (dim != Parameter::dim(t2->parameters))
goto Ldistinct;
for (size_t i = 0; i < dim; i++)
{ Parameter *arg1 = Parameter::getNth(t1->parameters, i);
Parameter *arg2 = Parameter::getNth(t2->parameters, i);
if (!arg1->type->equals(arg2->type))
{
#if 0 // turn on this for contravariant argument types, see bugzilla 3075
// BUG: cannot convert ref to const to ref to immutable
// We can add const, but not subtract it
if (arg2->type->implicitConvTo(arg1->type) < MATCHconst)
#endif
goto Ldistinct;
}
const StorageClass sc = STCref | STCin | STCout | STClazy;
if ((arg1->storageClass & sc) != (arg2->storageClass & sc))
inoutmismatch = 1;
// We can add scope, but not subtract it
if (!(arg1->storageClass & STCscope) && (arg2->storageClass & STCscope))
inoutmismatch = 1;
}
}
else if (t1->parameters != t2->parameters)
{
size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim;
size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim;
if (dim1 || dim2)
goto Ldistinct;
}
// The argument lists match
if (inoutmismatch)
goto Lnotcovariant;
if (t1->linkage != t2->linkage)
goto Lnotcovariant;
{
// Return types
Type *t1n = t1->next;
Type *t2n = t2->next;
if (!t1n || !t2n) // happens with return type inference
goto Lnotcovariant;
if (t1n->equals(t2n))
goto Lcovariant;
if (t1n->ty == Tclass && t2n->ty == Tclass)
{
/* If same class type, but t2n is const, then it's
* covariant. Do this test first because it can work on
* forward references.
*/
if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym &&
MODimplicitConv(t1n->mod, t2n->mod))
goto Lcovariant;
// If t1n is forward referenced:
ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
// if (cd->scope)
// cd->semantic(NULL);
#if 0
if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration())
#else
if (!cd->isBaseInfoComplete())
#endif
{
return 3; // forward references
}
}
if (t1n->ty == Tstruct && t2n->ty == Tstruct)
{
if (((TypeStruct *)t1n)->sym == ((TypeStruct *)t2n)->sym &&
MODimplicitConv(t1n->mod, t2n->mod))
goto Lcovariant;
}
else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n))
goto Lcovariant;
}
goto Lnotcovariant;
Lcovariant:
if (t1->isref != t2->isref)
goto Lnotcovariant;
/* Can convert mutable to const
*/
if (!MODimplicitConv(t2->mod, t1->mod))
{
// If adding 'const' will make it covariant
if (MODimplicitConv(t2->mod, MODmerge(t1->mod, MODconst)))
stc |= STCconst;
else
goto Lnotcovariant;
}
/* Can convert pure to impure, and nothrow to throw
*/
if (!t1->purity && t2->purity)
stc |= STCpure;
if (!t1->isnothrow && t2->isnothrow)
stc |= STCnothrow;
/* Can convert safe/trusted to system
*/
if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted)
// Should we infer trusted or safe? Go with safe.
stc |= STCsafe;
if (stc)
{ if (pstc)
*pstc = stc;
goto Lnotcovariant;
}
//printf("\tcovaraint: 1\n");
return 1;
Ldistinct:
//printf("\tcovaraint: 0\n");
return 0;
Lnotcovariant:
//printf("\tcovaraint: 2\n");
return 2;
}
void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag)
{ unsigned char mc;
//printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars());
//static int nest; if (++nest == 50) *(char*)0=0;
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
MODtoDecoBuffer(buf, mod);
switch (linkage)
{
case LINKd: mc = 'F'; break;
case LINKc: mc = 'U'; break;
case LINKwindows: mc = 'W'; break;
case LINKpascal: mc = 'V'; break;
case LINKcpp: mc = 'R'; break;
default:
assert(0);
}
buf->writeByte(mc);
if (purity || isnothrow || isproperty || isref || trust)
{
if (purity)
buf->writestring("Na");
if (isnothrow)
buf->writestring("Nb");
if (isref)
buf->writestring("Nc");
if (isproperty)
buf->writestring("Nd");
switch (trust)
{
case TRUSTtrusted:
buf->writestring("Ne");
break;
case TRUSTsafe:
buf->writestring("Nf");
break;
}
}
// Write argument types
Parameter::argsToDecoBuffer(buf, parameters);
//if (buf->data[buf->offset - 1] == '@') halt();
buf->writeByte('Z' - varargs); // mark end of arg list
assert(next);
next->toDecoBuffer(buf);
inuse--;
}
void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
{
toCBufferWithAttributes(buf, ident, hgs, this, NULL);
}
void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td)
{
//printf("TypeFunction::toCBuffer() this = %p\n", this);
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
/* Use 'storage class' style for attributes
*/
if (attrs->mod)
{
MODtoBuffer(buf, attrs->mod);
buf->writeByte(' ');
}
if (attrs->purity)
buf->writestring("pure ");
if (attrs->isnothrow)
buf->writestring("nothrow ");
if (attrs->isproperty)
buf->writestring("@property ");
if (attrs->isref)
buf->writestring("ref ");
switch (attrs->trust)
{
case TRUSTsystem:
buf->writestring("@system ");
break;
case TRUSTtrusted:
buf->writestring("@trusted ");
break;
case TRUSTsafe:
buf->writestring("@safe ");
break;
}
if (hgs->ddoc != 1)
{
const char *p = NULL;
switch (attrs->linkage)
{
case LINKd: p = NULL; break;
case LINKc: p = "C"; break;
case LINKwindows: p = "Windows"; break;
case LINKpascal: p = "Pascal"; break;
case LINKcpp: p = "C++"; break;
default:
assert(0);
}
if (!hgs->hdrgen && p)
{
buf->writestring("extern (");
buf->writestring(p);
buf->writestring(") ");
}
}
if (!ident || ident->toHChars2() == ident->toChars())
{ if (next)
next->toCBuffer2(buf, hgs, 0);
else if (hgs->ddoc)
buf->writestring("auto");
}
if (ident)
{
if (next || hgs->ddoc)
buf->writeByte(' ');
buf->writestring(ident->toHChars2());
}
if (td)
{ buf->writeByte('(');
for (size_t i = 0; i < td->origParameters->dim; i++)
{
TemplateParameter *tp = td->origParameters->tdata()[i];
if (i)
buf->writestring(", ");
tp->toCBuffer(buf, hgs);
}
buf->writeByte(')');
}
Parameter::argsToCBuffer(buf, hgs, parameters, varargs);
inuse--;
}
void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref);
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
if (hgs->ddoc != 1)
{
const char *p = NULL;
switch (linkage)
{
case LINKd: p = NULL; break;
case LINKc: p = "C"; break;
case LINKwindows: p = "Windows"; break;
case LINKpascal: p = "Pascal"; break;
case LINKcpp: p = "C++"; break;
default:
assert(0);
}
if (!hgs->hdrgen && p)
{
buf->writestring("extern (");
buf->writestring(p);
buf->writestring(") ");
}
}
if (next)
{
next->toCBuffer2(buf, hgs, 0);
buf->writeByte(' ');
}
buf->writestring("function");
Parameter::argsToCBuffer(buf, hgs, parameters, varargs);
attributesToCBuffer(buf, mod);
inuse--;
}
void TypeFunction::attributesToCBuffer(OutBuffer *buf, int mod)
{
/* Use postfix style for attributes
*/
if (mod != this->mod)
{
modToBuffer(buf);
}
if (purity)
buf->writestring(" pure");
if (isnothrow)
buf->writestring(" nothrow");
if (isproperty)
buf->writestring(" @property");
if (isref)
buf->writestring(" ref");
switch (trust)
{
case TRUSTsystem:
buf->writestring(" @system");
break;
case TRUSTtrusted:
buf->writestring(" @trusted");
break;
case TRUSTsafe:
buf->writestring(" @safe");
break;
}
}
Type *TypeFunction::semantic(Loc loc, Scope *sc)
{
if (deco) // if semantic() already run
{
//printf("already done\n");
return this;
}
//printf("TypeFunction::semantic() this = %p\n", this);
//printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs);
/* Copy in order to not mess up original.
* This can produce redundant copies if inferring return type,
* as semantic() will get called again on this.
*/
TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction));
memcpy(tf, this, sizeof(TypeFunction));
if (parameters)
{ tf->parameters = (Parameters *)parameters->copy();
for (size_t i = 0; i < parameters->dim; i++)
{ Parameter *arg = parameters->tdata()[i];
Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter));
memcpy(cpy, arg, sizeof(Parameter));
tf->parameters->tdata()[i] = cpy;
}
}
if (sc->stc & STCpure)
tf->purity = PUREfwdref;
if (sc->stc & STCnothrow)
tf->isnothrow = TRUE;
if (sc->stc & STCref)
tf->isref = TRUE;
if (sc->stc & STCsafe)
tf->trust = TRUSTsafe;
if (sc->stc & STCsystem)
tf->trust = TRUSTsystem;
if (sc->stc & STCtrusted)
tf->trust = TRUSTtrusted;
if (sc->stc & STCproperty)
tf->isproperty = TRUE;
tf->linkage = sc->linkage;
/* If the parent is @safe, then this function defaults to safe
* too.
* If the parent's @safe-ty is inferred, then this function's @safe-ty needs
* to be inferred first.
*/
if (tf->trust == TRUSTdefault)
for (Dsymbol *p = sc->func; p; p = p->toParent2())
{ FuncDeclaration *fd = p->isFuncDeclaration();
if (fd)
{
if (fd->isSafeBypassingInference())
tf->trust = TRUSTsafe; // default to @safe
break;
}
}
bool wildreturn = FALSE;
if (tf->next)
{
sc = sc->push();
sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
tf->next = tf->next->semantic(loc,sc);
sc = sc->pop();
#if !SARRAYVALUE
if (tf->next->toBasetype()->ty == Tsarray)
{ error(loc, "functions cannot return static array %s", tf->next->toChars());
tf->next = Type::terror;
}
#endif
if (tf->next->toBasetype()->ty == Tfunction)
{ error(loc, "functions cannot return a function");
tf->next = Type::terror;
}
if (tf->next->toBasetype()->ty == Ttuple)
{ error(loc, "functions cannot return a tuple");
tf->next = Type::terror;
}
if (tf->next->isscope() && !(sc->flags & SCOPEctor))
error(loc, "functions cannot return scope %s", tf->next->toChars());
if (tf->next->toBasetype()->ty == Tvoid)
tf->isref = FALSE; // rewrite "ref void" as just "void"
if (tf->next->hasWild() &&
!(tf->next->ty == Tpointer && tf->next->nextOf()->ty == Tfunction || tf->next->ty == Tdelegate))
wildreturn = TRUE;
}
bool wildparams = FALSE;
if (tf->parameters)
{
/* Create a scope for evaluating the default arguments for the parameters
*/
Scope *argsc = sc->push();
argsc->stc = 0; // don't inherit storage class
argsc->protection = PROTpublic;
argsc->func = NULL;
size_t dim = Parameter::dim(tf->parameters);
for (size_t i = 0; i < dim; i++)
{ Parameter *fparam = Parameter::getNth(tf->parameters, i);
tf->inuse++;
fparam->type = fparam->type->semantic(loc, argsc);
if (tf->inuse == 1) tf->inuse--;
fparam->type = fparam->type->addStorageClass(fparam->storageClass);
if (fparam->storageClass & (STCauto | STCalias | STCstatic))
{
if (!fparam->type)
continue;
}
Type *t = fparam->type->toBasetype();
if (fparam->storageClass & (STCout | STCref | STClazy))
{
//if (t->ty == Tsarray)
//error(loc, "cannot have out or ref parameter of type %s", t->toChars());
if (fparam->storageClass & STCout && fparam->type->mod & (STCconst | STCimmutable))
error(loc, "cannot have const or immutable out parameter of type %s", t->toChars());
}
if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
error(loc, "cannot have parameter of type %s", fparam->type->toChars());
if (t->hasWild() &&
!(t->ty == Tpointer && t->nextOf()->ty == Tfunction || t->ty == Tdelegate))
{
wildparams = TRUE;
//if (tf->next && !wildreturn)
// error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')");
}
if (fparam->defaultArg)
{ Expression *e = fparam->defaultArg;
e = e->inferType(fparam->type);
e = e->semantic(argsc);
e = resolveProperties(argsc, e);
if (e->op == TOKfunction) // see Bugzilla 4820
{ FuncExp *fe = (FuncExp *)e;
if (fe->fd)
{ if (fe->fd->tok == TOKreserved)
{
if (fe->type->ty == Tpointer)
{
fe->fd->vthis = NULL;
fe->fd->tok = TOKfunction;
}
else
fe->fd->tok = TOKdelegate;
}
// Replace function literal with a function symbol,
// since default arg expression must be copied when used
// and copying the literal itself is wrong.
e = new VarExp(e->loc, fe->fd, 0);
e = new AddrExp(e->loc, e);
e = e->semantic(argsc);
}
}
e = e->implicitCastTo(argsc, fparam->type);
fparam->defaultArg = e;
}
/* If fparam after semantic() turns out to be a tuple, the number of parameters may
* change.
*/
if (t->ty == Ttuple)
{
TypeTuple *tt = (TypeTuple *)t;
if (fparam->storageClass && tt->arguments && tt->arguments->dim)
{
/* Propagate additional storage class from tuple parameters to their
* element-parameters.
* Make a copy, as original may be referenced elsewhere.
*/
size_t tdim = tt->arguments->dim;
Parameters *newparams = new Parameters();
newparams->setDim(tdim);
for (size_t j = 0; j < tdim; j++)
{ Parameter *narg = (*tt->arguments)[j];
newparams->tdata()[j] = new Parameter(narg->storageClass | fparam->storageClass,
narg->type, narg->ident, narg->defaultArg);
}
fparam->type = new TypeTuple(newparams);
}
fparam->storageClass = 0;
/* Reset number of parameters, and back up one to do this fparam again,
* now that it is a tuple
*/
dim = Parameter::dim(tf->parameters);
i--;
continue;
}
/* Resolve "auto ref" storage class to be either ref or value,
* based on the argument matching the parameter
*/
if (fparam->storageClass & STCauto)
{
if (fargs && i < fargs->dim)
{ Expression *farg = fargs->tdata()[i];
if (farg->isLvalue())
; // ref parameter
else
fparam->storageClass &= ~STCref; // value parameter
}
else
error(loc, "auto can only be used for template function parameters");
}
// Remove redundant storage classes for type, they are already applied
fparam->storageClass &= ~(STC_TYPECTOR | STCin);
}
argsc->pop();
}
if (tf->isWild())
wildparams = TRUE;
if (wildreturn && !wildparams)
error(loc, "inout on return means inout must be on a parameter as well for %s", toChars());
tf->iswild = wildparams;
if (tf->next)
tf->deco = tf->merge()->deco;
if (tf->inuse)
{ error(loc, "recursive type");
tf->inuse = 0;
return terror;
}
if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 2))
error(loc, "properties can only have zero, one, or two parameter");
if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0)
error(loc, "variadic functions with non-D linkage must have at least one parameter");
/* Don't return merge(), because arg identifiers and default args
* can be different
* even though the types match
*/
return tf;
}
/********************************************
* Do this lazily, as the parameter types might be forward referenced.
*/
void TypeFunction::purityLevel()
{
TypeFunction *tf = this;
if (tf->purity == PUREfwdref)
{ /* Evaluate what kind of purity based on the modifiers for the parameters
*/
tf->purity = PUREstrong; // assume strong until something weakens it
if (tf->parameters)
{
size_t dim = Parameter::dim(tf->parameters);
for (size_t i = 0; i < dim; i++)
{ Parameter *fparam = Parameter::getNth(tf->parameters, i);
if (fparam->storageClass & STClazy)
{
tf->purity = PUREweak;
break;
}
if (fparam->storageClass & STCout)
{
tf->purity = PUREweak;
break;
}
if (!fparam->type)
continue;
if (fparam->storageClass & STCref)
{
if (!(fparam->type->mod & (MODconst | MODimmutable | MODwild)))
{ tf->purity = PUREweak;
break;
}
if (fparam->type->mod & MODconst)
{ tf->purity = PUREconst;
continue;
}
}
Type *t = fparam->type->toBasetype();
if (!t->hasPointers())
continue;
if (t->mod & (MODimmutable | MODwild))
continue;
/* The rest of this is too strict; fix later.
* For example, the only pointer members of a struct may be immutable,
* which would maintain strong purity.
*/
if (t->mod & MODconst)
{ tf->purity = PUREconst;
continue;
}
Type *tn = t->nextOf();
if (tn)
{ tn = tn->toBasetype();
if (tn->ty == Tpointer || tn->ty == Tarray)
{ /* Accept immutable(T)* and immutable(T)[] as being strongly pure
*/
if (tn->mod & (MODimmutable | MODwild))
continue;
if (tn->mod & MODconst)
{ tf->purity = PUREconst;
continue;
}
}
}
/* Should catch delegates and function pointers, and fold in their purity
*/
tf->purity = PUREweak; // err on the side of too strict
break;
}
}
}
}
/********************************
* 'args' are being matched to function 'this'
* Determine match level.
* Input:
* flag 1 performing a partial ordering match
* Returns:
* MATCHxxxx
*/
int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag)
{
//printf("TypeFunction::callMatch() %s\n", toChars());
MATCH match = MATCHexact; // assume exact match
unsigned wildmatch = 0;
if (ethis)
{ Type *t = ethis->type;
if (t->toBasetype()->ty == Tpointer)
t = t->toBasetype()->nextOf(); // change struct* to struct
if (t->mod != mod)
{
if (MODimplicitConv(t->mod, mod))
match = MATCHconst;
else if ((mod & MODwild)
&& MODimplicitConv(t->mod, (mod & ~MODwild) | MODconst))
{
match = MATCHconst;
}
else
return MATCHnomatch;
}
if (isWild())
{
if (t->isWild())
wildmatch |= MODwild;
else if (t->isConst())
wildmatch |= MODconst;
else if (t->isImmutable())
wildmatch |= MODimmutable;
else
wildmatch |= MODmutable;
}
}
size_t nparams = Parameter::dim(parameters);
size_t nargs = args ? args->dim : 0;
if (nparams == nargs)
;
else if (nargs > nparams)
{
if (varargs == 0)
goto Nomatch; // too many args; no match
match = MATCHconvert; // match ... with a "conversion" match level
}
for (size_t u = 0; u < nargs; u++)
{
if (u >= nparams)
break;
Parameter *p = Parameter::getNth(parameters, u);
Expression *arg = args->tdata()[u];
assert(arg);
if (!(p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid))
{
unsigned mod = arg->type->wildConvTo(p->type);
if (mod)
{
wildmatch |= mod;
}
}
}
if (wildmatch)
{ /* Calculate wild matching modifier
*/
if (wildmatch & MODconst || wildmatch & (wildmatch - 1))
wildmatch = MODconst;
else if (wildmatch & MODimmutable)
wildmatch = MODimmutable;
else if (wildmatch & MODwild)
wildmatch = MODwild;
else
{ assert(wildmatch & MODmutable);
wildmatch = MODmutable;
}
}
for (size_t u = 0; u < nparams; u++)
{ MATCH m;
// BUG: what about out and ref?
Parameter *p = Parameter::getNth(parameters, u);
assert(p);
if (u >= nargs)
{
if (p->defaultArg)
continue;
goto L1; // try typesafe variadics
}
{
Expression *arg = args->tdata()[u];
assert(arg);
if (arg->op == TOKfunction)
{
arg = ((FuncExp *)arg)->inferType(p->type, 1);
if (!arg)
goto L1; // try typesafe variadics
}
//printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars());
Type *targ = arg->type;
Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type;
// Non-lvalues do not match ref or out parameters
if (p->storageClass & STCref)
{ if (!arg->isLvalue())
{ if (arg->op == TOKstring && tprm->ty == Tsarray)
{ if (targ->ty != Tsarray)
targ = new TypeSArray(targ->nextOf(),
new IntegerExp(0, ((StringExp *)arg)->len,
Type::tindex));
}
else
goto Nomatch;
}
/* Don't allow static arrays to be passed to mutable references
* to static arrays if the argument cannot be modified.
*/
Type *targb = targ->toBasetype();
Type *tprmb = tprm->toBasetype();
//printf("%s\n", targb->toChars());
//printf("%s\n", tprmb->toChars());
if (targb->nextOf() && tprmb->ty == Tsarray &&
!MODimplicitConv(targb->nextOf()->mod, tprmb->nextOf()->mod))
goto Nomatch;
// ref variable behaves like head-const reference
if (!targb->constConv(tprmb))
goto Nomatch;
}
else if (p->storageClass & STCout)
{ if (!arg->isLvalue())
goto Nomatch;
}
if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid)
m = MATCHconvert;
else
{
//printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars());
if (flag)
// for partial ordering, value is an irrelevant mockup, just look at the type
m = targ->implicitConvTo(tprm);
else
m = arg->implicitConvTo(tprm);
//printf("match %d\n", m);
}
}
/* prefer matching the element type rather than the array
* type when more arguments are present with T[]...
*/
if (varargs == 2 && u + 1 == nparams && nargs > nparams)
goto L1;
//printf("\tm = %d\n", m);
if (m == MATCHnomatch) // if no match
{
L1:
if (varargs == 2 && u + 1 == nparams) // if last varargs param
{ Type *tb = p->type->toBasetype();
TypeSArray *tsa;
dinteger_t sz;
switch (tb->ty)
{
case Tsarray:
tsa = (TypeSArray *)tb;
sz = tsa->dim->toInteger();
if (sz != nargs - u)
goto Nomatch;
case Tarray:
{ TypeArray *ta = (TypeArray *)tb;
for (; u < nargs; u++)
{
Expression *arg = args->tdata()[u];
assert(arg);
#if 1
if (arg->op == TOKfunction)
{
arg = ((FuncExp *)arg)->inferType(tb->nextOf(), 1);
if (!arg)
goto Nomatch;
}
/* If lazy array of delegates,
* convert arg(s) to delegate(s)
*/
Type *tret = p->isLazyArray();
if (tret)
{
if (ta->next->equals(arg->type))
{ m = MATCHexact;
}
else
{
m = arg->implicitConvTo(tret);
if (m == MATCHnomatch)
{
if (tret->toBasetype()->ty == Tvoid)
m = MATCHconvert;
}
}
}
else
m = arg->implicitConvTo(ta->next);
#else
m = arg->implicitConvTo(ta->next);
#endif
if (m == MATCHnomatch)
goto Nomatch;
if (m < match)
match = m;
}
goto Ldone;
}
case Tclass:
// Should see if there's a constructor match?
// Or just leave it ambiguous?
goto Ldone;
default:
goto Nomatch;
}
}
goto Nomatch;
}
if (m < match)
match = m; // pick worst match
}
Ldone:
//printf("match = %d\n", match);
return match;
Nomatch:
//printf("no match\n");
return MATCHnomatch;
}
Type *TypeFunction::reliesOnTident(TemplateParameters *tparams)
{
size_t dim = Parameter::dim(parameters);
for (size_t i = 0; i < dim; i++)
{ Parameter *fparam = Parameter::getNth(parameters, i);
Type *t = fparam->type->reliesOnTident(tparams);
if (t)
return t;
}
return next ? next->reliesOnTident(tparams) : NULL;
}
/********************************************
* Return TRUE if there are lazy parameters.
*/
bool TypeFunction::hasLazyParameters()
{
size_t dim = Parameter::dim(parameters);
for (size_t i = 0; i < dim; i++)
{ Parameter *fparam = Parameter::getNth(parameters, i);
if (fparam->storageClass & STClazy)
return TRUE;
}
return FALSE;
}
/***************************
* Examine function signature for parameter p and see if
* p can 'escape' the scope of the function.
*/
bool TypeFunction::parameterEscapes(Parameter *p)
{
/* Scope parameters do not escape.
* Allow 'lazy' to imply 'scope' -
* lazy parameters can be passed along
* as lazy parameters to the next function, but that isn't
* escaping.
*/
if (p->storageClass & (STCscope | STClazy))
return FALSE;
if (purity)
{ /* With pure functions, we need only be concerned if p escapes
* via any return statement.
*/
Type* tret = nextOf()->toBasetype();
if (!isref && !tret->hasPointers())
{ /* The result has no references, so p could not be escaping
* that way.
*/
return FALSE;
}
}
/* Assume it escapes in the absence of better information.
*/
return TRUE;
}
Expression *TypeFunction::defaultInit(Loc loc)
{
error(loc, "function does not have a default initializer");
return new ErrorExp();
}
Type *TypeFunction::addStorageClass(StorageClass stc)
{
TypeFunction *t = (TypeFunction *)Type::addStorageClass(stc);
if ((stc & STCpure && !t->purity) ||
(stc & STCnothrow && !t->isnothrow) ||
(stc & STCsafe && t->trust < TRUSTtrusted))
{
// Klunky to change these
TypeFunction *tf = new TypeFunction(t->parameters, t->next, t->varargs, t->linkage, 0);
tf->mod = t->mod;
tf->fargs = fargs;
tf->purity = t->purity;
tf->isnothrow = t->isnothrow;
tf->isproperty = t->isproperty;
tf->isref = t->isref;
tf->trust = t->trust;
if (stc & STCpure)
tf->purity = PUREfwdref;
if (stc & STCnothrow)
tf->isnothrow = true;
if (stc & STCsafe)
tf->trust = TRUSTsafe;
tf->deco = tf->merge()->deco;
t = tf;
}
return t;
}
/***************************** TypeDelegate *****************************/
TypeDelegate::TypeDelegate(Type *t)
: TypeNext(Tfunction, t)
{
ty = Tdelegate;
}
Type *TypeDelegate::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypeDelegate(t);
t->mod = mod;
}
return t;
}
Type *TypeDelegate::semantic(Loc loc, Scope *sc)
{
if (deco) // if semantic() already run
{
//printf("already done\n");
return this;
}
next = next->semantic(loc,sc);
/* In order to deal with Bugzilla 4028, perhaps default arguments should
* be removed from next before the merge.
*/
/* Don't return merge(), because arg identifiers and default args
* can be different
* even though the types match
*/
//deco = merge()->deco;
//return this;
return merge();
}
d_uns64 TypeDelegate::size(Loc loc)
{
return PTRSIZE * 2;
}
unsigned TypeDelegate::alignsize()
{
#if DMDV1
// See Bugzilla 942 for discussion
if (!global.params.is64bit)
return PTRSIZE * 2;
#endif
return PTRSIZE;
}
MATCH TypeDelegate::implicitConvTo(Type *to)
{
//printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to);
//printf("from: %s\n", toChars());
//printf("to : %s\n", to->toChars());
if (this == to)
return MATCHexact;
#if 1 // not allowing covariant conversions because it interferes with overriding
if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1)
return MATCHconvert;
#endif
return MATCHnomatch;
}
void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
TypeFunction *tf = (TypeFunction *)next;
tf->next->toCBuffer2(buf, hgs, 0);
buf->writestring(" delegate");
Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs);
tf->attributesToCBuffer(buf, mod);
}
Expression *TypeDelegate::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeDelegate::defaultInit() '%s'\n", toChars());
#endif
return new NullExp(loc, this);
}
int TypeDelegate::isZeroInit(Loc loc)
{
return 1;
}
int TypeDelegate::checkBoolean()
{
return TRUE;
}
Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::ptr)
{
e->type = tvoidptr;
return e;
}
else if (ident == Id::funcptr)
{
e = e->addressOf(sc);
e->type = tvoidptr;
e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE));
e->type = tvoidptr;
e = new PtrExp(e->loc, e);
e->type = next->pointerTo();
return e;
}
else
{
e = Type::dotExp(sc, e, ident);
}
return e;
}
int TypeDelegate::hasPointers()
{
return TRUE;
}
/***************************** TypeQualified *****************************/
TypeQualified::TypeQualified(TY ty, Loc loc)
: Type(ty)
{
this->loc = loc;
}
void TypeQualified::syntaxCopyHelper(TypeQualified *t)
{
//printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
idents.setDim(t->idents.dim);
for (size_t i = 0; i < idents.dim; i++)
{
Identifier *id = t->idents.tdata()[i];
if (id->dyncast() == DYNCAST_DSYMBOL)
{
TemplateInstance *ti = (TemplateInstance *)id;
ti = (TemplateInstance *)ti->syntaxCopy(NULL);
id = (Identifier *)ti;
}
idents.tdata()[i] = id;
}
}
void TypeQualified::addIdent(Identifier *ident)
{
idents.push(ident);
}
void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs)
{
for (size_t i = 0; i < idents.dim; i++)
{ Identifier *id = idents.tdata()[i];
buf->writeByte('.');
if (id->dyncast() == DYNCAST_DSYMBOL)
{
TemplateInstance *ti = (TemplateInstance *)id;
ti->toCBuffer(buf, hgs);
}
else
buf->writestring(id->toChars());
}
}
d_uns64 TypeQualified::size(Loc loc)
{
error(this->loc, "size of type %s is not known", toChars());
return 1;
}
/*************************************
* Takes an array of Identifiers and figures out if
* it represents a Type or an Expression.
* Output:
* if expression, *pe is set
* if type, *pt is set
*/
void TypeQualified::resolveHelper(Loc loc, Scope *sc,
Dsymbol *s, Dsymbol *scopesym,
Expression **pe, Type **pt, Dsymbol **ps)
{
VarDeclaration *v;
EnumMember *em;
Expression *e;
#if 0
printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars());
if (scopesym)
printf("\tscopesym = '%s'\n", scopesym->toChars());
#endif
*pe = NULL;
*pt = NULL;
*ps = NULL;
if (s)
{
//printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
s->checkDeprecated(loc, sc); // check for deprecated aliases
s = s->toAlias();
//printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
for (size_t i = 0; i < idents.dim; i++)
{
Identifier *id = idents.tdata()[i];
Dsymbol *sm = s->searchX(loc, sc, id);
//printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
//printf("\tgetType = '%s'\n", s->getType()->toChars());
if (!sm)
{ Type *t;
v = s->isVarDeclaration();
if (v && id == Id::length)
{
e = v->getConstInitializer();
if (!e)
e = new VarExp(loc, v);
t = e->type;
if (!t)
goto Lerror;
goto L3;
}
else if (v && (id == Id::stringof || id == Id::offsetof))
{
e = new DsymbolExp(loc, s, 0);
do
{
id = idents.tdata()[i];
e = new DotIdExp(loc, e, id);
} while (++i < idents.dim);
e = e->semantic(sc);
*pe = e;
return;
}
t = s->getType();
if (!t && s->isDeclaration())
{ t = s->isDeclaration()->type;
if (!t && s->isTupleDeclaration())
{
e = new TupleExp(loc, s->isTupleDeclaration());
e = e->semantic(sc);
t = e->type;
}
}
if (t)
{
sm = t->toDsymbol(sc);
if (sm)
{ sm = sm->search(loc, id, 0);
if (sm)
goto L2;
}
//e = t->getProperty(loc, id);
e = new TypeExp(loc, t);
e = t->dotExp(sc, e, id);
i++;
L3:
for (; i < idents.dim; i++)
{
id = idents.tdata()[i];
//printf("e: '%s', id: '%s', type = %s\n", e->toChars(), id->toChars(), e->type->toChars());
e = new DotIdExp(e->loc, e, id);
e = e->semantic(sc);
}
if (e->op == TOKtype)
*pt = e->type;
else
*pe = e;
}
else
{
Lerror:
if (id->dyncast() == DYNCAST_DSYMBOL)
{ // searchX already handles errors for template instances
assert(global.errors);
}
else
{
sm = s->search_correct(id);
if (sm)
error(loc, "identifier '%s' of '%s' is not defined, did you mean '%s %s'?",
id->toChars(), toChars(), sm->kind(), sm->toChars());
else
error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
}
*pe = new ErrorExp();
}
return;
}
L2:
s = sm->toAlias();
}
v = s->isVarDeclaration();
if (v)
{
*pe = new VarExp(loc, v);
return;
}
#if 0
fd = s->isFuncDeclaration();
if (fd)
{
*pe = new DsymbolExp(loc, fd, 1);
return;
}
#endif
em = s->isEnumMember();
if (em)
{
// It's not a type, it's an expression
*pe = em->value->copy();
return;
}
L1:
Type *t = s->getType();
if (!t)
{
// If the symbol is an import, try looking inside the import
Import *si;
si = s->isImport();
if (si)
{
s = si->search(loc, s->ident, 0);
if (s && s != si)
goto L1;
s = si;
}
*ps = s;
return;
}
if (t->ty == Tinstance && t != this && !t->deco)
{ error(loc, "forward reference to '%s'", t->toChars());
return;
}
if (t != this)
{
if (t->reliesOnTident())
{
if (s->scope)
t = t->semantic(loc, s->scope);
else
{
/* Attempt to find correct scope in which to evaluate t.
* Not sure if this is right or not, or if we should just
* give forward reference error if s->scope is not set.
*/
for (Scope *scx = sc; 1; scx = scx->enclosing)
{
if (!scx)
{ error(loc, "forward reference to '%s'", t->toChars());
return;
}
if (scx->scopesym == scopesym)
{
t = t->semantic(loc, scx);
break;
}
}
}
}
}
if (t->ty == Ttuple)
*pt = t;
else
*pt = t->merge();
}
if (!s)
{
const char *p = toChars();
const char *n = importHint(p);
if (n)
error(loc, "'%s' is not defined, perhaps you need to import %s; ?", p, n);
else
{
Identifier *id = new Identifier(p, TOKidentifier);
s = sc->search_correct(id);
if (s)
error(loc, "undefined identifier %s, did you mean %s %s?", p, s->kind(), s->toChars());
else
error(loc, "undefined identifier %s", p);
}
*pt = Type::terror;
}
}
/***************************** TypeIdentifier *****************************/
TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
: TypeQualified(Tident, loc)
{
this->ident = ident;
}
Type *TypeIdentifier::syntaxCopy()
{
TypeIdentifier *t;
t = new TypeIdentifier(loc, ident);
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag)
{ unsigned len;
char *name;
Type::toDecoBuffer(buf, flag);
name = ident->toChars();
len = strlen(name);
buf->printf("%d%s", len, name);
}
void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(this->ident->toChars());
toCBuffer2Helper(buf, hgs);
}
/*************************************
* Takes an array of Identifiers and figures out if
* it represents a Type or an Expression.
* Output:
* if expression, *pe is set
* if type, *pt is set
*/
void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
Dsymbol *scopesym;
//printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
if ((ident->equals(Id::super) || ident->equals(Id::This)) && !hasThis(sc))
{
AggregateDeclaration *ad = sc->getStructClassScope();
if (ad)
{
ClassDeclaration *cd = ad->isClassDeclaration();
if (cd)
{
if (ident->equals(Id::This))
ident = cd->ident;
else if (cd->baseClass && ident->equals(Id::super))
ident = cd->baseClass->ident;
}
else
{
StructDeclaration *sd = ad->isStructDeclaration();
if (sd && ident->equals(Id::This))
ident = sd->ident;
}
}
}
Dsymbol *s = sc->search(loc, ident, &scopesym);
resolveHelper(loc, sc, s, scopesym, pe, pt, ps);
if (*pt)
(*pt) = (*pt)->addMod(mod);
}
/*****************************************
* See if type resolves to a symbol, if so,
* return that symbol.
*/
Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
{
//printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
if (!sc)
return NULL;
//printf("ident = '%s'\n", ident->toChars());
Dsymbol *scopesym;
Dsymbol *s = sc->search(loc, ident, &scopesym);
if (s)
{
for (size_t i = 0; i < idents.dim; i++)
{
Identifier *id = idents.tdata()[i];
s = s->searchX(loc, sc, id);
if (!s) // failed to find a symbol
{ //printf("\tdidn't find a symbol\n");
break;
}
}
}
return s;
}
Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeIdentifier::semantic(%s)\n", toChars());
resolve(loc, sc, &e, &t, &s);
if (t)
{
//printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
if (t->ty == Ttypedef)
{ TypeTypedef *tt = (TypeTypedef *)t;
if (tt->sym->sem == 1)
error(loc, "circular reference of typedef %s", tt->toChars());
}
t = t->addMod(mod);
}
else
{
if (s)
{
s->error(loc, "is used as a type");
//halt();
}
else
error(loc, "%s is used as a type", toChars());
t = terror;
}
//t->print();
return t;
}
Type *TypeIdentifier::reliesOnTident(TemplateParameters *tparams)
{
if (tparams)
{
if (idents.dim == 0)
{
for (size_t i = 0; i < tparams->dim; i++)
{ TemplateParameter *tp = tparams->tdata()[i];
if (tp->ident->equals(ident))
return this;
}
}
return NULL;
}
else
return this;
}
Expression *TypeIdentifier::toExpression()
{
Expression *e = new IdentifierExp(loc, ident);
for (size_t i = 0; i < idents.dim; i++)
{
Identifier *id = idents.tdata()[i];
e = new DotIdExp(loc, e, id);
}
return e;
}
/***************************** TypeInstance *****************************/
TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
: TypeQualified(Tinstance, loc)
{
this->tempinst = tempinst;
}
Type *TypeInstance::syntaxCopy()
{
//printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
TypeInstance *t;
t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
tempinst->toCBuffer(buf, hgs);
toCBuffer2Helper(buf, hgs);
}
void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
// Note close similarity to TypeIdentifier::resolve()
Dsymbol *s;
*pe = NULL;
*pt = NULL;
*ps = NULL;
#if 0
if (!idents.dim)
{
error(loc, "template instance '%s' has no identifier", toChars());
return;
}
#endif
//id = (Identifier *)idents.data[0];
//printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars());
s = tempinst;
if (s)
{ //printf("s = %s\n", s->toChars());
s->semantic(sc);
}
resolveHelper(loc, sc, s, NULL, pe, pt, ps);
if (*pt)
*pt = (*pt)->addMod(mod);
//printf("pt = '%s'\n", (*pt)->toChars());
}
Type *TypeInstance::semantic(Loc loc, Scope *sc)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
if (sc->parameterSpecialization)
{
unsigned errors = global.startGagging();
resolve(loc, sc, &e, &t, &s);
if (global.endGagging(errors))
{
return this;
}
}
else
resolve(loc, sc, &e, &t, &s);
if (!t)
{
error(loc, "%s is used as a type", toChars());
t = terror;
}
return t;
}
Dsymbol *TypeInstance::toDsymbol(Scope *sc)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeInstance::semantic(%s)\n", toChars());
if (sc->parameterSpecialization)
{
unsigned errors = global.startGagging();
resolve(loc, sc, &e, &t, &s);
if (global.endGagging(errors))
return NULL;
}
else
resolve(loc, sc, &e, &t, &s);
return s;
}
/***************************** TypeTypeof *****************************/
TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
: TypeQualified(Ttypeof, loc)
{
this->exp = exp;
inuse = 0;
}
Type *TypeTypeof::syntaxCopy()
{
//printf("TypeTypeof::syntaxCopy() %s\n", toChars());
TypeTypeof *t;
t = new TypeTypeof(loc, exp->syntaxCopy());
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
{
Type *t;
t = semantic(loc, sc);
if (t == this)
return NULL;
return t->toDsymbol(sc);
}
void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring("typeof(");
exp->toCBuffer(buf, hgs);
buf->writeByte(')');
toCBuffer2Helper(buf, hgs);
}
Type *TypeTypeof::semantic(Loc loc, Scope *sc)
{
Type *t;
//printf("TypeTypeof::semantic() %s\n", toChars());
//static int nest; if (++nest == 50) *(char*)0=0;
if (inuse)
{
inuse = 2;
error(loc, "circular typeof definition");
return Type::terror;
}
inuse++;
#if 0
/* Special case for typeof(this) and typeof(super) since both
* should work even if they are not inside a non-static member function
*/
if (exp->op == TOKthis || exp->op == TOKsuper)
{
// Find enclosing struct or class
for (Dsymbol *s = sc->parent; 1; s = s->parent)
{
ClassDeclaration *cd;
StructDeclaration *sd;
if (!s)
{
error(loc, "%s is not in a struct or class scope", exp->toChars());
goto Lerr;
}
cd = s->isClassDeclaration();
if (cd)
{
if (exp->op == TOKsuper)
{
cd = cd->baseClass;
if (!cd)
{ error(loc, "class %s has no 'super'", s->toChars());
goto Lerr;
}
}
t = cd->type;
break;
}
sd = s->isStructDeclaration();
if (sd)
{
if (exp->op == TOKsuper)
{
error(loc, "struct %s has no 'super'", sd->toChars());
goto Lerr;
}
t = sd->type->pointerTo();
break;
}
}
}
else
#endif
{
Scope *sc2 = sc->push();
sc2->intypeof++;
sc2->speculative = true;
sc2->flags |= sc->flags & SCOPEstaticif;
unsigned oldspecgag = global.speculativeGag;
if (global.gag)
global.speculativeGag = global.gag;
exp = exp->semantic(sc2);
global.speculativeGag = oldspecgag;
#if DMDV2
if (exp->type && exp->type->ty == Tfunction &&
((TypeFunction *)exp->type)->isproperty)
exp = resolveProperties(sc2, exp);
#endif
sc2->pop();
if (exp->op == TOKtype)
{
error(loc, "argument %s to typeof is not an expression", exp->toChars());
goto Lerr;
}
t = exp->type;
if (!t)
{
error(loc, "expression (%s) has no type", exp->toChars());
goto Lerr;
}
if (t->ty == Ttypeof)
{ error(loc, "forward reference to %s", toChars());
goto Lerr;
}
t = t->addMod(mod);
/* typeof should reflect the true type,
* not what 'auto' would have gotten us.
*/
//t = t->toHeadMutable();
}
if (idents.dim)
{
Dsymbol *s = t->toDsymbol(sc);
for (size_t i = 0; i < idents.dim; i++)
{
if (!s)
break;
Identifier *id = idents.tdata()[i];
s = s->searchX(loc, sc, id);
}
if (s)
{
t = s->getType();
if (!t)
{ error(loc, "%s is not a type", s->toChars());
goto Lerr;
}
}
else
{ error(loc, "cannot resolve .property for %s", toChars());
goto Lerr;
}
}
inuse--;
return t;
Lerr:
inuse--;
return terror;
}
d_uns64 TypeTypeof::size(Loc loc)
{
if (exp->type)
return exp->type->size(loc);
else
return TypeQualified::size(loc);
}
/***************************** TypeReturn *****************************/
TypeReturn::TypeReturn(Loc loc)
: TypeQualified(Treturn, loc)
{
}
Type *TypeReturn::syntaxCopy()
{
TypeReturn *t = new TypeReturn(loc);
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
Dsymbol *TypeReturn::toDsymbol(Scope *sc)
{
Type *t = semantic(0, sc);
if (t == this)
return NULL;
return t->toDsymbol(sc);
}
Type *TypeReturn::semantic(Loc loc, Scope *sc)
{
Type *t;
if (!sc->func)
{ error(loc, "typeof(return) must be inside function");
goto Lerr;
}
t = sc->func->type->nextOf();
if (!t)
{
error(loc, "cannot use typeof(return) inside function %s with inferred return type", sc->func->toChars());
goto Lerr;
}
t = t->addMod(mod);
if (idents.dim)
{
Dsymbol *s = t->toDsymbol(sc);
for (size_t i = 0; i < idents.dim; i++)
{
if (!s)
break;
Identifier *id = idents.tdata()[i];
s = s->searchX(loc, sc, id);
}
if (s)
{
t = s->getType();
if (!t)
{ error(loc, "%s is not a type", s->toChars());
goto Lerr;
}
}
else
{ error(loc, "cannot resolve .property for %s", toChars());
goto Lerr;
}
}
return t;
Lerr:
return terror;
}
void TypeReturn::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring("typeof(return)");
toCBuffer2Helper(buf, hgs);
}
/***************************** TypeEnum *****************************/
TypeEnum::TypeEnum(EnumDeclaration *sym)
: Type(Tenum)
{
this->sym = sym;
}
char *TypeEnum::toChars()
{
if (mod)
return Type::toChars();
return sym->toChars();
}
Type *TypeEnum::syntaxCopy()
{
return this;
}
Type *TypeEnum::semantic(Loc loc, Scope *sc)
{
//printf("TypeEnum::semantic() %s\n", toChars());
//sym->semantic(sc);
return merge();
}
d_uns64 TypeEnum::size(Loc loc)
{
if (!sym->memtype)
{
error(loc, "enum %s is forward referenced", sym->toChars());
return 4;
}
return sym->memtype->size(loc);
}
unsigned TypeEnum::alignsize()
{
if (!sym->memtype)
{
error(0, "enum %s is forward referenced", sym->toChars());
return 4;
}
return sym->memtype->alignsize();
}
Dsymbol *TypeEnum::toDsymbol(Scope *sc)
{
return sym;
}
Type *TypeEnum::toBasetype()
{
if (sym->scope)
{ // Enum is forward referenced. We don't need to resolve the whole thing,
// just the base type
if (sym->memtype)
{ sym->memtype = sym->memtype->semantic(sym->loc, sym->scope);
}
else
{ if (!sym->isAnonymous())
sym->memtype = Type::tint32;
}
}
if (!sym->memtype)
{
error(sym->loc, "enum %s is forward referenced", sym->toChars());
return tint32;
}
return sym->memtype->toBasetype();
}
void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag)
{
const char *name = sym->mangle();
Type::toDecoBuffer(buf, flag);
buf->printf("%s", name);
}
void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(sym->toChars());
}
Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
#endif
Dsymbol *s = sym->search(e->loc, ident, 0);
if (!s)
{
if (ident == Id::max ||
ident == Id::min ||
ident == Id::init ||
ident == Id::mangleof ||
!sym->memtype
)
{
return getProperty(e->loc, ident);
}
return sym->memtype->dotExp(sc, e, ident);
}
EnumMember *m = s->isEnumMember();
Expression *em = m->value->copy();
em->loc = e->loc;
return em;
}
Expression *TypeEnum::getProperty(Loc loc, Identifier *ident)
{ Expression *e;
if (ident == Id::max)
{
if (!sym->maxval)
goto Lfwd;
e = sym->maxval;
}
else if (ident == Id::min)
{
if (!sym->minval)
goto Lfwd;
e = sym->minval;
}
else if (ident == Id::init)
{
e = defaultInitLiteral(loc);
}
else if (ident == Id::stringof)
{ char *s = toChars();
e = new StringExp(loc, s, strlen(s), 'c');
Scope sc;
e = e->semantic(&sc);
}
else if (ident == Id::mangleof)
{
e = Type::getProperty(loc, ident);
}
else
{
e = toBasetype()->getProperty(loc, ident);
}
return e;
Lfwd:
error(loc, "forward reference of %s.%s", toChars(), ident->toChars());
return new ErrorExp();
}
int TypeEnum::isintegral()
{
return sym->memtype->isintegral();
}
int TypeEnum::isfloating()
{
return sym->memtype->isfloating();
}
int TypeEnum::isreal()
{
return sym->memtype->isreal();
}
int TypeEnum::isimaginary()
{
return sym->memtype->isimaginary();
}
int TypeEnum::iscomplex()
{
return sym->memtype->iscomplex();
}
int TypeEnum::isunsigned()
{
return sym->memtype->isunsigned();
}
int TypeEnum::isscalar()
{
return sym->memtype->isscalar();
}
int TypeEnum::isAssignable()
{
return sym->memtype->isAssignable();
}
int TypeEnum::checkBoolean()
{
return sym->memtype->checkBoolean();
}
int TypeEnum::needsDestruction()
{
return sym->memtype->needsDestruction();
}
MATCH TypeEnum::implicitConvTo(Type *to)
{ MATCH m;
//printf("TypeEnum::implicitConvTo()\n");
if (ty == to->ty && sym == ((TypeEnum *)to)->sym)
m = (mod == to->mod) ? MATCHexact : MATCHconst;
else if (sym->memtype->implicitConvTo(to))
m = MATCHconvert; // match with conversions
else
m = MATCHnomatch; // no match
return m;
}
MATCH TypeEnum::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeEnum *)to)->sym &&
MODimplicitConv(mod, to->mod))
return MATCHconst;
return MATCHnomatch;
}
Expression *TypeEnum::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeEnum::defaultInit() '%s'\n", toChars());
#endif
// Initialize to first member of enum
//printf("%s\n", sym->defaultval->type->toChars());
if (!sym->defaultval)
{
error(loc, "forward reference of %s.init", toChars());
return new ErrorExp();
}
return sym->defaultval;
}
int TypeEnum::isZeroInit(Loc loc)
{
if (!sym->defaultval && sym->scope)
{ // Enum is forward referenced. We need to resolve the whole thing.
sym->semantic(NULL);
}
if (!sym->defaultval)
{
error(loc, "enum %s is forward referenced", sym->toChars());
return 0;
}
return sym->defaultval->isBool(FALSE);
}
int TypeEnum::hasPointers()
{
return toBasetype()->hasPointers();
}
/***************************** TypeTypedef *****************************/
TypeTypedef::TypeTypedef(TypedefDeclaration *sym)
: Type(Ttypedef)
{
this->sym = sym;
}
Type *TypeTypedef::syntaxCopy()
{
return this;
}
char *TypeTypedef::toChars()
{
return Type::toChars();
}
Type *TypeTypedef::semantic(Loc loc, Scope *sc)
{
//printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem);
int errors = global.errors;
sym->semantic(sc);
if (errors != global.errors)
return terror;
return merge();
}
d_uns64 TypeTypedef::size(Loc loc)
{
return sym->basetype->size(loc);
}
unsigned TypeTypedef::alignsize()
{
return sym->basetype->alignsize();
}
Dsymbol *TypeTypedef::toDsymbol(Scope *sc)
{
return sym;
}
void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
const char *name = sym->mangle();
buf->printf("%s", name);
}
void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars());
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(sym->toChars());
}
Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
#endif
if (ident == Id::init)
{
return Type::dotExp(sc, e, ident);
}
return sym->basetype->dotExp(sc, e, ident);
}
Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeTypedef::getProperty(ident = '%s') '%s'\n", ident->toChars(), toChars());
#endif
if (ident == Id::init)
{
return Type::getProperty(loc, ident);
}
return sym->basetype->getProperty(loc, ident);
}
int TypeTypedef::isintegral()
{
//printf("TypeTypedef::isintegral()\n");
//printf("sym = '%s'\n", sym->toChars());
//printf("basetype = '%s'\n", sym->basetype->toChars());
return sym->basetype->isintegral();
}
int TypeTypedef::isfloating()
{
return sym->basetype->isfloating();
}
int TypeTypedef::isreal()
{
return sym->basetype->isreal();
}
int TypeTypedef::isimaginary()
{
return sym->basetype->isimaginary();
}
int TypeTypedef::iscomplex()
{
return sym->basetype->iscomplex();
}
int TypeTypedef::isunsigned()
{
return sym->basetype->isunsigned();
}
int TypeTypedef::isscalar()
{
return sym->basetype->isscalar();
}
int TypeTypedef::isAssignable()
{
return sym->basetype->isAssignable();
}
int TypeTypedef::checkBoolean()
{
return sym->basetype->checkBoolean();
}
int TypeTypedef::needsDestruction()
{
return sym->basetype->needsDestruction();
}
Type *TypeTypedef::toBasetype()
{
if (sym->inuse)
{
sym->error("circular definition");
sym->basetype = Type::terror;
return Type::terror;
}
sym->inuse = 1;
Type *t = sym->basetype->toBasetype();
sym->inuse = 0;
t = t->addMod(mod);
return t;
}
MATCH TypeTypedef::implicitConvTo(Type *to)
{ MATCH m;
//printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
if (equals(to))
m = MATCHexact; // exact match
else if (sym->basetype->implicitConvTo(to))
m = MATCHconvert; // match with conversions
else if (ty == to->ty && sym == ((TypeTypedef *)to)->sym)
{
m = constConv(to);
}
else
m = MATCHnomatch; // no match
return m;
}
MATCH TypeTypedef::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeTypedef *)to)->sym)
return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype);
return MATCHnomatch;
}
Type *TypeTypedef::toHeadMutable()
{
if (!mod)
return this;
Type *tb = toBasetype();
Type *t = tb->toHeadMutable();
if (t->equals(tb))
return this;
else
return mutableOf();
}
Expression *TypeTypedef::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeTypedef::defaultInit() '%s'\n", toChars());
#endif
if (sym->init)
{
//sym->init->toExpression()->print();
return sym->init->toExpression();
}
Type *bt = sym->basetype;
Expression *e = bt->defaultInit(loc);
e->type = this;
while (bt->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)bt;
e->type = tsa->next;
bt = tsa->next->toBasetype();
}
return e;
}
Expression *TypeTypedef::defaultInitLiteral(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeTypedef::defaultInitLiteral() '%s'\n", toChars());
#endif
if (sym->init)
{
//sym->init->toExpression()->print();
return sym->init->toExpression();
}
Type *bt = sym->basetype;
Expression *e = bt->defaultInitLiteral(loc);
e->type = this;
return e;
}
int TypeTypedef::isZeroInit(Loc loc)
{
if (sym->init)
{
if (sym->init->isVoidInitializer())
return 1; // initialize voids to 0
Expression *e = sym->init->toExpression();
if (e && e->isBool(FALSE))
return 1;
return 0; // assume not
}
if (sym->inuse)
{
sym->error("circular definition");
sym->basetype = Type::terror;
}
sym->inuse = 1;
int result = sym->basetype->isZeroInit(loc);
sym->inuse = 0;
return result;
}
int TypeTypedef::hasPointers()
{
return toBasetype()->hasPointers();
}
int TypeTypedef::hasWild()
{
assert(toBasetype());
return mod & MODwild || toBasetype()->hasWild();
}
/***************************** TypeStruct *****************************/
TypeStruct::TypeStruct(StructDeclaration *sym)
: Type(Tstruct)
{
this->sym = sym;
}
char *TypeStruct::toChars()
{
//printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco);
if (mod)
return Type::toChars();
TemplateInstance *ti = sym->parent->isTemplateInstance();
if (ti && ti->toAlias() == sym)
{
return ti->toChars();
}
return sym->toChars();
}
Type *TypeStruct::syntaxCopy()
{
return this;
}
Type *TypeStruct::semantic(Loc loc, Scope *sc)
{
//printf("TypeStruct::semantic('%s')\n", sym->toChars());
/* Cannot do semantic for sym because scope chain may not
* be right.
*/
//sym->semantic(sc);
return merge();
}
d_uns64 TypeStruct::size(Loc loc)
{
return sym->size(loc);
}
unsigned TypeStruct::alignsize()
{ unsigned sz;
sym->size(0); // give error for forward references
sz = sym->alignsize;
if (sz > sym->structalign)
sz = sym->structalign;
return sz;
}
Dsymbol *TypeStruct::toDsymbol(Scope *sc)
{
return sym;
}
void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag)
{
const char *name = sym->mangle();
//printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name);
Type::toDecoBuffer(buf, flag);
buf->printf("%s", name);
}
void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
TemplateInstance *ti = sym->parent->isTemplateInstance();
if (ti && ti->toAlias() == sym)
buf->writestring(ti->toChars());
else
buf->writestring(sym->toChars());
}
Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
VarDeclaration *v;
Dsymbol *s;
DotVarExp *de;
Declaration *d;
#if LOGDOTEXP
printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (!sym->members)
{
error(e->loc, "struct %s is forward referenced", sym->toChars());
return new ErrorExp();
}
/* If e.tupleof
*/
if (ident == Id::tupleof)
{
/* Create a TupleExp out of the fields of the struct e:
* (e.field0, e.field1, e.field2, ...)
*/
e = e->semantic(sc); // do this before turning on noaccesscheck
e->type->size(); // do semantic of type
Expressions *exps = new Expressions;
exps->reserve(sym->fields.dim);
Expression *ev = e;
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = sym->fields.tdata()[i];
Expression *fe;
if (i == 0 && sc->func && sym->fields.dim > 1 &&
e->hasSideEffect())
{
Identifier *id = Lexer::uniqueId("__tup");
ExpInitializer *ei = new ExpInitializer(e->loc, e);
VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei);
vd->storage_class |= STCctfe | STCref | STCforeach;
ev = new VarExp(e->loc, vd);
fe = new CommaExp(e->loc, new DeclarationExp(e->loc, vd), ev);
fe = new DotVarExp(e->loc, fe, v);
}
else
fe = new DotVarExp(ev->loc, ev, v);
exps->push(fe);
}
e = new TupleExp(e->loc, exps);
sc = sc->push();
sc->noaccesscheck = 1;
e = e->semantic(sc);
sc->pop();
return e;
}
if (e->op == TOKdotexp)
{ DotExp *de = (DotExp *)e;
if (de->e1->op == TOKimport)
{
assert(0); // cannot find a case where this happens; leave
// assert in until we do
ScopeExp *se = (ScopeExp *)de->e1;
s = se->sds->search(e->loc, ident, 0);
e = de->e1;
goto L1;
}
}
s = sym->search(e->loc, ident, 0);
L1:
if (!s)
{
return noMember(sc, e, ident);
}
if (!s->isFuncDeclaration()) // because of overloading
s->checkDeprecated(e->loc, sc);
s = s->toAlias();
v = s->isVarDeclaration();
if (v && !v->isDataseg())
{
Expression *ei = v->getConstInitializer();
if (ei)
{ e = ei->copy(); // need to copy it if it's a StringExp
e = e->semantic(sc);
return e;
}
}
if (s->getType())
{
//return new DotTypeExp(e->loc, e, s);
return new TypeExp(e->loc, s->getType());
}
EnumMember *em = s->isEnumMember();
if (em)
{
assert(em->value);
return em->value->copy();
}
TemplateMixin *tm = s->isTemplateMixin();
if (tm)
{
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
de->type = e->type;
return de;
}
TemplateDeclaration *td = s->isTemplateDeclaration();
if (td)
{
e = new DotTemplateExp(e->loc, e, td);
e = e->semantic(sc);
return e;
}
TemplateInstance *ti = s->isTemplateInstance();
if (ti)
{ if (!ti->semanticRun)
{
if (global.errors)
return new ErrorExp(); // TemplateInstance::semantic() will fail anyway
ti->semantic(sc);
}
s = ti->inst->toAlias();
if (!s->isTemplateInstance())
goto L1;
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
de->type = e->type;
return de;
}
if (s->isImport() || s->isModule() || s->isPackage())
{
e = new DsymbolExp(e->loc, s, 0);
e = e->semantic(sc);
return e;
}
OverloadSet *o = s->isOverloadSet();
if (o)
{
OverExp *oe = new OverExp(o);
if (e->op == TOKtype)
return oe;
return new DotExp(e->loc, e, oe);
}
d = s->isDeclaration();
#ifdef DEBUG
if (!d)
printf("d = %s '%s'\n", s->kind(), s->toChars());
#endif
assert(d);
if (e->op == TOKtype)
{ FuncDeclaration *fd = sc->func;
if (d->isTupleDeclaration())
{
e = new TupleExp(e->loc, d->isTupleDeclaration());
e = e->semantic(sc);
return e;
}
else if (d->needThis() && fd && fd->vthis)
{
e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
e = e->semantic(sc);
return e;
}
return new VarExp(e->loc, d, 1);
}
if (d->isDataseg())
{
// (e, d)
VarExp *ve;
accessCheck(e->loc, sc, e, d);
ve = new VarExp(e->loc, d);
e = new CommaExp(e->loc, e, ve);
e = e->semantic(sc);
return e;
}
if (v)
{
if (v->toParent() != sym)
sym->error(e->loc, "'%s' is not a member", v->toChars());
// *(&e + offset)
accessCheck(e->loc, sc, e, d);
#if 0
Expression *b = new AddrExp(e->loc, e);
b->type = e->type->pointerTo();
b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32));
b->type = v->type->pointerTo();
b = new PtrExp(e->loc, b);
b->type = v->type->addMod(e->type->mod);
return b;
#endif
}
de = new DotVarExp(e->loc, e, d);
return de->semantic(sc);
}
unsigned TypeStruct::memalign(unsigned salign)
{
sym->size(0); // give error for forward references
return sym->structalign;
}
Expression *TypeStruct::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeStruct::defaultInit() '%s'\n", toChars());
#endif
Symbol *s = sym->toInitializer();
Declaration *d = new SymbolDeclaration(sym->loc, s, sym);
assert(d);
d->type = this;
return new VarExp(sym->loc, d);
}
/***************************************
* Use when we prefer the default initializer to be a literal,
* rather than a global immutable variable.
*/
Expression *TypeStruct::defaultInitLiteral(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars());
#endif
if (sym->isNested())
return defaultInit(loc);
Expressions *structelems = new Expressions();
structelems->setDim(sym->fields.dim);
for (size_t j = 0; j < structelems->dim; j++)
{
VarDeclaration *vd = sym->fields.tdata()[j];
Expression *e;
if (vd->init)
{ if (vd->init->isVoidInitializer())
e = NULL;
else
e = vd->init->toExpression();
}
else
e = vd->type->defaultInitLiteral(loc);
(*structelems)[j] = e;
}
StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems);
/* Copy from the initializer symbol for larger symbols,
* otherwise the literals expressed as code get excessively large.
*/
if (size(loc) > PTRSIZE * 4)
structinit->sinit = sym->toInitializer();
// Why doesn't the StructLiteralExp constructor do this, when
// sym->type != NULL ?
structinit->type = sym->type;
return structinit;
}
int TypeStruct::isZeroInit(Loc loc)
{
return sym->zeroInit;
}
int TypeStruct::checkBoolean()
{
return FALSE;
}
int TypeStruct::needsDestruction()
{
return sym->dtor != NULL;
}
int TypeStruct::isAssignable()
{
int assignable = TRUE;
unsigned offset;
/* If any of the fields are const or invariant,
* then one cannot assign this struct.
*/
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = sym->fields.tdata()[i];
//printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind());
if (i == 0)
;
else if (v->offset == offset)
{
/* If any fields of anonymous union are assignable,
* then regard union as assignable.
* This is to support unsafe things like Rebindable templates.
*/
if (assignable)
continue;
}
else
{
if (!assignable)
return FALSE;
}
assignable = v->type->isMutable() && v->type->isAssignable();
offset = v->offset;
//printf(" -> assignable = %d\n", assignable);
}
return assignable;
}
int TypeStruct::hasPointers()
{
// Probably should cache this information in sym rather than recompute
StructDeclaration *s = sym;
sym->size(0); // give error for forward references
for (size_t i = 0; i < s->fields.dim; i++)
{
Dsymbol *sm = s->fields.tdata()[i];
Declaration *d = sm->isDeclaration();
if (d->storage_class & STCref || d->hasPointers())
return TRUE;
}
return FALSE;
}
MATCH TypeStruct::implicitConvTo(Type *to)
{ MATCH m;
//printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars());
if (to->ty == Taarray && sym->ident == Id::AssociativeArray)
{
/* If there is an error instantiating AssociativeArray!(), it shouldn't
* be reported -- it just means implicit conversion is impossible.
*/
int errs = global.startGagging();
to = ((TypeAArray*)to)->getImpl()->type;
if (global.endGagging(errs))
{
return MATCHnomatch;
}
}
if (ty == to->ty && sym == ((TypeStruct *)to)->sym)
{ m = MATCHexact; // exact match
if (mod != to->mod)
{
if (MODimplicitConv(mod, to->mod))
m = MATCHconst;
else
{ /* Check all the fields. If they can all be converted,
* allow the conversion.
*/
for (size_t i = 0; i < sym->fields.dim; i++)
{ Dsymbol *s = sym->fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
// 'from' type
Type *tvf = v->type->addMod(mod);
// 'to' type
Type *tv = v->type->castMod(to->mod);
//printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv));
if (tvf->implicitConvTo(tv) < MATCHconst)
return MATCHnomatch;
}
m = MATCHconst;
}
}
}
else if (sym->aliasthis)
m = aliasthisOf()->implicitConvTo(to);
else
m = MATCHnomatch; // no match
return m;
}
MATCH TypeStruct::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeStruct *)to)->sym &&
MODimplicitConv(mod, to->mod))
return MATCHconst;
return MATCHnomatch;
}
unsigned TypeStruct::wildConvTo(Type *tprm)
{
if (ty == tprm->ty && sym == ((TypeStruct *)tprm)->sym)
return Type::wildConvTo(tprm);
if (sym->aliasthis)
{ Type *t = aliasthisOf();
assert(t);
return t->wildConvTo(tprm);
}
return 0;
}
Type *TypeStruct::toHeadMutable()
{
return this;
}
/***************************** TypeClass *****************************/
TypeClass::TypeClass(ClassDeclaration *sym)
: Type(Tclass)
{
this->sym = sym;
}
char *TypeClass::toChars()
{
if (mod)
return Type::toChars();
return (char *)sym->toPrettyChars();
}
Type *TypeClass::syntaxCopy()
{
return this;
}
Type *TypeClass::semantic(Loc loc, Scope *sc)
{
//printf("TypeClass::semantic(%s)\n", sym->toChars());
if (deco)
return this;
//printf("\t%s\n", merge()->deco);
return merge();
}
d_uns64 TypeClass::size(Loc loc)
{
return PTRSIZE;
}
Dsymbol *TypeClass::toDsymbol(Scope *sc)
{
return sym;
}
void TypeClass::toDecoBuffer(OutBuffer *buf, int flag)
{
const char *name = sym->mangle();
//printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name);
Type::toDecoBuffer(buf, flag);
buf->printf("%s", name);
}
void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(sym->toChars());
}
Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
VarDeclaration *v;
Dsymbol *s;
#if LOGDOTEXP
printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars());
#endif
if (e->op == TOKdotexp)
{ DotExp *de = (DotExp *)e;
if (de->e1->op == TOKimport)
{
ScopeExp *se = (ScopeExp *)de->e1;
s = se->sds->search(e->loc, ident, 0);
e = de->e1;
goto L1;
}
}
if (ident == Id::tupleof)
{
/* Create a TupleExp
*/
e = e->semantic(sc); // do this before turning on noaccesscheck
/* If this is called in the middle of a class declaration,
* class Inner {
* int x;
* alias typeof(Inner.tupleof) T;
* int y;
* }
* then Inner.y will be omitted from the tuple.
*/
// Detect that error, and at least try to run semantic() on it if we can
sym->size(e->loc);
Expressions *exps = new Expressions;
exps->reserve(sym->fields.dim);
Expression *ev = e;
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = sym->fields.tdata()[i];
// Don't include hidden 'this' pointer
if (v->isThisDeclaration())
continue;
Expression *fe;
if (i == 0 && sc->func && sym->fields.dim > 1 &&
e->hasSideEffect())
{
Identifier *id = Lexer::uniqueId("__tup");
ExpInitializer *ei = new ExpInitializer(e->loc, e);
VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei);
vd->storage_class |= STCctfe | STCref | STCforeach;
ev = new VarExp(e->loc, vd);
fe = new CommaExp(e->loc, new DeclarationExp(e->loc, vd), ev);
fe = new DotVarExp(e->loc, fe, v);
}
else
fe = new DotVarExp(e->loc, ev, v);
exps->push(fe);
}
e = new TupleExp(e->loc, exps);
sc = sc->push();
sc->noaccesscheck = 1;
e = e->semantic(sc);
sc->pop();
return e;
}
s = sym->search(e->loc, ident, 0);
L1:
if (!s)
{
// See if it's a base class
if (Dsymbol *cbase = sym->searchBase(e->loc, ident))
{
e = new DotTypeExp(0, e, cbase);
return e;
}
if (ident == Id::classinfo)
{
assert(ClassDeclaration::classinfo);
Type *t = ClassDeclaration::classinfo->type;
if (e->op == TOKtype || e->op == TOKdottype)
{
/* For type.classinfo, we know the classinfo
* at compile time.
*/
if (!sym->vclassinfo)
sym->vclassinfo = new TypeInfoClassDeclaration(sym->type);
e = new VarExp(e->loc, sym->vclassinfo);
e = e->addressOf(sc);
e->type = t; // do this so we don't get redundant dereference
}
else
{ /* For class objects, the classinfo reference is the first
* entry in the vtbl[]
*/
e = new PtrExp(e->loc, e);
e->type = t->pointerTo();
if (sym->isInterfaceDeclaration())
{
if (sym->isCPPinterface())
{ /* C++ interface vtbl[]s are different in that the
* first entry is always pointer to the first virtual
* function, not classinfo.
* We can't get a .classinfo for it.
*/
error(e->loc, "no .classinfo for C++ interface objects");
}
/* For an interface, the first entry in the vtbl[]
* is actually a pointer to an instance of struct Interface.
* The first member of Interface is the .classinfo,
* so add an extra pointer indirection.
*/
e->type = e->type->pointerTo();
e = new PtrExp(e->loc, e);
e->type = t->pointerTo();
}
e = new PtrExp(e->loc, e, t);
}
return e;
}
if (ident == Id::__vptr)
{ /* The pointer to the vtbl[]
* *cast(invariant(void*)**)e
*/
e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo());
e = new PtrExp(e->loc, e);
e = e->semantic(sc);
return e;
}
if (ident == Id::__monitor)
{ /* The handle to the monitor (call it a void*)
* *(cast(void**)e + 1)
*/
e = e->castTo(sc, tvoidptr->pointerTo());
e = new AddExp(e->loc, e, new IntegerExp(1));
e = new PtrExp(e->loc, e);
e = e->semantic(sc);
return e;
}
if (ident == Id::typeinfo)
{
if (!global.params.useDeprecated)
error(e->loc, ".typeinfo deprecated, use typeid(type)");
return getTypeInfo(sc);
}
if (ident == Id::outer && sym->vthis)
{
s = sym->vthis;
}
else
{
return noMember(sc, e, ident);
}
}
if (!s->isFuncDeclaration()) // because of overloading
s->checkDeprecated(e->loc, sc);
s = s->toAlias();
v = s->isVarDeclaration();
if (v && !v->isDataseg())
{ Expression *ei = v->getConstInitializer();
if (ei)
{ e = ei->copy(); // need to copy it if it's a StringExp
e = e->semantic(sc);
return e;
}
}
if (s->getType())
{
// if (e->op == TOKtype)
return new TypeExp(e->loc, s->getType());
// return new DotTypeExp(e->loc, e, s);
}
EnumMember *em = s->isEnumMember();
if (em)
{
assert(em->value);
return em->value->copy();
}
TemplateMixin *tm = s->isTemplateMixin();
if (tm)
{
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
de->type = e->type;
return de;
}
TemplateDeclaration *td = s->isTemplateDeclaration();
if (td)
{
e = new DotTemplateExp(e->loc, e, td);
e = e->semantic(sc);
return e;
}
TemplateInstance *ti = s->isTemplateInstance();
if (ti)
{ if (!ti->semanticRun)
{
if (global.errors)
return new ErrorExp(); // TemplateInstance::semantic() will fail anyway
ti->semantic(sc);
}
s = ti->inst->toAlias();
if (!s->isTemplateInstance())
goto L1;
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
de->type = e->type;
return de;
}
#if 0 // shouldn't this be here?
if (s->isImport() || s->isModule() || s->isPackage())
{
e = new DsymbolExp(e->loc, s, 0);
e = e->semantic(sc);
return e;
}
#endif
OverloadSet *o = s->isOverloadSet();
if (o)
{
OverExp *oe = new OverExp(o);
if (e->op == TOKtype)
return oe;
return new DotExp(e->loc, e, oe);
}
Declaration *d = s->isDeclaration();
if (!d)
{
e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
return new ErrorExp();
}
if (e->op == TOKtype)
{
/* It's:
* Class.d
*/
if (d->isTupleDeclaration())
{
e = new TupleExp(e->loc, d->isTupleDeclaration());
e = e->semantic(sc);
return e;
}
else if (d->needThis() && (hasThis(sc) || !(sc->intypeof || d->isFuncDeclaration())))
{
if (sc->func)
{
ClassDeclaration *thiscd;
thiscd = sc->func->toParent()->isClassDeclaration();
if (thiscd)
{
ClassDeclaration *cd = e->type->isClassHandle();
if (cd == thiscd)
{
e = new ThisExp(e->loc);
e = new DotTypeExp(e->loc, e, cd);
DotVarExp *de = new DotVarExp(e->loc, e, d);
e = de->semantic(sc);
return e;
}
else if ((!cd || !cd->isBaseOf(thiscd, NULL)) &&
!d->isFuncDeclaration())
e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars());
}
}
/* Rewrite as:
* this.d
*/
DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d);
e = de->semantic(sc);
return e;
}
else
{
VarExp *ve = new VarExp(e->loc, d, 1);
return ve;
}
}
if (d->isDataseg())
{
// (e, d)
VarExp *ve;
accessCheck(e->loc, sc, e, d);
ve = new VarExp(e->loc, d);
e = new CommaExp(e->loc, e, ve);
e = e->semantic(sc);
return e;
}
if (d->parent && d->toParent()->isModule())
{
// (e, d)
VarExp *ve = new VarExp(e->loc, d, 1);
e = new CommaExp(e->loc, e, ve);
e->type = d->type;
return e;
}
DotVarExp *de = new DotVarExp(e->loc, e, d, d->hasOverloads());
return de->semantic(sc);
}
ClassDeclaration *TypeClass::isClassHandle()
{
return sym;
}
int TypeClass::isscope()
{
return sym->isscope;
}
int TypeClass::isBaseOf(Type *t, int *poffset)
{
if (t->ty == Tclass)
{ ClassDeclaration *cd;
cd = ((TypeClass *)t)->sym;
if (sym->isBaseOf(cd, poffset))
return 1;
}
return 0;
}
MATCH TypeClass::implicitConvTo(Type *to)
{
//printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars());
MATCH m = constConv(to);
if (m != MATCHnomatch)
return m;
ClassDeclaration *cdto = to->isClassHandle();
if (cdto)
{
if (cdto->scope)
cdto->semantic(NULL);
if (cdto->isBaseOf(sym, NULL))
{ //printf("'to' is base\n");
return MATCHconvert;
}
}
if (global.params.Dversion == 1)
{
// Allow conversion to (void *)
if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid)
return MATCHconvert;
}
m = MATCHnomatch;
if (sym->aliasthis)
m = aliasthisOf()->implicitConvTo(to);
return m;
}
MATCH TypeClass::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeClass *)to)->sym &&
MODimplicitConv(mod, to->mod))
return MATCHconst;
/* Conversion derived to const(base)
*/
int offset = 0;
if (to->isBaseOf(this, &offset) && offset == 0 && !to->isMutable())
return MATCHconvert;
return MATCHnomatch;
}
unsigned TypeClass::wildConvTo(Type *tprm)
{
Type *tcprm = tprm->substWildTo(MODconst);
if (constConv(tcprm))
return Type::wildConvTo(tprm);
ClassDeclaration *cdprm = tcprm->isClassHandle();
if (cdprm && cdprm->isBaseOf(sym, NULL))
return Type::wildConvTo(tprm);
if (sym->aliasthis)
return aliasthisOf()->wildConvTo(tprm);
return 0;
}
Type *TypeClass::toHeadMutable()
{
return this;
}
Expression *TypeClass::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeClass::defaultInit() '%s'\n", toChars());
#endif
return new NullExp(loc, this);
}
int TypeClass::isZeroInit(Loc loc)
{
return 1;
}
int TypeClass::checkBoolean()
{
return TRUE;
}
int TypeClass::hasPointers()
{
return TRUE;
}
/***************************** TypeTuple *****************************/
TypeTuple::TypeTuple(Parameters *arguments)
: Type(Ttuple)
{
//printf("TypeTuple(this = %p)\n", this);
this->arguments = arguments;
//printf("TypeTuple() %p, %s\n", this, toChars());
#ifdef DEBUG
if (arguments)
{
for (size_t i = 0; i < arguments->dim; i++)
{
Parameter *arg = arguments->tdata()[i];
assert(arg && arg->type);
}
}
#endif
}
/****************
* Form TypeTuple from the types of the expressions.
* Assume exps[] is already tuple expanded.
*/
TypeTuple::TypeTuple(Expressions *exps)
: Type(Ttuple)
{
Parameters *arguments = new Parameters;
if (exps)
{
arguments->setDim(exps->dim);
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = exps->tdata()[i];
if (e->type->ty == Ttuple)
e->error("cannot form tuple of tuples");
Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL);
arguments->tdata()[i] = arg;
}
}
this->arguments = arguments;
//printf("TypeTuple() %p, %s\n", this, toChars());
}
/*******************************************
* Type tuple with 0, 1 or 2 types in it.
*/
TypeTuple::TypeTuple()
: Type(Ttuple)
{
arguments = new Parameters();
}
TypeTuple::TypeTuple(Type *t1)
: Type(Ttuple)
{
arguments = new Parameters();
arguments->push(new Parameter(0, t1, NULL, NULL));
}
TypeTuple::TypeTuple(Type *t1, Type *t2)
: Type(Ttuple)
{
arguments = new Parameters();
arguments->push(new Parameter(0, t1, NULL, NULL));
arguments->push(new Parameter(0, t2, NULL, NULL));
}
Type *TypeTuple::syntaxCopy()
{
Parameters *args = Parameter::arraySyntaxCopy(arguments);
Type *t = new TypeTuple(args);
t->mod = mod;
return t;
}
Type *TypeTuple::semantic(Loc loc, Scope *sc)
{
//printf("TypeTuple::semantic(this = %p)\n", this);
//printf("TypeTuple::semantic() %p, %s\n", this, toChars());
if (!deco)
deco = merge()->deco;
/* Don't return merge(), because a tuple with one type has the
* same deco as that type.
*/
return this;
}
int TypeTuple::equals(Object *o)
{ Type *t;
t = (Type *)o;
//printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
if (this == t)
{
return 1;
}
if (t->ty == Ttuple)
{ TypeTuple *tt = (TypeTuple *)t;
if (arguments->dim == tt->arguments->dim)
{
for (size_t i = 0; i < tt->arguments->dim; i++)
{ Parameter *arg1 = arguments->tdata()[i];
Parameter *arg2 = tt->arguments->tdata()[i];
if (!arg1->type->equals(arg2->type))
return 0;
}
return 1;
}
}
return 0;
}
Type *TypeTuple::reliesOnTident(TemplateParameters *tparams)
{
if (arguments)
{
for (size_t i = 0; i < arguments->dim; i++)
{
Parameter *arg = arguments->tdata()[i];
Type *t = arg->type->reliesOnTident(tparams);
if (t)
return t;
}
}
return NULL;
}
#if 0
Type *TypeTuple::makeConst()
{
//printf("TypeTuple::makeConst() %s\n", toChars());
if (cto)
return cto;
TypeTuple *t = (TypeTuple *)Type::makeConst();
t->arguments = new Parameters();
t->arguments->setDim(arguments->dim);
for (size_t i = 0; i < arguments->dim; i++)
{ Parameter *arg = arguments->tdata()[i];
Parameter *narg = new Parameter(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg);
t->arguments->tdata()[i] = (Parameter *)narg;
}
return t;
}
#endif
void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
Parameter::argsToCBuffer(buf, hgs, arguments, 0);
}
void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag)
{
//printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars());
Type::toDecoBuffer(buf, flag);
OutBuffer buf2;
Parameter::argsToDecoBuffer(&buf2, arguments);
unsigned len = buf2.offset;
buf->printf("%d%.*s", len, len, (char *)buf2.extractData());
}
Expression *TypeTuple::getProperty(Loc loc, Identifier *ident)
{ Expression *e;
#if LOGDOTEXP
printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
e = new IntegerExp(loc, arguments->dim, Type::tsize_t);
}
else if (ident == Id::init)
{
e = defaultInitLiteral(loc);
}
else
{
error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
e = new ErrorExp();
}
return e;
}
Expression *TypeTuple::defaultInit(Loc loc)
{
Expressions *exps = new Expressions();
exps->setDim(arguments->dim);
for (size_t i = 0; i < arguments->dim; i++)
{
Parameter *p = (*arguments)[i];
assert(p->type);
Expression *e = p->type->defaultInitLiteral(loc);
if (e->op == TOKerror)
return e;
(*exps)[i] = e;
}
return new TupleExp(loc, exps);
}
/***************************** TypeSlice *****************************/
/* This is so we can slice a TypeTuple */
TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
: TypeNext(Tslice, next)
{
//printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
this->lwr = lwr;
this->upr = upr;
}
Type *TypeSlice::syntaxCopy()
{
Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
t->mod = mod;
return t;
}
Type *TypeSlice::semantic(Loc loc, Scope *sc)
{
//printf("TypeSlice::semantic() %s\n", toChars());
next = next->semantic(loc, sc);
transitive();
//printf("next: %s\n", next->toChars());
Type *tbn = next->toBasetype();
if (tbn->ty != Ttuple)
{ error(loc, "can only slice tuple types, not %s", tbn->toChars());
return Type::terror;
}
TypeTuple *tt = (TypeTuple *)tbn;
lwr = semanticLength(sc, tbn, lwr);
lwr = lwr->optimize(WANTvalue | WANTinterpret);
uinteger_t i1 = lwr->toUInteger();
upr = semanticLength(sc, tbn, upr);
upr = upr->optimize(WANTvalue | WANTinterpret);
uinteger_t i2 = upr->toUInteger();
if (!(i1 <= i2 && i2 <= tt->arguments->dim))
{ error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->dim);
return Type::terror;
}
Parameters *args = new Parameters;
args->reserve(i2 - i1);
for (size_t i = i1; i < i2; i++)
{ Parameter *arg = tt->arguments->tdata()[i];
args->push(arg);
}
Type *t = (new TypeTuple(args))->semantic(loc, sc);
return t;
}
void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
next->resolve(loc, sc, pe, pt, ps);
if (*pe)
{ // It's really a slice expression
Expression *e;
e = new SliceExp(loc, *pe, lwr, upr);
*pe = e;
}
else if (*ps)
{ Dsymbol *s = *ps;
TupleDeclaration *td = s->isTupleDeclaration();
if (td)
{
/* It's a slice of a TupleDeclaration
*/
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
sym->parent = sc->scopesym;
sc = sc->push(sym);
lwr = lwr->semantic(sc);
lwr = lwr->optimize(WANTvalue | WANTinterpret);
uinteger_t i1 = lwr->toUInteger();
upr = upr->semantic(sc);
upr = upr->optimize(WANTvalue | WANTinterpret);
uinteger_t i2 = upr->toUInteger();
sc = sc->pop();
if (!(i1 <= i2 && i2 <= td->objects->dim))
{ error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim);
goto Ldefault;
}
if (i1 == 0 && i2 == td->objects->dim)
{
*ps = td;
return;
}
/* Create a new TupleDeclaration which
* is a slice [i1..i2] out of the old one.
*/
Objects *objects = new Objects;
objects->setDim(i2 - i1);
for (size_t i = 0; i < objects->dim; i++)
{
objects->tdata()[i] = td->objects->tdata()[(size_t)i1 + i];
}
TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
*ps = tds;
}
else
goto Ldefault;
}
else
{
Ldefault:
Type::resolve(loc, sc, pe, pt, ps);
}
}
void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->printf("[%s .. ", lwr->toChars());
buf->printf("%s]", upr->toChars());
}
/***************************** TypeNull *****************************/
TypeNull::TypeNull()
: Type(Tnull)
{
}
Type *TypeNull::syntaxCopy()
{
// No semantic analysis done, no need to copy
return this;
}
MATCH TypeNull::implicitConvTo(Type *to)
{
//printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
//printf("from: %s\n", toChars());
//printf("to : %s\n", to->toChars());
MATCH m = Type::implicitConvTo(to);
if (m)
return m;
// NULL implicitly converts to any pointer type or dynamic array
//if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
{
Type *tb= to->toBasetype();
if (tb->ty == Tpointer || tb->ty == Tarray ||
tb->ty == Taarray || tb->ty == Tclass ||
tb->ty == Tdelegate)
return MATCHconst;
}
return MATCHnomatch;
}
void TypeNull::toDecoBuffer(OutBuffer *buf, int flag)
{
//tvoidptr->toDecoBuffer(buf, flag);
Type::toDecoBuffer(buf, flag);
}
void TypeNull::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
{
buf->writestring("typeof(null)");
}
d_uns64 TypeNull::size(Loc loc) { return tvoidptr->size(loc); }
//Expression *TypeNull::getProperty(Loc loc, Identifier *ident) { return new ErrorExp(); }
//Expression *TypeNull::dotExp(Scope *sc, Expression *e, Identifier *ident) { return new ErrorExp(); }
Expression *TypeNull::defaultInit(Loc loc) { return new NullExp(0, Type::tnull); }
//Expression *TypeNull::defaultInitLiteral(Loc loc) { return new ErrorExp(); }
/***************************** Parameter *****************************/
Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
{
this->type = type;
this->ident = ident;
this->storageClass = storageClass;
this->defaultArg = defaultArg;
}
Parameter *Parameter::syntaxCopy()
{
Parameter *a = new Parameter(storageClass,
type ? type->syntaxCopy() : NULL,
ident,
defaultArg ? defaultArg->syntaxCopy() : NULL);
return a;
}
Parameters *Parameter::arraySyntaxCopy(Parameters *args)
{ Parameters *a = NULL;
if (args)
{
a = new Parameters();
a->setDim(args->dim);
for (size_t i = 0; i < a->dim; i++)
{ Parameter *arg = args->tdata()[i];
arg = arg->syntaxCopy();
a->tdata()[i] = arg;
}
}
return a;
}
char *Parameter::argsTypesToChars(Parameters *args, int varargs)
{
OutBuffer *buf = new OutBuffer();
#if 1
HdrGenState hgs;
argsToCBuffer(buf, &hgs, args, varargs);
#else
buf->writeByte('(');
if (args)
{ OutBuffer argbuf;
HdrGenState hgs;
for (size_t i = 0; i < args->dim; i++)
{ if (i)
buf->writeByte(',');
Parameter *arg = args->tdata()[i];
argbuf.reset();
arg->type->toCBuffer2(&argbuf, &hgs, 0);
buf->write(&argbuf);
}
if (varargs)
{
if (i && varargs == 1)
buf->writeByte(',');
buf->writestring("...");
}
}
buf->writeByte(')');
#endif
return buf->toChars();
}
void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs)
{
buf->writeByte('(');
if (arguments)
{
OutBuffer argbuf;
size_t dim = Parameter::dim(arguments);
for (size_t i = 0; i < dim; i++)
{
if (i)
buf->writestring(", ");
Parameter *arg = Parameter::getNth(arguments, i);
if (arg->storageClass & STCauto)
buf->writestring("auto ");
if (arg->storageClass & STCout)
buf->writestring("out ");
else if (arg->storageClass & STCref)
buf->writestring((global.params.Dversion == 1)
? "inout " : "ref ");
else if (arg->storageClass & STCin)
buf->writestring("in ");
else if (arg->storageClass & STClazy)
buf->writestring("lazy ");
else if (arg->storageClass & STCalias)
buf->writestring("alias ");
StorageClass stc = arg->storageClass;
if (arg->type && arg->type->mod & MODshared)
stc &= ~STCshared;
StorageClassDeclaration::stcToCBuffer(buf,
stc & (STCconst | STCimmutable | STCshared | STCscope));
argbuf.reset();
if (arg->storageClass & STCalias)
{ if (arg->ident)
argbuf.writestring(arg->ident->toChars());
}
else
arg->type->toCBuffer(&argbuf, arg->ident, hgs);
if (arg->defaultArg)
{
argbuf.writestring(" = ");
arg->defaultArg->toCBuffer(&argbuf, hgs);
}
buf->write(&argbuf);
}
if (varargs)
{
if (arguments->dim && varargs == 1)
buf->writeByte(',');
buf->writestring("...");
}
}
buf->writeByte(')');
}
static int argsToDecoBufferDg(void *ctx, size_t n, Parameter *arg)
{
arg->toDecoBuffer((OutBuffer *)ctx);
return 0;
}
void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments)
{
//printf("Parameter::argsToDecoBuffer()\n");
// Write argument types
foreach(arguments, &argsToDecoBufferDg, buf);
}
/****************************************
* Determine if parameter list is really a template parameter list
* (i.e. it has auto or alias parameters)
*/
static int isTPLDg(void *ctx, size_t n, Parameter *arg)
{
if (arg->storageClass & (STCalias | STCauto | STCstatic))
return 1;
return 0;
}
int Parameter::isTPL(Parameters *arguments)
{
//printf("Parameter::isTPL()\n");
return foreach(arguments, &isTPLDg, NULL);
}
/****************************************************
* Determine if parameter is a lazy array of delegates.
* If so, return the return type of those delegates.
* If not, return NULL.
*/
Type *Parameter::isLazyArray()
{
// if (inout == Lazy)
{
Type *tb = type->toBasetype();
if (tb->ty == Tsarray || tb->ty == Tarray)
{
Type *tel = ((TypeArray *)tb)->next->toBasetype();
if (tel->ty == Tdelegate)
{
TypeDelegate *td = (TypeDelegate *)tel;
TypeFunction *tf = (TypeFunction *)td->next;
if (!tf->varargs && Parameter::dim(tf->parameters) == 0)
{
return tf->next; // return type of delegate
}
}
}
}
return NULL;
}
void Parameter::toDecoBuffer(OutBuffer *buf)
{
if (storageClass & STCscope)
buf->writeByte('M');
switch (storageClass & (STCin | STCout | STCref | STClazy))
{ case 0:
case STCin:
break;
case STCout:
buf->writeByte('J');
break;
case STCref:
buf->writeByte('K');
break;
case STClazy:
buf->writeByte('L');
break;
default:
#ifdef DEBUG
printf("storageClass = x%llx\n", storageClass & (STCin | STCout | STCref | STClazy));
halt();
#endif
assert(0);
}
#if 0
int mod = 0x100;
if (type->toBasetype()->ty == Tclass)
mod = 0;
type->toDecoBuffer(buf, mod);
#else
//type->toHeadMutable()->toDecoBuffer(buf, 0);
type->toDecoBuffer(buf, 0);
#endif
}
/***************************************
* Determine number of arguments, folding in tuples.
*/
static int dimDg(void *ctx, size_t n, Parameter *)
{
++*(size_t *)ctx;
return 0;
}
size_t Parameter::dim(Parameters *args)
{
size_t n = 0;
foreach(args, &dimDg, &n);
return n;
}
/***************************************
* Get nth Parameter, folding in tuples.
* Returns:
* Parameter* nth Parameter
* NULL not found, *pn gets incremented by the number
* of Parameters
*/
struct GetNthParamCtx
{
size_t nth;
Parameter *arg;
};
static int getNthParamDg(void *ctx, size_t n, Parameter *arg)
{
GetNthParamCtx *p = (GetNthParamCtx *)ctx;
if (n == p->nth)
{ p->arg = arg;
return 1;
}
return 0;
}
Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn)
{
GetNthParamCtx ctx = { nth, NULL };
int res = foreach(args, &getNthParamDg, &ctx);
return res ? ctx.arg : NULL;
}
/***************************************
* Expands tuples in args in depth first order. Calls
* dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
* If dg returns !=0, stops and returns that value else returns 0.
* Use this function to avoid the O(N + N^2/2) complexity of
* calculating dim and calling N times getNth.
*/
int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, size_t *pn)
{
assert(dg);
if (!args)
return 0;
size_t n = pn ? *pn : 0; // take over index
int result = 0;
for (size_t i = 0; i < args->dim; i++)
{ Parameter *arg = args->tdata()[i];
Type *t = arg->type->toBasetype();
if (t->ty == Ttuple)
{ TypeTuple *tu = (TypeTuple *)t;
result = foreach(tu->arguments, dg, ctx, &n);
}
else
result = dg(ctx, n++, arg);
if (result)
break;
}
if (pn)
*pn = n; // update index
return result;
}