Changeset 71a3593


Ignore:
Timestamp:
Aug 5, 2016, 12:06:29 PM (8 years ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
d9e2280
Parents:
9706554 (diff), a2f920f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg2:software/cfa/cfa-cc

Files:
4 added
34 edited

Legend:

Unmodified
Added
Removed
  • doc/aaron_comp_II/comp_II.tex

    r9706554 r71a3593  
    8484\section{Introduction}
    8585
    86 \CFA\footnote{Pronounced ``C-for-all'', and written \CFA, CFA, or \CFL.} is an evolutionary modernization of the C programming language currently being designed and built at the University of Waterloo by a team led by Peter Buhr.
    87 \CFA adds multiple features to C, including name overloading, user-defined operators, parametric-polymorphic routines, and type constructors and destructors, among others.
    88 These features make \CFA significantly more powerful and expressive than C, but impose a significant compile-time cost to support, particularly in the expression resolver, which must evaluate the typing rules of a much more complex type system.
    89 The primary goal of this proposed research project is to develop a sufficiently performant expression resolution algorithm, experimentally validate its performance, and integrate it into \Index*{CFA-CC}, the \CFA reference compiler.
    90 Secondary goals of this project include the development of various new language features for \CFA; parametric-polymorphic (``generic'') types have already been designed and implemented, and reference types and user-defined conversions are under design consideration.
    91 The experimental performance-testing architecture for resolution algorithms will also be used to determine the compile-time cost of adding such new features to the \CFA type system.
    92 More broadly, this research should provide valuable data for implementers of compilers for other programming languages with similarly powerful static type systems.
     86\CFA\footnote{Pronounced ``C-for-all'', and written \CFA or \CFL.} is an evolutionary modernization of the C programming language currently being designed and built at the University of Waterloo by a team led by Peter Buhr.
     87\CFA both fixes existing design problems and adds multiple new features to C, including name overloading, user-defined operators, parametric-polymorphic routines, and type constructors and destructors, among others.
     88The new features make \CFA significantly more powerful and expressive than C, but impose a significant compile-time cost, particularly in the expression resolver, which must evaluate the typing rules of a much more complex type-system.
     89
     90The primary goal of this research project is to develop a sufficiently performant expression resolution algorithm, experimentally validate its performance, and integrate it into CFA, the \CFA reference compiler.
     91Secondary goals of this project include the development of various new language features for \CFA: parametric-polymorphic (``generic'') types have already been designed and implemented, and reference types and user-defined conversions are under design consideration.
     92An experimental performance-testing architecture for resolution algorithms is under development to determine the relative performance of different expression resolution algorithms, as well as the compile-time cost of adding various new features to the \CFA type-system.
     93More broadly, this research should provide valuable data for implementers of compilers for other programming languages with similarly powerful static type-systems.
    9394
    9495\section{\CFA}
    9596
    96 To make the scope of the proposed expression resolution problem more explicit, it is necessary to define the features of both C and \CFA (both current and proposed) which affect this algorithm.
    97 In some cases the interactions of multiple features make expression resolution a significantly more complex problem than any individual feature would; in others a feature which does not by itself add any complexity to expression resolution will trigger previously rare edge cases much more frequently.
     97To make the scope of the proposed expression resolution problem more explicit, it is necessary to define the features of both C and \CFA (both current and proposed) that affect this algorithm.
     98In some cases the interactions of multiple features make expression resolution a significantly more complex problem than any individual feature would; in other cases a feature that does not by itself add any complexity to expression resolution triggers previously rare edge cases more frequently.
     99
     100It is important to note that \CFA is not an object-oriented language.
     101\CFA does have a system of (possibly implicit) type conversions derived from C's type conversions; while these conversions may be thought of as something like an inheritance hierarchy the underlying semantics are significantly different and such an analogy is loose at best.
     102Particularly, \CFA has no concept of ``subclass'', and thus no need to integrate an inheritance-based form of polymorphism with its parametric and overloading-based polymorphism.
     103The graph structure of the \CFA type conversions is also markedly different than an inheritance graph; it has neither a top nor a bottom type, and does not satisfy the lattice properties typical of inheritance graphs.
    98104
    99105\subsection{Polymorphic Functions}
     
    101107Such functions are written using a ©forall© clause (which gives the language its name):
    102108\begin{lstlisting}
    103 forall(otype T)
     109®forall(otype T)®
    104110T identity(T x) {
    105111    return x;
     
    110116The ©identity© function above can be applied to any complete object type (or ``©otype©'').
    111117The type variable ©T© is transformed into a set of additional implicit parameters to ©identity© which encode sufficient information about ©T© to create and return a variable of that type.
    112 The current \CFA implementation passes the size and alignment of the type represented by an ©otype© parameter, as well as an assignment operator, constructor, copy constructor \& destructor.
     118The current \CFA implementation passes the size and alignment of the type represented by an ©otype© parameter, as well as an assignment operator, constructor, copy constructor and destructor.
    113119
    114120Since bare polymorphic types do not provide a great range of available operations, \CFA also provides a \emph{type assertion} mechanism to provide further information about a type:
    115121\begin{lstlisting}
    116 forall(otype T | { T twice(T); })
     122forall(otype T ®| { T twice(T); }®)
    117123T four_times(T x) {
    118124    return twice( twice(x) );
     
    137143Finding appropriate functions to satisfy type assertions is essentially a recursive case of expression resolution, as it takes a name (that of the type assertion) and attempts to match it to a suitable declaration in the current scope.
    138144If a polymorphic function can be used to satisfy one of its own type assertions, this recursion may not terminate, as it is possible that function will be examined as a candidate for its own type assertion unboundedly repeatedly.
    139 To avoid infinite loops, the current \Index*{CFA-CC} compiler imposes a fixed limit on the possible depth of recursion, similar to that employed by most \Index*[C++]{\CC} compilers for template expansion; this restriction means that there are some semantically well-typed expressions which cannot be resolved by {CFA-CC}.
     145To avoid infinite loops, the current CFA compiler imposes a fixed limit on the possible depth of recursion, similar to that employed by most \CC compilers for template expansion; this restriction means that there are some semantically well-typed expressions which cannot be resolved by CFA.
    140146One area of potential improvement this project proposes to investigate is the possibility of using the compiler's knowledge of the current set of declarations to more precicely determine when further type assertion satisfaction recursion will not produce a well-typed expression.
     147
     148\subsubsection{Traits}
     149\CFA provides \emph{traits} as a means to name a group of type assertions, as in the example below:
     150\begin{lstlisting}
     151trait has_magnitude(otype T) {
     152    bool ?<?(T, T);        // comparison operator for T
     153    T -?(T);               // negation operator for T
     154    void ?{}(T*, zero_t);  // constructor from 0 literal
     155};
     156
     157forall(otype M | has_magnitude(M))
     158M abs( M m ) {
     159    M zero = 0;  // uses zero_t constructor from trait
     160    return m < zero ? -m : m;
     161}
     162
     163forall(otype M | has_magnitude(M))
     164M max_magnitude( M a, M b ) {
     165    M aa = abs(a), ab = abs(b);
     166    return aa < ab ? b : a;
     167}
     168\end{lstlisting}
     169
     170Semantically, a trait is merely a named list of type assertions, but they can be used in many of the same situations where an interface in Java or an abstract base class in \CC would be used.
     171Unlike Java interfaces or \CC base classes, \CFA types do not explicitly state any inheritance relationship to traits they satisfy; this can be considered a form of structural inheritance, similar to interface implementation in Go, as opposed to the nominal inheritance model of Java and \CC.
     172% TODO talk about modelling of nominal inheritance with structural inheritance, possibility of investigating some resolver algorithms that require nominal
    141173
    142174\subsection{Name Overloading}
     
    174206Open research questions on this topic include whether a conversion graph can be generated that represents each allowable conversion in C with a unique minimal-length path, such that the path lengths accurately represent the relative costs of the conversions, whether such a graph representation can be usefully augmented to include user-defined types as well as built-in types, and whether the graph can be efficiently represented and included in the expression resolver.
    175207
    176 \subsection{Constructors \& Destructors}
     208\subsection{Constructors and Destructors}
    177209Rob Shluntz, a current member of the \CFA research team, has added constructors and destructors to \CFA.
    178210Each type has an overridable default-generated zero-argument constructor, copy constructor, assignment operator, and destructor; for struct types these functions each call their equivalents on each field of the struct.
     
    180212
    181213\subsection{Generic Types}
    182 The author has added a generic type capability to \CFA, designed to efficiently and naturally integrate with \CFA's existing polymorphic functions.
     214I have already added a generic type capability to \CFA, designed to efficiently and naturally integrate with \CFA's existing polymorphic functions.
    183215A generic type can be declared by placing a ©forall© specifier on a struct or union declaration, and instantiated using a parenthesized list of types after the type name:
    184216\begin{lstlisting}
     
    195227\end{lstlisting}
    196228For \emph{concrete} generic types, that is, those where none of the type parameters depend on polymorphic type variables (like ©pair(const char*, int)© above), the struct is essentially template expanded to a new struct type; for \emph{polymorphic} generic types (such as ©pair(const char*, T)© above), member access is handled by a runtime calculation of the field offset, based on the size and alignment information of the polymorphic parameter type.
    197 The default-generated constructors, destructor \& assignment operator for a generic type are polymorphic functions with the same list of type parameters as the generic type definition.
    198 
    199 Aside from giving users the ability to create more parameterized types than just the built-in pointer, array \& function types, the combination of generic types with polymorphic functions and implicit conversions makes the edge case where a polymorphic function can match its own assertions much more common, as follows:
     229The default-generated constructors, destructor and assignment operator for a generic type are polymorphic functions with the same list of type parameters as the generic type definition.
     230
     231Aside from giving users the ability to create more parameterized types than just the built-in pointer, array and function types, the combination of generic types with polymorphic functions and implicit conversions makes the edge case where a polymorphic function can match its own assertions much more common, as follows:
    200232\begin{itemize}
    201233\item Given an expression in an untyped context, such as a top-level function call with no assignment of return values, apply a polymorphic implicit conversion to the expression that can produce multiple types (the built-in conversion from ©void*© to any other pointer type is one, but not the only).
     
    221253
    222254\subsection{Reference Types}
    223 The author, in collaboration with the rest of the \CFA research team, has been designing \emph{reference types} for \CFA.
     255I have been designing \emph{reference types} for \CFA, in collaboration with the rest of the \CFA research team.
    224256Given some type ©T©, a ©T&© (``reference to ©T©'') is essentially an automatically dereferenced pointer; with these semantics most of the C standard's discussions of lvalues can be expressed in terms of references instead, with the benefit of being able to express the difference between the reference and non-reference version of a type in user code.
    225257References preserve C's existing qualifier-dropping lvalue-to-rvalue conversion (\eg a ©const volatile int&© can be implicitly converted to a bare ©int©); the reference proposal also adds a rvalue-to-lvalue conversion to \CFA, implemented by storing the value in a new compiler-generated temporary and passing a reference to the temporary.
     
    229261
    230262\subsection{Literal Types}
    231 Another proposal currently under consideration for the \CFA type system is assigning special types to the literal values ©0© and ©1©.%, say ©zero_t© and ©one_t©.
     263Another proposal currently under consideration for the \CFA type-system is assigning special types to the literal values ©0© and ©1©.%, say ©zero_t© and ©one_t©.
    232264Implicit conversions from these types would allow ©0© and ©1© to be considered as values of many different types, depending on context, allowing expression desugarings like ©if ( x ) {}© $\Rightarrow$ ©if ( x != 0 ) {}© to be implemented efficiently and precicely.
    233265This is a generalization of C's existing behaviour of treating ©0© as either an integer zero or a null pointer constant, and treating either of those values as boolean false.
     
    248280Expression resolution is somewhat unavoidably exponential in $p$, the number of function parameters, and $d$, the depth of the expression tree, but these values are fixed by the user programmer, and generally bounded by reasonably small constants.
    249281$k$, on the other hand, is mostly dependent on the representation of types in the system and the efficiency of type assertion checking; if a candidate argument combination can be compared to a function parameter list in linear time in the length of the list (\ie $k = 1$), then the $p^{k \cdot d}$ term is linear in the input size of the source code for the expression, otherwise the resolution algorithm will exibit sub-linear performance scaling on code containing more-deeply nested expressions.
    250 The number of valid interpretations of any subexpression, $i$, is bounded by the number of types in the system, which is possibly infinite, though practical resolution algorithms for \CFA must be able to place some finite bound on $i$, possibly at the expense of type system completeness.
     282The number of valid interpretations of any subexpression, $i$, is bounded by the number of types in the system, which is possibly infinite, though practical resolution algorithms for \CFA must be able to place some finite bound on $i$, possibly at the expense of type-system completeness.
    251283
    252284The research goal of this project is to develop a performant expression resolver for \CFA; this analysis suggests two primary areas of investigation to accomplish that end.
    253 The first is efficient argument-parameter matching; Bilson\cite{Bilson03} mentions significant optimization opportunities available in the current literature to improve on the existing {CFA-CC} compiler.
     285The first is efficient argument-parameter matching; Bilson\cite{Bilson03} mentions significant optimization opportunities available in the current literature to improve on the existing CFA compiler.
    254286%TODO: look up and lit review
    255287The second, and likely more fruitful, area of investigation is heuristics and algorithmic approaches to reduce the number of argument interpretations considered in the common case; given the large ($p+1$) exponent on number of interpretations considered in the runtime analysis, even small reductions here could have a significant effect on overall resolver runtime.
     
    299331Another approach would be to generate a set of possible implicit conversions for each set of interpretations of a given argument.
    300332This would have the benefit of detecting ambiguous interpretations of arguments at the level of the argument rather than its containing call, would also never find more than one interpretation of the argument with a given type, and would re-use calculation of implicit conversions between function candidates.
    301 On the other hand, this approach may unncessarily generate argument interpretations that will never match a parameter, wasting work.
     333On the other hand, this approach may unncessarily generate argument interpretations that will never match a parameter, wasting work.
     334Further, in the presence of tuple types this approach may lead to a combinatorial explosion of argument interpretations considered, unless the tuple can be considered as a sequence of elements rather than a unified whole.
    302335
    303336\subsection{Candidate Set Generation}
    304 Cormack\cite{Cormack81}, Baker\cite{Baker82} \& Bilson\cite{Bilson03} all generate the complete set of candidate argument interpretations before attempting to match the containing function call expression.
     337Cormack\cite{Cormack81}, Baker\cite{Baker82} and Bilson\cite{Bilson03} all generate the complete set of candidate argument interpretations before attempting to match the containing function call expression.
    305338However, given that the top-level expression interpretation that is ultimately chosen will be the minimal-cost valid interpretation, any consideration of non-minimal-cost interpretations is in some sense wasted work.
    306339If we assume that user programmers will generally write function calls with relatively low-cost interpretations, a possible work-saving heuristic is to generate only the lowest-cost argument interpretations first, attempt to find a valid top-level interpretation using them, and only if that fails generate the higher-cost argument interpretations.
    307340
    308341\subsubsection{Eager}
    309 Within the eager approach taken by Cormack, Baker \& Bilson, there are still variants to explore.
    310 Cormack \& Baker do not account for implict conversions, and thus do not account for the possibility of multiple valid interpretations with distinct costs; Bilson, on the other hand, sorts the list of interpretations to aid in finding minimal-cost interpretations.
     342Within the eager approach taken by Cormack, Baker and Bilson, there are still variants to explore.
     343Cormack and Baker do not account for implict conversions, and thus do not account for the possibility of multiple valid interpretations with distinct costs; Bilson, on the other hand, sorts the list of interpretations to aid in finding minimal-cost interpretations.
    311344Sorting the lists of argument or function call interpretations by cost at some point during resolution may provide useful opportunities to short-circuit expression evaluation when a minimal-cost interpretation is found, though it is not clear if this short-circuiting behaviour would justify the cost of the sort.
    312345
     
    315348However, if user programmers actually use relatively few implicit conversions, then the ``on arguments'' approach to implicit conversions will generate a large number of high-cost interpretations which may never be used.
    316349The essence of the lazy approach to candidate set generation is to wrap the matching algorithm into the element generator of a lazy list type, only generating as few elements at a time as possible to ensure that the next-smallest-cost interpretation has been generated.
    317 Assuming that argument interpretations are provided to the parameter matching algorithm in sorted order, a sorted list of function call interpretations can be produced by generating combinations of arguments sorted by total cost\footnote{The author has developed a lazy $n$-way combination generation algorithm that can perform this task.}, then generating function call interpretations in the order suggested by this list.
     350Assuming that argument interpretations are provided to the parameter matching algorithm in sorted order, a sorted list of function call interpretations can be produced by generating combinations of arguments sorted by total cost\footnote{I have already developed a lazy $n$-way combination generation algorithm to perform this task.}, then generating function call interpretations in the order suggested by this list.
    318351Note that the function call interpretation chosen may have costs of its own, for instance polymorphic type binding, so in some cases a number of argument combinations (any combination whose marginal cost does not exceed the cost of the function call interpretation itself) may need to be considered to determine the next-smallest-cost function call interpretation.
    319352Ideally, this candidate generation approach will lead to very few unused candidates being generated (in the expected case where the user programmer has, in fact, provided a validly-typable program), but this research project will need to determine whether or not the overheads of lazy generation exceed the benefit produced from considering fewer interpretations.
     
    333366%\subsection{Parameter-Directed}
    334367%\textbf{TODO: Richard's algorithm isn't Baker (Cormack?), disentangle from this section \ldots}.
    335 %The expression resolution algorithm used by the existing iteration of {CFA-CC} is based on Baker's\cite{Baker82} algorithm for overload resolution in Ada.
     368%The expression resolution algorithm used by the existing iteration of CFA is based on Baker's\cite{Baker82} algorithm for overload resolution in Ada.
    336369%The essential idea of this algorithm is to first find the possible interpretations of the most deeply nested subexpressions, then to use these interpretations to recursively generate valid interpretations of their superexpressions.
    337370%To simplify matters, the only expressions considered in this discussion of the algorithm are function application and literal expressions; other expression types can generally be considered to be variants of one of these for the purposes of the resolver, \eg variables are essentially zero-argument functions.
     
    341374%\textbf{TODO: Figure}
    342375%
    343 %Baker's algorithm was designed to account for name overloading; Richard Bilson\cite{Bilson03} extended this algorithm to also handle polymorphic functions, implicit conversions \& multiple return types when designing the original \CFA compiler.
     376%Baker's algorithm was designed to account for name overloading; Richard Bilson\cite{Bilson03} extended this algorithm to also handle polymorphic functions, implicit conversions and multiple return types when designing the original \CFA compiler.
    344377%The core of the algorithm is a function which Baker refers to as $gen\_calls$.
    345378%$gen\_calls$ takes as arguments the name of a function $f$ and a list containing the set of possible subexpression interpretations $S_j$ for each argument of the function and returns a set of possible interpretations of calling that function on those arguments.
     
    363396\section{Proposal}
    364397Baker\cite{Baker82} discussed various expression resolution algorithms that could handle name overloading, but left experimental comparison of those algorithms to future work; Bilson\cite{Bilson03} described one extension of Baker's algorithm to handle implicit conversions, but did not fully explore the space of algorithmic approaches to handle both overloaded names and implicit conversions.
    365 This project is intended to experimentally test a number of expression resolution algorithms which are powerful enough to handle the \CFA type system, including both name overloading and implicit conversions.
     398This project is intended to experimentally test a number of expression resolution algorithms which are powerful enough to handle the \CFA type-system, including both name overloading and implicit conversions.
    366399This comparison will close Baker's open research question, as well as potentially improving on Bilson's \CFA compiler.
    367400
    368 Rather than testing all of these algorithms in-place in the \CFA compiler, a resolver prototype will be developed which acts on a simplified input language encapsulating the essential details of the \CFA type system\footnote{Note that this simplified input language is not required to be a usable programming language.}.
     401Rather than testing all of these algorithms in-place in the \CFA compiler, a resolver prototype will be developed which acts on a simplified input language encapsulating the essential details of the \CFA type-system\footnote{Note that this simplified input language is not required to be a usable programming language.}.
    369402Multiple variants of this resolver prototype will be implemented, each encapsulating a different expression resolution variant, sharing as much code as feasible.
    370403These variants will be instrumented to test runtime performance, and run on a variety of input files; the input files may be generated programmatically or from exisiting code in \CFA or similar languages.
    371 These experimental results will allow the research team to determine the algorithm likely to be most performant in practical use, and replace {CFA-CC}'s existing expression resolver with that code.
     404These experimental results will allow the research team to determine the algorithm likely to be most performant in practical use, and replace CFA's existing expression resolver with that code.
    372405The experimental results will also provide some empirical sense of the compile-time cost of various language features by comparing the results of the most performant resolver variant that supports the feature with the most performant resolver variant that doesn't, a useful capability to guide language design.
    373406
    374 This proposed project should provide valuable data on how to implement a performant compiler for modern programming languages such as \CFA with powerful static type systems, specifically targeting the feature interaction between name overloading and implicit conversions.
     407This proposed project should provide valuable data on how to implement a performant compiler for modern programming languages such as \CFA with powerful static type-systems, specifically targeting the feature interaction between name overloading and implicit conversions.
    375408
    376409\appendix
     
    379412\begin{center}
    380413\begin{tabular}{ | r @{--} l | p{4in} | }
    381 \hline       May 2015 & April 2016   & Project familiarization and generic types design \& implementation. \\
    382 \hline       May 2016 & April 2017   & Design \& implement resolver prototype and run performance experiments. \\
    383 \hline       May 2017 & August 2017  & Integrate new language features and best-performing resolver prototype into {CFA-CC}. \\
    384 \hline September 2017 & January 2018 & Thesis writing \& defense. \\
     414\hline       May 2015 & April 2016   & Project familiarization and generic types design and implementation. \\
     415\hline       May 2016 & April 2017   & Design and implement resolver prototype and run performance experiments. \\
     416\hline       May 2017 & August 2017  & Integrate new language features and best-performing resolver prototype into CFA. \\
     417\hline September 2017 & January 2018 & Thesis writing and defense. \\
    385418\hline
    386419\end{tabular}
  • doc/working/resolver_design.md

    r9706554 r71a3593  
    3737
    3838An alternate possibility would be to only count two-arg constructors
    39 `void ?{} ( To*, From )` as unsafe conversions; under this semantics, safe and  
     39`void ?{} ( To*, From )` as unsafe conversions; under this semantics, safe and
    4040explicit conversions should also have a compiler-enforced restriction to
    4141ensure that they are two-arg functions (this restriction may be valuable
     
    6969two chains of conversions, one among the signed integral types, another among
    7070the unsigned, and to use monomorphic conversions to allow conversions between
    71 signed and unsigned integer types).   
     71signed and unsigned integer types).
    7272
    7373### Implementation Details ###
     
    509509A variant of the above scheme would be to fix a maximum depth of polymorphic
    510510type variables (16 seems like a reasonable choice) at which a parameter would
    511 be considered to be effectively monomorphic, and to subtract the value  
     511be considered to be effectively monomorphic, and to subtract the value
    512512described above from that maximum, clamping the result to a minimum of 0.
    513513Under this scheme, assuming a maximum value of 4, `int` has value 0, `T` has
     
    577577specifying the (completely arbitrary) maximum depth as part of the language or
    578578allowing the compiler to refuse to accept otherwise well-typed deeply-nested
    579 polymorphic types. 
     579polymorphic types.
    580580
    581581For purposes of determining polymorphism, the list of return types of a
     
    951951`sizeof`, `alignof`, and `offsetof` expressions have at most a single
    952952interpretation, of type `size_t`.
    953 `sizeof` and `alignof` expressions take either a type or an expression as a 
    954 an argument; if the argument is a type, it must be a complete type which is
    955 not a function type, if an expression, the expression must have a single
     953`sizeof` and `alignof` expressions take either a type or an expression as an
     954argument; if the argument is a type, it must be a complete type which is not a
     955function type, if an expression, the expression must have a single
    956956interpretation, the type of which conforms to the same rules.
    957957`offsetof` takes two arguments, a type and a member name; the type must be
     
    16201620                        = delete;
    16211621        }
     1622
     1623## Appendix E: Features to Add in Resolver Re-write ##
     1624* Reference types
     1625* Special types for 0 and 1 literals
     1626* Expression type for return statement that resolves similarly to ?=?
     1627  - This is to get rid of the kludge in the box pass that effectively
     1628    re-implements the resolver poorly.
  • src/CodeGen/CodeGenerator.cc

    r9706554 r71a3593  
    148148        void CodeGenerator::visit( ObjectDecl * objectDecl ) {
    149149                extension( objectDecl );
     150                genAttributes( objectDecl->get_attributes() );
     151
    150152                handleStorageClass( objectDecl );
    151153                output << genType( objectDecl->get_type(), mangleName( objectDecl ) );
     
    271273                printDesignators( init->get_designators() );
    272274                output << "{ ";
    273                 if ( init->begin_initializers() == init->end_initializers() ) {
     275                if ( init->begin() == init->end() ) {
    274276                        // illegal to leave initializer list empty for scalar initializers, but always legal to have 0
    275277                        output << "0";
    276278                } else {
    277                         genCommaList( init->begin_initializers(), init->end_initializers() );
     279                        genCommaList( init->begin(), init->end() );
    278280                } // if
    279281                output << " }";
  • src/GenPoly/Box.cc

    r9706554 r71a3593  
    6262
    6363                FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
    64 
    65                 /// Abstracts type equality for a list of parameter types
    66                 struct TypeList {
    67                         TypeList() : params() {}
    68                         TypeList( const std::list< Type* > &_params ) : params() { cloneAll(_params, params); }
    69                         TypeList( std::list< Type* > &&_params ) : params( _params ) {}
    70 
    71                         TypeList( const TypeList &that ) : params() { cloneAll(that.params, params); }
    72                         TypeList( TypeList &&that ) : params( std::move( that.params ) ) {}
    73 
    74                         /// Extracts types from a list of TypeExpr*
    75                         TypeList( const std::list< TypeExpr* >& _params ) : params() {
    76                                 for ( std::list< TypeExpr* >::const_iterator param = _params.begin(); param != _params.end(); ++param ) {
    77                                         params.push_back( (*param)->get_type()->clone() );
    78                                 }
    79                         }
    80 
    81                         TypeList& operator= ( const TypeList &that ) {
    82                                 deleteAll( params );
    83 
    84                                 params.clear();
    85                                 cloneAll( that.params, params );
    86 
    87                                 return *this;
    88                         }
    89 
    90                         TypeList& operator= ( TypeList &&that ) {
    91                                 deleteAll( params );
    92 
    93                                 params = std::move( that.params );
    94 
    95                                 return *this;
    96                         }
    97 
    98                         ~TypeList() { deleteAll( params ); }
    99 
    100                         bool operator== ( const TypeList& that ) const {
    101                                 if ( params.size() != that.params.size() ) return false;
    102 
    103                                 SymTab::Indexer dummy;
    104                                 for ( std::list< Type* >::const_iterator it = params.begin(), jt = that.params.begin(); it != params.end(); ++it, ++jt ) {
    105                                         if ( ! ResolvExpr::typesCompatible( *it, *jt, dummy ) ) return false;
    106                                 }
    107                                 return true;
    108                         }
    109 
    110                         std::list< Type* > params;  ///< Instantiation parameters
    111                 };
    112 
    113                 /// Maps a key and a TypeList to the some value, accounting for scope
    114                 template< typename Key, typename Value >
    115                 class InstantiationMap {
    116                         /// Wraps value for a specific (Key, TypeList) combination
    117                         typedef std::pair< TypeList, Value* > Instantiation;
    118                         /// List of TypeLists paired with their appropriate values
    119                         typedef std::vector< Instantiation > ValueList;
    120                         /// Underlying map type; maps keys to a linear list of corresponding TypeLists and values
    121                         typedef ScopedMap< Key*, ValueList > InnerMap;
    122 
    123                         InnerMap instantiations;  ///< instantiations
    124 
    125                 public:
    126                         /// Starts a new scope
    127                         void beginScope() { instantiations.beginScope(); }
    128 
    129                         /// Ends a scope
    130                         void endScope() { instantiations.endScope(); }
    131 
    132                         /// Gets the value for the (key, typeList) pair, returns NULL on none such.
    133                         Value *lookup( Key *key, const std::list< TypeExpr* >& params ) const {
    134                                 TypeList typeList( params );
    135 
    136                                 // scan scopes for matches to the key
    137                                 for ( typename InnerMap::const_iterator insts = instantiations.find( key ); insts != instantiations.end(); insts = instantiations.findNext( insts, key ) ) {
    138                                         for ( typename ValueList::const_reverse_iterator inst = insts->second.rbegin(); inst != insts->second.rend(); ++inst ) {
    139                                                 if ( inst->first == typeList ) return inst->second;
    140                                         }
    141                                 }
    142                                 // no matching instantiations found
    143                                 return 0;
    144                         }
    145 
    146                         /// Adds a value for a (key, typeList) pair to the current scope
    147                         void insert( Key *key, const std::list< TypeExpr* > &params, Value *value ) {
    148                                 instantiations[ key ].push_back( Instantiation( TypeList( params ), value ) );
    149                         }
    150                 };
    15164
    15265                /// Adds layout-generation functions to polymorphic types
     
    239152                };
    240153
    241                 /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
    242                 class GenericInstantiator : public DeclMutator {
    243                         /// Map of (generic type, parameter list) pairs to concrete type instantiations
    244                         InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
    245                         /// Namer for concrete types
    246                         UniqueName typeNamer;
    247 
    248                 public:
    249                         GenericInstantiator() : DeclMutator(), instantiations(), typeNamer("_conc_") {}
    250 
    251                         virtual Type* mutate( StructInstType *inst );
    252                         virtual Type* mutate( UnionInstType *inst );
    253 
    254         //              virtual Expression* mutate( MemberExpr *memberExpr );
    255 
    256                         virtual void doBeginScope();
    257                         virtual void doEndScope();
    258                 private:
    259                         /// Wrap instantiation lookup for structs
    260                         StructDecl* lookup( StructInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (StructDecl*)instantiations.lookup( inst->get_baseStruct(), typeSubs ); }
    261                         /// Wrap instantiation lookup for unions
    262                         UnionDecl* lookup( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (UnionDecl*)instantiations.lookup( inst->get_baseUnion(), typeSubs ); }
    263                         /// Wrap instantiation insertion for structs
    264                         void insert( StructInstType *inst, const std::list< TypeExpr* > &typeSubs, StructDecl *decl ) { instantiations.insert( inst->get_baseStruct(), typeSubs, decl ); }
    265                         /// Wrap instantiation insertion for unions
    266                         void insert( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs, UnionDecl *decl ) { instantiations.insert( inst->get_baseUnion(), typeSubs, decl ); }
    267                 };
    268 
    269154                /// Replaces member and size/align/offsetof expressions on polymorphic generic types with calculated expressions.
    270155                /// * Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference
     
    354239                Pass1 pass1;
    355240                Pass2 pass2;
    356                 GenericInstantiator instantiator;
    357241                PolyGenericCalculator polyCalculator;
    358242                Pass3 pass3;
     
    361245                mutateTranslationUnit/*All*/( translationUnit, pass1 );
    362246                mutateTranslationUnit/*All*/( translationUnit, pass2 );
    363                 instantiator.mutateDeclarationList( translationUnit );
    364247                mutateTranslationUnit/*All*/( translationUnit, polyCalculator );
    365248                mutateTranslationUnit/*All*/( translationUnit, pass3 );
     
    889772                                                arg++;
    890773                                        } else {
    891                                                 /// xxx - should this be an assertion?
     774                                                // xxx - should this be an assertion?
    892775                                                throw SemanticError( "unbound type variable: " + tyParm->first + " in application ", appExpr );
    893776                                        } // if
     
    902785                        std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin();
    903786                        std::list< Expression* >::const_iterator fnArg = arg;
    904                         std::set< std::string > seenTypes; //< names for generic types we've seen
     787                        std::set< std::string > seenTypes; ///< names for generic types we've seen
    905788
    906789                        // a polymorphic return type may need to be added to the argument list
     
    1042925                /// this gets rid of warnings from gcc.
    1043926                void addCast( Expression *&actual, Type *formal, const TyVarMap &tyVars ) {
    1044                         Type * newType = formal->clone();
    1045                         if ( getFunctionType( newType ) ) {
     927                        if ( getFunctionType( formal ) ) {
     928                                Type * newType = formal->clone();
    1046929                                newType = ScrubTyVars::scrub( newType, tyVars );
    1047930                                actual = new CastExpr( actual, newType );
     
    17751658                }
    17761659
    1777 //////////////////////////////////////// GenericInstantiator //////////////////////////////////////////////////
    1778 
    1779                 /// Makes substitutions of params into baseParams; returns true if all parameters substituted for a concrete type
    1780                 bool makeSubstitutions( const std::list< TypeDecl* >& baseParams, const std::list< Expression* >& params, std::list< TypeExpr* >& out ) {
    1781                         bool allConcrete = true;  // will finish the substitution list even if they're not all concrete
    1782 
    1783                         // substitute concrete types for given parameters, and incomplete types for placeholders
    1784                         std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
    1785                         std::list< Expression* >::const_iterator param = params.begin();
    1786                         for ( ; baseParam != baseParams.end() && param != params.end(); ++baseParam, ++param ) {
    1787         //                      switch ( (*baseParam)->get_kind() ) {
    1788         //                      case TypeDecl::Any: {   // any type is a valid substitution here; complete types can be used to instantiate generics
    1789                                         TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    1790                                         assert(paramType && "Aggregate parameters should be type expressions");
    1791                                         out.push_back( paramType->clone() );
    1792                                         // check that the substituted type isn't a type variable itself
    1793                                         if ( dynamic_cast< TypeInstType* >( paramType->get_type() ) ) {
    1794                                                 allConcrete = false;
    1795                                         }
    1796         //                              break;
    1797         //                      }
    1798         //                      case TypeDecl::Dtype:  // dtype can be consistently replaced with void [only pointers, which become void*]
    1799         //                              out.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
    1800         //                              break;
    1801         //                      case TypeDecl::Ftype:  // pointer-to-ftype can be consistently replaced with void (*)(void) [similar to dtype]
    1802         //                              out.push_back( new TypeExpr( new FunctionType( Type::Qualifiers(), false ) ) );
    1803         //                              break;
    1804         //                      }
    1805                         }
    1806 
    1807                         // if any parameters left over, not done
    1808                         if ( baseParam != baseParams.end() ) return false;
    1809         //              // if not enough parameters given, substitute remaining incomplete types for placeholders
    1810         //              for ( ; baseParam != baseParams.end(); ++baseParam ) {
    1811         //                      switch ( (*baseParam)->get_kind() ) {
    1812         //                      case TypeDecl::Any:    // no more substitutions here, fail early
    1813         //                              return false;
    1814         //                      case TypeDecl::Dtype:  // dtype can be consistently replaced with void [only pointers, which become void*]
    1815         //                              out.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
    1816         //                              break;
    1817         //                      case TypeDecl::Ftype:  // pointer-to-ftype can be consistently replaced with void (*)(void) [similar to dtype]
    1818         //                              out.push_back( new TypeExpr( new FunctionType( Type::Qualifiers(), false ) ) );
    1819         //                              break;
    1820         //                      }
    1821         //              }
    1822 
    1823                         return allConcrete;
    1824                 }
    1825 
    1826                 /// Substitutes types of members of in according to baseParams => typeSubs, appending the result to out
    1827                 void substituteMembers( const std::list< Declaration* >& in, const std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs,
    1828                                                                 std::list< Declaration* >& out ) {
    1829                         // substitute types into new members
    1830                         TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
    1831                         for ( std::list< Declaration* >::const_iterator member = in.begin(); member != in.end(); ++member ) {
    1832                                 Declaration *newMember = (*member)->clone();
    1833                                 subs.apply(newMember);
    1834                                 out.push_back( newMember );
    1835                         }
    1836                 }
    1837 
    1838                 Type* GenericInstantiator::mutate( StructInstType *inst ) {
    1839                         // mutate subtypes
    1840                         Type *mutated = Mutator::mutate( inst );
    1841                         inst = dynamic_cast< StructInstType* >( mutated );
    1842                         if ( ! inst ) return mutated;
    1843 
    1844                         // exit early if no need for further mutation
    1845                         if ( inst->get_parameters().empty() ) return inst;
    1846                         assert( inst->get_baseParameters() && "Base struct has parameters" );
    1847 
    1848                         // check if type can be concretely instantiated; put substitutions into typeSubs
    1849                         std::list< TypeExpr* > typeSubs;
    1850                         if ( ! makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs ) ) {
    1851                                 deleteAll( typeSubs );
    1852                                 return inst;
    1853                         }
    1854 
    1855                         // make concrete instantiation of generic type
    1856                         StructDecl *concDecl = lookup( inst, typeSubs );
    1857                         if ( ! concDecl ) {
    1858                                 // set concDecl to new type, insert type declaration into statements to add
    1859                                 concDecl = new StructDecl( typeNamer.newName( inst->get_name() ) );
    1860                                 substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs,        concDecl->get_members() );
    1861                                 DeclMutator::addDeclaration( concDecl );
    1862                                 insert( inst, typeSubs, concDecl );
    1863                         }
    1864                         StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() );
    1865                         newInst->set_baseStruct( concDecl );
    1866 
    1867                         deleteAll( typeSubs );
    1868                         delete inst;
    1869                         return newInst;
    1870                 }
    1871 
    1872                 Type* GenericInstantiator::mutate( UnionInstType *inst ) {
    1873                         // mutate subtypes
    1874                         Type *mutated = Mutator::mutate( inst );
    1875                         inst = dynamic_cast< UnionInstType* >( mutated );
    1876                         if ( ! inst ) return mutated;
    1877 
    1878                         // exit early if no need for further mutation
    1879                         if ( inst->get_parameters().empty() ) return inst;
    1880                         assert( inst->get_baseParameters() && "Base union has parameters" );
    1881 
    1882                         // check if type can be concretely instantiated; put substitutions into typeSubs
    1883                         std::list< TypeExpr* > typeSubs;
    1884                         if ( ! makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs ) ) {
    1885                                 deleteAll( typeSubs );
    1886                                 return inst;
    1887                         }
    1888 
    1889                         // make concrete instantiation of generic type
    1890                         UnionDecl *concDecl = lookup( inst, typeSubs );
    1891                         if ( ! concDecl ) {
    1892                                 // set concDecl to new type, insert type declaration into statements to add
    1893                                 concDecl = new UnionDecl( typeNamer.newName( inst->get_name() ) );
    1894                                 substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    1895                                 DeclMutator::addDeclaration( concDecl );
    1896                                 insert( inst, typeSubs, concDecl );
    1897                         }
    1898                         UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() );
    1899                         newInst->set_baseUnion( concDecl );
    1900 
    1901                         deleteAll( typeSubs );
    1902                         delete inst;
    1903                         return newInst;
    1904                 }
    1905 
    1906         //      /// Gets the base struct or union declaration for a member expression; NULL if not applicable
    1907         //      AggregateDecl* getMemberBaseDecl( MemberExpr *memberExpr ) {
    1908         //              // get variable for member aggregate
    1909         //              VariableExpr *varExpr = dynamic_cast< VariableExpr* >( memberExpr->get_aggregate() );
    1910         //              if ( ! varExpr ) return NULL;
    1911         //
    1912         //              // get object for variable
    1913         //              ObjectDecl *objectDecl = dynamic_cast< ObjectDecl* >( varExpr->get_var() );
    1914         //              if ( ! objectDecl ) return NULL;
    1915         //
    1916         //              // get base declaration from object type
    1917         //              Type *objectType = objectDecl->get_type();
    1918         //              StructInstType *structType = dynamic_cast< StructInstType* >( objectType );
    1919         //              if ( structType ) return structType->get_baseStruct();
    1920         //              UnionInstType *unionType = dynamic_cast< UnionInstType* >( objectType );
    1921         //              if ( unionType ) return unionType->get_baseUnion();
    1922         //
    1923         //              return NULL;
    1924         //      }
    1925         //
    1926         //      /// Finds the declaration with the given name, returning decls.end() if none such
    1927         //      std::list< Declaration* >::const_iterator findDeclNamed( const std::list< Declaration* > &decls, const std::string &name ) {
    1928         //              for( std::list< Declaration* >::const_iterator decl = decls.begin(); decl != decls.end(); ++decl ) {
    1929         //                      if ( (*decl)->get_name() == name ) return decl;
    1930         //              }
    1931         //              return decls.end();
    1932         //      }
    1933         //
    1934         //      Expression* Instantiate::mutate( MemberExpr *memberExpr ) {
    1935         //              // mutate, exiting early if no longer MemberExpr
    1936         //              Expression *expr = Mutator::mutate( memberExpr );
    1937         //              memberExpr = dynamic_cast< MemberExpr* >( expr );
    1938         //              if ( ! memberExpr ) return expr;
    1939         //
    1940         //              // get declaration of member and base declaration of member, exiting early if not found
    1941         //              AggregateDecl *memberBase = getMemberBaseDecl( memberExpr );
    1942         //              if ( ! memberBase ) return memberExpr;
    1943         //              DeclarationWithType *memberDecl = memberExpr->get_member();
    1944         //              std::list< Declaration* >::const_iterator baseIt = findDeclNamed( memberBase->get_members(), memberDecl->get_name() );
    1945         //              if ( baseIt == memberBase->get_members().end() ) return memberExpr;
    1946         //              DeclarationWithType *baseDecl = dynamic_cast< DeclarationWithType* >( *baseIt );
    1947         //              if ( ! baseDecl ) return memberExpr;
    1948         //
    1949         //              // check if stated type of the member is not the type of the member's declaration; if so, need a cast
    1950         //              // this *SHOULD* be safe, I don't think anything but the void-replacements I put in for dtypes would make it past the typechecker
    1951         //              SymTab::Indexer dummy;
    1952         //              if ( ResolvExpr::typesCompatible( memberDecl->get_type(), baseDecl->get_type(), dummy ) ) return memberExpr;
    1953         //              else return new CastExpr( memberExpr, memberDecl->get_type() );
    1954         //      }
    1955 
    1956                 void GenericInstantiator::doBeginScope() {
    1957                         DeclMutator::doBeginScope();
    1958                         instantiations.beginScope();
    1959                 }
    1960 
    1961                 void GenericInstantiator::doEndScope() {
    1962                         DeclMutator::doEndScope();
    1963                         instantiations.endScope();
    1964                 }
    1965 
    19661660////////////////////////////////////////// PolyGenericCalculator ////////////////////////////////////////////////////
    19671661
     
    21071801                        findGeneric( objectType ); // ensure layout for this type is available
    21081802
     1803                        // replace member expression with dynamically-computed layout expression
    21091804                        Expression *newMemberExpr = 0;
    21101805                        if ( StructInstType *structType = dynamic_cast< StructInstType* >( objectType ) ) {
  • src/GenPoly/DeclMutator.h

    r9706554 r71a3593  
    2828        class DeclMutator : public Mutator {
    2929        public:
     30                typedef Mutator Parent;
     31
    3032                DeclMutator();
    3133                virtual ~DeclMutator();
    32                
     34
     35                using Parent::mutate;
    3336                virtual CompoundStmt* mutate(CompoundStmt *compoundStmt);
    3437                virtual Statement* mutate(IfStmt *ifStmt);
     
    4245                /// Mutates a list of declarations with this visitor
    4346                void mutateDeclarationList(std::list< Declaration* >& decls);
    44                
     47
    4548                /// Called on entry to a new scope; overriders should call this as a super-class call
    4649                virtual void doBeginScope();
  • src/GenPoly/Specialize.cc

    r9706554 r71a3593  
    3131#include "Common/UniqueName.h"
    3232#include "Common/utility.h"
     33#include "InitTweak/InitTweak.h"
    3334
    3435namespace GenPoly {
     
    184185                mutateAll( appExpr->get_args(), *this );
    185186
    186                 // create thunks for the inferred parameters
    187                 for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
    188                         inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
    189                 }
    190 
    191                 handleExplicitParams( appExpr );
     187                if ( ! InitTweak::isIntrinsicCallExpr( appExpr ) ) {
     188                        // create thunks for the inferred parameters
     189                        // don't need to do this for intrinsic calls, because they aren't actually passed
     190                        for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
     191                                inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
     192                        }
     193
     194                        handleExplicitParams( appExpr );
     195                }
    192196
    193197                return appExpr;
  • src/GenPoly/module.mk

    r9706554 r71a3593  
    2323       GenPoly/CopyParams.cc \
    2424       GenPoly/FindFunction.cc \
    25        GenPoly/DeclMutator.cc
     25       GenPoly/DeclMutator.cc \
     26       GenPoly/InstantiateGeneric.cc
  • src/InitTweak/FixGlobalInit.cc

    r9706554 r71a3593  
    4646                FunctionDecl * destroyFunction;
    4747        };
    48 
    49         class ConstExprChecker : public Visitor {
    50         public:
    51                 ConstExprChecker() : isConstExpr( true ) {}
    52 
    53                 virtual void visit( ApplicationExpr *applicationExpr ) { isConstExpr = false; }
    54                 virtual void visit( UntypedExpr *untypedExpr ) { isConstExpr = false; }
    55                 virtual void visit( NameExpr *nameExpr ) { isConstExpr = false; }
    56                 virtual void visit( CastExpr *castExpr ) { isConstExpr = false; }
    57                 virtual void visit( LabelAddressExpr *labAddressExpr ) { isConstExpr = false; }
    58                 virtual void visit( UntypedMemberExpr *memberExpr ) { isConstExpr = false; }
    59                 virtual void visit( MemberExpr *memberExpr ) { isConstExpr = false; }
    60                 virtual void visit( VariableExpr *variableExpr ) { isConstExpr = false; }
    61                 virtual void visit( ConstantExpr *constantExpr ) { /* bottom out */ }
    62                 // these might be okay?
    63                 // virtual void visit( SizeofExpr *sizeofExpr );
    64                 // virtual void visit( AlignofExpr *alignofExpr );
    65                 // virtual void visit( UntypedOffsetofExpr *offsetofExpr );
    66                 // virtual void visit( OffsetofExpr *offsetofExpr );
    67                 // virtual void visit( OffsetPackExpr *offsetPackExpr );
    68                 // virtual void visit( AttrExpr *attrExpr );
    69                 // virtual void visit( CommaExpr *commaExpr );
    70                 // virtual void visit( LogicalExpr *logicalExpr );
    71                 // virtual void visit( ConditionalExpr *conditionalExpr );
    72                 virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }
    73                 virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }
    74                 virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; }
    75                 virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; }
    76                 virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; }
    77                 virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; }
    78 
    79                 bool isConstExpr;
    80         };
    81 
    82         bool isConstExpr( Initializer * init ) {
    83                 if ( init ) {
    84                         ConstExprChecker checker;
    85                         init->accept( checker );
    86                         return checker.isConstExpr;
    87                 } // if
    88                 // for all intents and purposes, no initializer means const expr
    89                 return true;
    90         }
    9148
    9249        void fixGlobalInit( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary ) {
     
    14097                std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();
    14198
    142                 if ( ! tryConstruct( objDecl ) ) return; // don't construct @= or designated objects
    143                 if ( objDecl->get_storageClass() == DeclarationNode::Extern ) return;
    14499                // C allows you to initialize objects with constant expressions
    145100                // xxx - this is an optimization. Need to first resolve constructors before we decide
     
    147102                // if ( isConstExpr( objDecl->get_init() ) ) return;
    148103
    149                 if ( dynamic_cast< ArrayType * > ( objDecl->get_type() ) ) {
    150                         // xxx - initialize each element of the array
    151                 } else {
    152                         // steal initializer from object and attach it to a new temporary
    153                         ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, objDecl->get_type()->clone(), objDecl->get_init() );
    154                         objDecl->set_init( NULL );
    155                         initStatements.push_back( new DeclStmt( noLabels, newObj ) );
     104                if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
     105                        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     106                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    156107
    157                         // copy construct objDecl using temporary
    158                         UntypedExpr * init = new UntypedExpr( new NameExpr( "?{}" ) );
    159                         init->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    160                         init->get_args().push_back( new VariableExpr( newObj ) );
    161                         initStatements.push_back( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, init ) ) );
    162 
    163                         // add destructor calls to global destroy function
    164                         UntypedExpr * destroy = new UntypedExpr( new NameExpr( "^?{}" ) );
    165                         destroy->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    166                         destroyStatements.push_front( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, destroy ) ) );
     108                        Statement * dtor = ctorInit->get_dtor();
     109                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
     110                                // don't need to call intrinsic dtor, because it does nothing, but
     111                                // non-intrinsic dtors must be called
     112                                destroyStatements.push_front( dtor );
     113                                ctorInit->set_dtor( NULL );
     114                        } // if
     115                        if ( Statement * ctor = ctorInit->get_ctor() ) {
     116                                initStatements.push_back( ctor );
     117                                objDecl->set_init( NULL );
     118                                ctorInit->set_ctor( NULL );
     119                        } else if ( Initializer * init = ctorInit->get_init() ) {
     120                                objDecl->set_init( init );
     121                                ctorInit->set_init( NULL );
     122                        } else {
     123                                // no constructor and no initializer, which is okay
     124                                objDecl->set_init( NULL );
     125                        } // if
     126                        delete ctorInit;
    167127                } // if
    168128        }
  • src/InitTweak/FixInit.cc

    r9706554 r71a3593  
    1818#include <iterator>
    1919#include <algorithm>
     20#include "InitTweak.h"
    2021#include "FixInit.h"
    21 #include "InitTweak.h"
     22#include "FixGlobalInit.h"
    2223#include "ResolvExpr/Resolver.h"
    2324#include "ResolvExpr/typeops.h"
     
    2526#include "SynTree/Type.h"
    2627#include "SynTree/Expression.h"
     28#include "SynTree/Attribute.h"
    2729#include "SynTree/Statement.h"
    2830#include "SynTree/Initializer.h"
     
    8385                };
    8486
     87                // debug
    8588                struct printSet {
    8689                        typedef ObjDeclCollector::ObjectSet ObjectSet;
     
    159162
    160163                        virtual DeclarationWithType * mutate( ObjectDecl *objDecl );
     164
     165                        std::list< Declaration * > staticDtorDecls;
    161166                };
    162167
     
    171176        } // namespace
    172177
    173         void fix( std::list< Declaration * > & translationUnit ) {
     178        void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
     179                // fixes ConstructorInit for global variables. should happen before fixInitializers.
     180                InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
     181
    174182                InsertImplicitCalls::insert( translationUnit );
    175183                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
     
    194202                void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) {
    195203                        FixInit fixer;
    196                         mutateAll( translationUnit, fixer );
     204
     205                        // can't use mutateAll, because need to insert declarations at top-level
     206                        // can't use DeclMutator, because sometimes need to insert IfStmt, etc.
     207                        SemanticError errors;
     208                        for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
     209                                try {
     210                                        *i = maybeMutate( *i, fixer );
     211                                        translationUnit.splice( i, fixer.staticDtorDecls );
     212                                } catch( SemanticError &e ) {
     213                                        errors.append( e );
     214                                } // try
     215                        } // for
     216                        if ( ! errors.isEmpty() ) {
     217                                throw errors;
     218                        } // if
    197219                }
    198220
     
    422444                                if ( Statement * ctor = ctorInit->get_ctor() ) {
    423445                                        if ( objDecl->get_storageClass() == DeclarationNode::Static ) {
     446                                                // originally wanted to take advantage of gcc nested functions, but
     447                                                // we get memory errors with this approach. To remedy this, the static
     448                                                // variable is hoisted when the destructor needs to be called.
     449                                                //
    424450                                                // generate:
    425                                                 // static bool __objName_uninitialized = true;
    426                                                 // if (__objName_uninitialized) {
    427                                                 //   __ctor(__objName);
    428                                                 //   void dtor_atexit() {
    429                                                 //     __dtor(__objName);
     451                                                // static T __objName_static_varN;
     452                                                // void __objName_dtor_atexitN() {
     453                                                //   __dtor__...;
     454                                                // }
     455                                                // int f(...) {
     456                                                //   ...
     457                                                //   static bool __objName_uninitialized = true;
     458                                                //   if (__objName_uninitialized) {
     459                                                //     __ctor(__objName);
     460                                                //     __objName_uninitialized = false;
     461                                                //     atexit(__objName_dtor_atexitN);
    430462                                                //   }
    431                                                 //   on_exit(dtorOnExit, &__objName);
    432                                                 //   __objName_uninitialized = false;
     463                                                //   ...
    433464                                                // }
    434465
    435                                                 // generate first line
     466                                                static UniqueName dtorCallerNamer( "_dtor_atexit" );
     467
     468                                                // static bool __objName_uninitialized = true
    436469                                                BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool );
    437470                                                SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators );
     
    439472                                                isUninitializedVar->fixUniqueId();
    440473
    441                                                 // void dtor_atexit(...) {...}
    442                                                 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
    443                                                 dtorCaller->fixUniqueId();
    444                                                 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor()->clone() );
    445 
    446                                                 // on_exit(dtor_atexit);
    447                                                 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) );
    448                                                 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) );
    449 
    450474                                                // __objName_uninitialized = false;
    451475                                                UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) );
     
    457481                                                std::list< Statement * > & body = initStmts->get_kids();
    458482                                                body.push_back( ctor );
    459                                                 body.push_back( new DeclStmt( noLabels, dtorCaller ) );
    460                                                 body.push_back( new ExprStmt( noLabels, callAtexit ) );
    461483                                                body.push_back( new ExprStmt( noLabels, setTrue ) );
    462484
     
    465487                                                stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) );
    466488                                                stmtsToAddAfter.push_back( ifStmt );
     489
     490                                                if ( ctorInit->get_dtor() ) {
     491                                                        // if the object has a non-trivial destructor, have to
     492                                                        // hoist it and the object into the global space and
     493                                                        // call the destructor function with atexit.
     494
     495                                                        Statement * dtorStmt = ctorInit->get_dtor()->clone();
     496
     497                                                        // void __objName_dtor_atexitN(...) {...}
     498                                                        FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + dtorCallerNamer.newName(), DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
     499                                                        dtorCaller->fixUniqueId();
     500                                                        dtorCaller->get_statements()->get_kids().push_back( dtorStmt );
     501
     502                                                        // atexit(dtor_atexit);
     503                                                        UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) );
     504                                                        callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) );
     505
     506                                                        body.push_back( new ExprStmt( noLabels, callAtexit ) );
     507
     508                                                        // hoist variable and dtor caller decls to list of decls that will be added into global scope
     509                                                        staticDtorDecls.push_back( objDecl );
     510                                                        staticDtorDecls.push_back( dtorCaller );
     511
     512                                                        // need to rename object uniquely since it now appears
     513                                                        // at global scope and there could be multiple function-scoped
     514                                                        // static variables with the same name in different functions.
     515                                                        static UniqueName staticNamer( "_static_var" );
     516                                                        objDecl->set_mangleName( objDecl->get_mangleName() + staticNamer.newName() );
     517
     518                                                        objDecl->set_init( NULL );
     519                                                        ctorInit->set_ctor( NULL );
     520                                                        delete ctorInit;
     521
     522                                                        // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
     523                                                        // create a new object which is never used
     524                                                        static UniqueName dummyNamer( "_dummy" );
     525                                                        ObjectDecl * dummy = new ObjectDecl( dummyNamer.newName(), DeclarationNode::Static, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), 0, std::list< Attribute * >{ new Attribute("unused") } );
     526                                                        return dummy;
     527                                                }
    467528                                        } else {
    468529                                                stmtsToAddAfter.push_back( ctor );
     
    524585                                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    525586                                        Statement * dtor = ctorInit->get_dtor();
    526                                         if ( dtor && ! isInstrinsicSingleArgCallStmt( dtor ) ) {
     587                                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    527588                                                // don't need to call intrinsic dtor, because it does nothing, but
    528589                                                // non-intrinsic dtors must be called
  • src/InitTweak/FixInit.h

    r9706554 r71a3593  
    2727  /// replace constructor initializers with expression statements
    2828  /// and unwrap basic C-style initializers
    29         void fix( std::list< Declaration * > & translationUnit );
     29        void fix( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary );
    3030} // namespace
    3131
  • src/InitTweak/GenInit.cc

    r9706554 r71a3593  
    2626#include "SymTab/Autogen.h"
    2727#include "GenPoly/PolyMutator.h"
     28#include "GenPoly/DeclMutator.h"
    2829
    2930namespace InitTweak {
     
    5556          public:
    5657                /// create constructor and destructor statements for object declarations.
    57                 /// Destructors are inserted directly into the code, whereas constructors
    58                 /// will be added in after the resolver has run so that the initializer expression
    59                 /// is only removed if a constructor is found
     58                /// the actual call statements will be added in after the resolver has run
     59                /// so that the initializer expression is only removed if a constructor is found
     60                /// and the same destructor call is inserted in all of the appropriate locations.
    6061                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    61 
    62                 CtorDtor() : inFunction( false ) {}
    6362
    6463                virtual DeclarationWithType * mutate( ObjectDecl * );
    6564                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
    66                 virtual Declaration* mutate( StructDecl *aggregateDecl );
    67                 virtual Declaration* mutate( UnionDecl *aggregateDecl );
    68                 virtual Declaration* mutate( EnumDecl *aggregateDecl );
    69                 virtual Declaration* mutate( TraitDecl *aggregateDecl );
    70                 virtual TypeDecl* mutate( TypeDecl *typeDecl );
    71                 virtual Declaration* mutate( TypedefDecl *typeDecl );
    72 
    73                 virtual Type * mutate( FunctionType *funcType );
     65                // should not traverse into any of these declarations to find objects
     66                // that need to be constructed or destructed
     67                virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
     68                virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
     69                virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
     70                virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
     71                virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; }
     72                virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; }
     73
     74                virtual Type * mutate( FunctionType *funcType ) { return funcType; }
    7475
    7576          protected:
    76                 bool inFunction;
     77        };
     78
     79        class HoistArrayDimension : public GenPoly::DeclMutator {
     80          public:
     81                typedef GenPoly::DeclMutator Parent;
     82
     83                /// hoist dimension from array types in object declaration so that it uses a single
     84                /// const variable of type size_t, so that side effecting array dimensions are only
     85                /// computed once.
     86                static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
     87
     88          private:
     89                virtual DeclarationWithType * mutate( ObjectDecl * objectDecl );
     90                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
     91                // should not traverse into any of these declarations to find objects
     92                // that need to be constructed or destructed
     93                virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
     94                virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
     95                virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
     96                virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
     97                virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; }
     98                virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; }
     99
     100                virtual Type* mutate( FunctionType *funcType ) { return funcType; }
     101
     102                void hoist( Type * type );
     103
     104                DeclarationNode::StorageClass storageclass = DeclarationNode::NoStorageClass;
     105                bool inFunction = false;
    77106        };
    78107
    79108        void genInit( std::list< Declaration * > & translationUnit ) {
    80109                ReturnFixer::makeReturnTemp( translationUnit );
     110                HoistArrayDimension::hoistArrayDimension( translationUnit );
    81111                CtorDtor::generateCtorDtor( translationUnit );
    82112        }
     
    124154        }
    125155
     156        // precompute array dimension expression, because constructor generation may duplicate it,
     157        // which would be incorrect if it is a side-effecting computation.
     158        void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
     159                HoistArrayDimension hoister;
     160                hoister.mutateDeclarationList( translationUnit );
     161        }
     162
     163        DeclarationWithType * HoistArrayDimension::mutate( ObjectDecl * objectDecl ) {
     164                storageclass = objectDecl->get_storageClass();
     165                DeclarationWithType * temp = Parent::mutate( objectDecl );
     166                hoist( objectDecl->get_type() );
     167                storageclass = DeclarationNode::NoStorageClass;
     168                return temp;
     169        }
     170
     171        void HoistArrayDimension::hoist( Type * type ) {
     172                // if in function, generate const size_t var
     173                static UniqueName dimensionName( "_array_dim" );
     174
     175                // C doesn't allow variable sized arrays at global scope or for static variables,
     176                // so don't hoist dimension.
     177                if ( ! inFunction ) return;
     178                if ( storageclass == DeclarationNode::Static ) return;
     179
     180                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
     181                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
     182
     183                        // don't need to hoist dimension if it's a constexpr - only need to if there's potential
     184                        // for side effects.
     185                        if ( isConstExpr( arrayType->get_dimension() ) ) return;
     186
     187                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageclass, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
     188                        arrayDimension->get_type()->set_isConst( true );
     189
     190                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
     191                        addDeclaration( arrayDimension );
     192
     193                        hoist( arrayType->get_base() );
     194                        return;
     195                }
     196        }
     197
     198        DeclarationWithType * HoistArrayDimension::mutate( FunctionDecl *functionDecl ) {
     199                bool oldInFunc = inFunction;
     200                inFunction = true;
     201                DeclarationWithType * decl = Parent::mutate( functionDecl );
     202                inFunction = oldInFunc;
     203                return decl;
     204        }
    126205
    127206        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
     
    130209        }
    131210
    132         namespace {
    133                 Expression * makeCtorDtorExpr( std::string name, ObjectDecl * objDecl, std::list< Expression * > args ) {
    134                         UntypedExpr * expr = new UntypedExpr( new NameExpr( name ) );
    135                         expr->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    136                         expr->get_args().splice( expr->get_args().end(), args );
    137                         return expr;
    138                 }
    139         }
    140 
    141211        DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {
    142                 // hands off if designated or if @=
     212                // hands off if designated, if @=, or if extern
    143213                if ( tryConstruct( objDecl ) ) {
    144                         if ( inFunction ) {
    145                                 if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
    146                                         // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
    147                                         // TODO: walk initializer and generate appropriate copy ctor if element has initializer
    148                                         std::list< Expression * > args = makeInitList( objDecl->get_init() );
    149                                         if ( args.empty() ) {
    150                                                 std::list< Statement * > ctor;
    151                                                 std::list< Statement * > dtor;
    152 
    153                                                 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "?{}", back_inserter( ctor ) );
    154                                                 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "^?{}", front_inserter( dtor ), false );
    155 
    156                                                 // Currently makeArrayFunction produces a single Statement - a CompoundStmt
    157                                                 // which  wraps everything that needs to happen. As such, it's technically
    158                                                 // possible to use a Statement ** in the above calls, but this is inherently
    159                                                 // unsafe, so instead we take the slightly less efficient route, but will be
    160                                                 // immediately informed if somehow the above assumption is broken. In this case,
    161                                                 // we could always wrap the list of statements at this point with a CompoundStmt,
    162                                                 // but it seems reasonable at the moment for this to be done by makeArrayFunction
    163                                                 // itself
    164                                                 assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) );
    165                                                 assert( dtor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( dtor.front() ) );
    166                                                 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    167                                         } else {
    168                                                 // array came with an initializer list: initialize each element
    169                                                 // may have more initializers than elements in the array - need to check at each index that
    170                                                 // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
    171                                                 // computation.
    172                                                 // may have fewer initializers than eleemnts in the array - need to default construct
    173                                                 // remaining elements.
    174                                                 // might be able to merge this with the case above.
    175                                         }
    176                                 } else {
    177                                         // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
    178                                         Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
    179                                         Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
    180 
    181                                         // need to remember init expression, in case no ctors exist
    182                                         // if ctor does exist, want to use ctor expression instead of init
    183                                         // push this decision to the resolver
    184                                         ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
    185                                         ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
    186                                         objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
    187                                 }
     214                        // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     215                        // for each constructable object
     216                        std::list< Statement * > ctor;
     217                        std::list< Statement * > dtor;
     218
     219                        InitExpander srcParam( objDecl->get_init() );
     220                        InitExpander nullParam( (Initializer *)NULL );
     221                        SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     222                        SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     223
     224                        // Currently genImplicitCall produces a single Statement - a CompoundStmt
     225                        // which  wraps everything that needs to happen. As such, it's technically
     226                        // possible to use a Statement ** in the above calls, but this is inherently
     227                        // unsafe, so instead we take the slightly less efficient route, but will be
     228                        // immediately informed if somehow the above assumption is broken. In this case,
     229                        // we could always wrap the list of statements at this point with a CompoundStmt,
     230                        // but it seems reasonable at the moment for this to be done by genImplicitCall
     231                        // itself. It is possible that genImplicitCall produces no statements (e.g. if
     232                        // an array type does not have a dimension). In this case, it's fine to ignore
     233                        // the object for the purposes of construction.
     234                        assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     235                        if ( ctor.size() == 1 ) {
     236                                // need to remember init expression, in case no ctors exist
     237                                // if ctor does exist, want to use ctor expression instead of init
     238                                // push this decision to the resolver
     239                                assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
     240                                objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    188241                        }
    189242                }
     
    193246        DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) {
    194247                // parameters should not be constructed and destructed, so don't mutate FunctionType
    195                 bool oldInFunc = inFunction;
    196248                mutateAll( functionDecl->get_oldDecls(), *this );
    197                 inFunction = true;
    198249                functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
    199                 inFunction = oldInFunc;
    200250                return functionDecl;
    201251        }
    202 
    203         // should not traverse into any of these declarations to find objects
    204         // that need to be constructed or destructed
    205         Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
    206         Declaration* CtorDtor::mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
    207         Declaration* CtorDtor::mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
    208         Declaration* CtorDtor::mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
    209         TypeDecl* CtorDtor::mutate( TypeDecl *typeDecl ) { return typeDecl; }
    210         Declaration* CtorDtor::mutate( TypedefDecl *typeDecl ) { return typeDecl; }
    211         Type* CtorDtor::mutate( FunctionType *funcType ) { return funcType; }
    212 
    213252} // namespace InitTweak
    214253
  • src/InitTweak/InitTweak.cc

    r9706554 r71a3593  
     1#include <algorithm>
    12#include "InitTweak.h"
    23#include "SynTree/Visitor.h"
     
    45#include "SynTree/Initializer.h"
    56#include "SynTree/Expression.h"
     7#include "SynTree/Attribute.h"
    68#include "GenPoly/GenPoly.h"
    79
     
    2022                };
    2123
    22                 class InitExpander : public Visitor {
     24                class InitFlattener : public Visitor {
    2325                        public:
    24                         InitExpander() {}
    2526                        virtual void visit( SingleInit * singleInit );
    2627                        virtual void visit( ListInit * listInit );
     
    2829                };
    2930
    30                 void InitExpander::visit( SingleInit * singleInit ) {
     31                void InitFlattener::visit( SingleInit * singleInit ) {
    3132                        argList.push_back( singleInit->get_value()->clone() );
    3233                }
    3334
    34                 void InitExpander::visit( ListInit * listInit ) {
    35                         // xxx - for now, assume no nested list inits
    36                         std::list<Initializer*>::iterator it = listInit->begin_initializers();
    37                         for ( ; it != listInit->end_initializers(); ++it ) {
     35                void InitFlattener::visit( ListInit * listInit ) {
     36                        // flatten nested list inits
     37                        std::list<Initializer*>::iterator it = listInit->begin();
     38                        for ( ; it != listInit->end(); ++it ) {
    3839                                (*it)->accept( *this );
    3940                        }
     
    4243
    4344        std::list< Expression * > makeInitList( Initializer * init ) {
    44                 InitExpander expander;
    45                 maybeAccept( init, expander );
    46                 return expander.argList;
     45                InitFlattener flattener;
     46                maybeAccept( init, flattener );
     47                return flattener.argList;
    4748        }
    4849
     
    5354        }
    5455
     56        class InitExpander::ExpanderImpl {
     57        public:
     58                virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
     59                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
     60        };
     61
     62        class InitImpl : public InitExpander::ExpanderImpl {
     63        public:
     64                InitImpl( Initializer * init ) : init( init ) {}
     65
     66                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
     67                        // this is wrong, but just a placeholder for now
     68                        // if ( ! flattened ) flatten( indices );
     69                        // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
     70                        return makeInitList( init );
     71                }
     72
     73                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
     74        private:
     75                Initializer * init;
     76        };
     77
     78        class ExprImpl : public InitExpander::ExpanderImpl {
     79        public:
     80                ExprImpl( Expression * expr ) : arg( expr ) {}
     81
     82                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
     83                        std::list< Expression * > ret;
     84                        Expression * expr = maybeClone( arg );
     85                        if ( expr ) {
     86                                for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {
     87                                        // go through indices and layer on subscript exprs ?[?]
     88                                        ++it;
     89                                        UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );
     90                                        subscriptExpr->get_args().push_back( expr );
     91                                        subscriptExpr->get_args().push_back( (*it)->clone() );
     92                                        expr = subscriptExpr;
     93                                }
     94                                ret.push_back( expr );
     95                        }
     96                        return ret;
     97                }
     98
     99                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
     100        private:
     101                Expression * arg;
     102        };
     103
     104        InitExpander::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {}
     105
     106        InitExpander::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {}
     107
     108        std::list< Expression * > InitExpander::operator*() {
     109                return cur;
     110        }
     111
     112        InitExpander & InitExpander::operator++() {
     113                cur = expander->next( indices );
     114                return *this;
     115        }
     116
     117        // use array indices list to build switch statement
     118        void InitExpander::addArrayIndex( Expression * index, Expression * dimension ) {
     119                indices.push_back( index );
     120                indices.push_back( dimension );
     121        }
     122
     123        void InitExpander::clearArrayIndices() {
     124                indices.clear();
     125        }
     126
     127        namespace {
     128                /// given index i, dimension d, initializer init, and callExpr f, generates
     129                ///   if (i < d) f(..., init)
     130                ///   ++i;
     131                /// so that only elements within the range of the array are constructed
     132                template< typename OutIterator >
     133                void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
     134                        UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
     135                        cond->get_args().push_back( index->clone() );
     136                        cond->get_args().push_back( dimension->clone() );
     137
     138                        std::list< Expression * > args = makeInitList( init );
     139                        callExpr->get_args().splice( callExpr->get_args().end(), args );
     140
     141                        *out++ = new IfStmt( noLabels, cond, new ExprStmt( noLabels, callExpr ), NULL );
     142
     143                        UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
     144                        increment->get_args().push_back( new AddressExpr( index->clone() ) );
     145                        *out++ = new ExprStmt( noLabels, increment );
     146                }
     147
     148                template< typename OutIterator >
     149                void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
     150                        if ( idx == idxEnd ) return;
     151                        Expression * index = *idx++;
     152                        assert( idx != idxEnd );
     153                        Expression * dimension = *idx++;
     154
     155                        // xxx - may want to eventually issue a warning here if we can detect
     156                        // that the number of elements exceeds to dimension of the array
     157                        if ( idx == idxEnd ) {
     158                                if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
     159                                        for ( Initializer * init : *listInit ) {
     160                                                buildCallExpr( callExpr->clone(), index, dimension, init, out );
     161                                        }
     162                                } else {
     163                                        buildCallExpr( callExpr->clone(), index, dimension, init, out );
     164                                }
     165                        } else {
     166                                std::list< Statement * > branches;
     167
     168                                unsigned long cond = 0;
     169                                ListInit * listInit = dynamic_cast< ListInit * >( init );
     170                                if ( ! listInit ) {
     171                                        // xxx - this shouldn't be an error, but need a way to
     172                                        // terminate without creating output, so should catch this error
     173                                        throw SemanticError( "unbalanced list initializers" );
     174                                }
     175
     176                                static UniqueName targetLabel( "L__autogen__" );
     177                                Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );
     178                                for ( Initializer * init : *listInit ) {
     179                                        Expression * condition;
     180                                        // check for designations
     181                                        // if ( init-> ) {
     182                                                condition = new ConstantExpr( Constant::from_ulong( cond ) );
     183                                                ++cond;
     184                                        // } else {
     185                                        //      condition = // ... take designation
     186                                        //      cond = // ... take designation+1
     187                                        // }
     188                                        std::list< Statement * > stmts;
     189                                        build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
     190                                        stmts.push_back( new BranchStmt( noLabels, switchLabel, BranchStmt::Break ) );
     191                                        CaseStmt * caseStmt = new CaseStmt( noLabels, condition, stmts );
     192                                        branches.push_back( caseStmt );
     193                                }
     194                                *out++ = new SwitchStmt( noLabels, index->clone(), branches );
     195                                *out++ = new NullStmt( std::list<Label>{ switchLabel } );
     196                        }
     197                }
     198        }
     199
     200        // if array came with an initializer list: initialize each element
     201        // may have more initializers than elements in the array - need to check at each index that
     202        // we haven't exceeded size.
     203        // may have fewer initializers than elements in the array - need to default construct
     204        // remaining elements.
     205        // To accomplish this, generate switch statement, consuming all of expander's elements
     206        Statement * InitImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     207                if ( ! init ) return NULL;
     208                CompoundStmt * block = new CompoundStmt( noLabels );
     209                build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );
     210                if ( block->get_kids().empty() ) {
     211                        delete block;
     212                        return NULL;
     213                } else {
     214                        init = NULL; // init was consumed in creating the list init
     215                        return block;
     216                }
     217        }
     218
     219        Statement * ExprImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     220                return NULL;
     221        }
     222
     223        Statement * InitExpander::buildListInit( UntypedExpr * dst ) {
     224                return expander->buildListInit( dst, indices );
     225        }
     226
    55227        bool tryConstruct( ObjectDecl * objDecl ) {
    56228                return ! LinkageSpec::isBuiltin( objDecl->get_linkage() ) &&
    57229                        (objDecl->get_init() == NULL ||
    58230                                ( objDecl->get_init() != NULL && objDecl->get_init()->get_maybeConstructed() )) &&
    59                         ! isDesignated( objDecl->get_init() );
     231                        ! isDesignated( objDecl->get_init() )
     232                        && objDecl->get_storageClass() != DeclarationNode::Extern;
     233        }
     234
     235        class CallFinder : public Visitor {
     236        public:
     237                typedef Visitor Parent;
     238                CallFinder( const std::list< std::string > & names ) : names( names ) {}
     239
     240                virtual void visit( ApplicationExpr * appExpr ) {
     241                        handleCallExpr( appExpr );
     242                }
     243
     244                virtual void visit( UntypedExpr * untypedExpr ) {
     245                        handleCallExpr( untypedExpr );
     246                }
     247
     248                std::list< Expression * > * matches;
     249        private:
     250                const std::list< std::string > names;
     251
     252                template< typename CallExpr >
     253                void handleCallExpr( CallExpr * expr ) {
     254                        Parent::visit( expr );
     255                        std::string fname = getFunctionName( expr );
     256                        if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
     257                                matches->push_back( expr );
     258                        }
     259                }
     260        };
     261
     262        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
     263                static CallFinder finder( std::list< std::string >{ "?{}", "^?{}" } );
     264                finder.matches = &matches;
     265                maybeAccept( stmt, finder );
    60266        }
    61267
    62268        Expression * getCtorDtorCall( Statement * stmt ) {
    63                 if ( stmt == NULL ) return NULL;
    64                 if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) {
    65                         return exprStmt->get_expr();
    66                 } else if ( CompoundStmt * compoundStmt = dynamic_cast< CompoundStmt * >( stmt ) ) {
    67                         // could also be a compound statement with a loop, in the case of an array
    68                         if( compoundStmt->get_kids().size() == 2 ) {
    69                                 // loop variable and loop
    70                                 ForStmt * forStmt = dynamic_cast< ForStmt * >( compoundStmt->get_kids().back() );
    71                                 assert( forStmt && forStmt->get_body() );
    72                                 return getCtorDtorCall( forStmt->get_body() );
    73                         } else if ( compoundStmt->get_kids().size() == 1 ) {
    74                                 // should be the call statement, but in any case there's only one option
    75                                 return getCtorDtorCall( compoundStmt->get_kids().front() );
    76                         } else {
    77                                 assert( false && "too many statements in compoundStmt for getCtorDtorCall" );
    78                         }
    79                 } if ( ImplicitCtorDtorStmt * impCtorDtorStmt = dynamic_cast< ImplicitCtorDtorStmt * > ( stmt ) ) {
    80                         return getCtorDtorCall( impCtorDtorStmt->get_callStmt() );
    81                 } else {
    82                         // should never get here
    83                         assert( false && "encountered unknown call statement" );
    84                 }
    85         }
    86 
    87         bool isInstrinsicSingleArgCallStmt( Statement * stmt ) {
    88                 Expression * callExpr = getCtorDtorCall( stmt );
    89                 if ( ! callExpr ) return false;
    90                 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr );
    91                 assert( appExpr );
    92                 VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() );
     269                std::list< Expression * > matches;
     270                collectCtorDtorCalls( stmt, matches );
     271                assert( matches.size() <= 1 );
     272                return matches.size() == 1 ? matches.front() : NULL;
     273        }
     274
     275        namespace {
     276                VariableExpr * getCalledFunction( ApplicationExpr * appExpr ) {
     277                        assert( appExpr );
     278                        // xxx - it's possible this can be other things, e.g. MemberExpr, so this is insufficient
     279                        return dynamic_cast< VariableExpr * >( appExpr->get_function() );
     280                }
     281        }
     282
     283        ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {
     284                ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );
     285                if ( ! appExpr ) return NULL;
     286                VariableExpr * function = getCalledFunction( appExpr );
    93287                assert( function );
    94288                // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
    95289                // will call all member dtors, and some members may have a user defined dtor.
    96                 FunctionType * funcType = GenPoly::getFunctionType( function->get_var()->get_type() );
    97                 assert( funcType );
    98                 return function->get_var()->get_linkage() == LinkageSpec::Intrinsic && funcType->get_parameters().size() == 1;
     290                return function->get_var()->get_linkage() == LinkageSpec::Intrinsic ? appExpr : NULL;
     291        }
     292
     293        bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
     294                std::list< Expression * > callExprs;
     295                collectCtorDtorCalls( stmt, callExprs );
     296                // if ( callExprs.empty() ) return false; // xxx - do I still need this check?
     297                return std::all_of( callExprs.begin(), callExprs.end(), []( Expression * callExpr ){
     298                        if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
     299                                assert( ! appExpr->get_function()->get_results().empty() );
     300                                FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() );
     301                                assert( funcType );
     302                                return funcType->get_parameters().size() == 1;
     303                        }
     304                        return false;
     305                });
    99306        }
    100307
     
    160367                else return NULL;
    161368        }
     369
     370        class ConstExprChecker : public Visitor {
     371        public:
     372                ConstExprChecker() : isConstExpr( true ) {}
     373
     374                virtual void visit( ApplicationExpr *applicationExpr ) { isConstExpr = false; }
     375                virtual void visit( UntypedExpr *untypedExpr ) { isConstExpr = false; }
     376                virtual void visit( NameExpr *nameExpr ) { isConstExpr = false; }
     377                virtual void visit( CastExpr *castExpr ) { isConstExpr = false; }
     378                virtual void visit( LabelAddressExpr *labAddressExpr ) { isConstExpr = false; }
     379                virtual void visit( UntypedMemberExpr *memberExpr ) { isConstExpr = false; }
     380                virtual void visit( MemberExpr *memberExpr ) { isConstExpr = false; }
     381                virtual void visit( VariableExpr *variableExpr ) { isConstExpr = false; }
     382                virtual void visit( ConstantExpr *constantExpr ) { /* bottom out */ }
     383                // these might be okay?
     384                // virtual void visit( SizeofExpr *sizeofExpr );
     385                // virtual void visit( AlignofExpr *alignofExpr );
     386                // virtual void visit( UntypedOffsetofExpr *offsetofExpr );
     387                // virtual void visit( OffsetofExpr *offsetofExpr );
     388                // virtual void visit( OffsetPackExpr *offsetPackExpr );
     389                // virtual void visit( AttrExpr *attrExpr );
     390                // virtual void visit( CommaExpr *commaExpr );
     391                // virtual void visit( LogicalExpr *logicalExpr );
     392                // virtual void visit( ConditionalExpr *conditionalExpr );
     393                virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }
     394                virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }
     395                virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; }
     396                virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; }
     397                virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; }
     398                virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; }
     399
     400                bool isConstExpr;
     401        };
     402
     403        bool isConstExpr( Expression * expr ) {
     404                if ( expr ) {
     405                        ConstExprChecker checker;
     406                        expr->accept( checker );
     407                        return checker.isConstExpr;
     408                }
     409                return true;
     410        }
     411
     412        bool isConstExpr( Initializer * init ) {
     413                if ( init ) {
     414                        ConstExprChecker checker;
     415                        init->accept( checker );
     416                        return checker.isConstExpr;
     417                } // if
     418                // for all intents and purposes, no initializer means const expr
     419                return true;
     420        }
     421
    162422}
  • src/InitTweak/InitTweak.h

    r9706554 r71a3593  
    2626// helper functions for initialization
    2727namespace InitTweak {
    28   /// transform Initializer into an argument list that can be passed to a call expression
    29   std::list< Expression * > makeInitList( Initializer * init );
     28        /// transform Initializer into an argument list that can be passed to a call expression
     29        std::list< Expression * > makeInitList( Initializer * init );
    3030
    31   /// True if the resolver should try to construct objDecl
    32   bool tryConstruct( ObjectDecl * objDecl );
     31        /// True if the resolver should try to construct objDecl
     32        bool tryConstruct( ObjectDecl * objDecl );
    3333
    34   /// True if the Initializer contains designations
    35   bool isDesignated( Initializer * init );
     34        /// True if the Initializer contains designations
     35        bool isDesignated( Initializer * init );
    3636
    37   /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    38   /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    39   /// Currently has assertions that make it less than fully general.
    40   bool isInstrinsicSingleArgCallStmt( Statement * expr );
     37  /// Non-Null if expr is a call expression whose target function is intrinsic
     38  ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
    4139
    42   /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
    43   Expression * getCtorDtorCall( Statement * stmt );
     40        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
     41        /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
     42        /// Currently has assertions that make it less than fully general.
     43        bool isIntrinsicSingleArgCallStmt( Statement * expr );
    4444
    45   /// returns the name of the function being called
    46   std::string getFunctionName( Expression * expr );
     45        /// get all Ctor/Dtor call expressions from a Statement
     46        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    4747
    48   /// returns the argument to a call expression in position N indexed from 0
    49   Expression *& getCallArg( Expression * callExpr, unsigned int pos );
     48        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     49        Expression * getCtorDtorCall( Statement * stmt );
    5050
    51   /// returns the base type of a PointerType or ArrayType, else returns NULL
    52   Type * getPointerBase( Type * );
     51        /// returns the name of the function being called
     52        std::string getFunctionName( Expression * expr );
    5353
    54   /// returns the argument if it is a PointerType or ArrayType, else returns NULL
    55   Type * isPointerType( Type * );
     54        /// returns the argument to a call expression in position N indexed from 0
     55        Expression *& getCallArg( Expression * callExpr, unsigned int pos );
     56
     57        /// returns the base type of a PointerType or ArrayType, else returns NULL
     58        Type * getPointerBase( Type * );
     59
     60        /// returns the argument if it is a PointerType or ArrayType, else returns NULL
     61        Type * isPointerType( Type * );
     62
     63        /// returns true if expr is trivially a compile-time constant
     64        bool isConstExpr( Expression * expr );
     65        bool isConstExpr( Initializer * init );
     66
     67        class InitExpander {
     68        public:
     69                // expand by stepping through init to get each list of arguments
     70                InitExpander( Initializer * init );
     71
     72                // always expand to expr
     73                InitExpander( Expression * expr );
     74
     75                // iterator-like interface
     76                std::list< Expression * > operator*();
     77                InitExpander & operator++();
     78
     79                // builds statement which has the same semantics as a C-style list initializer
     80                // (for array initializers) using callExpr as the base expression to perform initialization
     81                Statement * buildListInit( UntypedExpr * callExpr );
     82                void addArrayIndex( Expression * index, Expression * dimension );
     83                void clearArrayIndices();
     84
     85                class ExpanderImpl;
     86        private:
     87                std::shared_ptr< ExpanderImpl > expander;
     88                std::list< Expression * > cur;
     89
     90                // invariant: list of size 2N (elements come in pairs [index, dimension])
     91                typedef std::list< Expression * > IndexList;
     92                IndexList indices;
     93        };
    5694} // namespace
    5795
  • src/Makefile.in

    r9706554 r71a3593  
    121121        GenPoly/driver_cfa_cpp-FindFunction.$(OBJEXT) \
    122122        GenPoly/driver_cfa_cpp-DeclMutator.$(OBJEXT) \
     123        GenPoly/driver_cfa_cpp-InstantiateGeneric.$(OBJEXT) \
    123124        InitTweak/driver_cfa_cpp-GenInit.$(OBJEXT) \
    124125        InitTweak/driver_cfa_cpp-FixInit.$(OBJEXT) \
     
    377378        GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc GenPoly/Specialize.cc \
    378379        GenPoly/CopyParams.cc GenPoly/FindFunction.cc \
    379         GenPoly/DeclMutator.cc InitTweak/GenInit.cc \
    380         InitTweak/FixInit.cc InitTweak/FixGlobalInit.cc \
    381         InitTweak/InitTweak.cc Parser/parser.yy Parser/lex.ll \
    382         Parser/TypedefTable.cc Parser/ParseNode.cc \
    383         Parser/DeclarationNode.cc Parser/ExpressionNode.cc \
    384         Parser/StatementNode.cc Parser/InitializerNode.cc \
    385         Parser/TypeData.cc Parser/LinkageSpec.cc \
    386         Parser/parseutility.cc Parser/Parser.cc \
     380        GenPoly/DeclMutator.cc GenPoly/InstantiateGeneric.cc \
     381        InitTweak/GenInit.cc InitTweak/FixInit.cc \
     382        InitTweak/FixGlobalInit.cc InitTweak/InitTweak.cc \
     383        Parser/parser.yy Parser/lex.ll Parser/TypedefTable.cc \
     384        Parser/ParseNode.cc Parser/DeclarationNode.cc \
     385        Parser/ExpressionNode.cc Parser/StatementNode.cc \
     386        Parser/InitializerNode.cc Parser/TypeData.cc \
     387        Parser/LinkageSpec.cc Parser/parseutility.cc Parser/Parser.cc \
    387388        ResolvExpr/AlternativeFinder.cc ResolvExpr/Alternative.cc \
    388389        ResolvExpr/Unify.cc ResolvExpr/PtrsAssignable.cc \
     
    585586GenPoly/driver_cfa_cpp-DeclMutator.$(OBJEXT): GenPoly/$(am__dirstamp) \
    586587        GenPoly/$(DEPDIR)/$(am__dirstamp)
     588GenPoly/driver_cfa_cpp-InstantiateGeneric.$(OBJEXT):  \
     589        GenPoly/$(am__dirstamp) GenPoly/$(DEPDIR)/$(am__dirstamp)
    587590InitTweak/$(am__dirstamp):
    588591        @$(MKDIR_P) InitTweak
     
    828831        -rm -f GenPoly/driver_cfa_cpp-FindFunction.$(OBJEXT)
    829832        -rm -f GenPoly/driver_cfa_cpp-GenPoly.$(OBJEXT)
     833        -rm -f GenPoly/driver_cfa_cpp-InstantiateGeneric.$(OBJEXT)
    830834        -rm -f GenPoly/driver_cfa_cpp-Lvalue.$(OBJEXT)
    831835        -rm -f GenPoly/driver_cfa_cpp-PolyMutator.$(OBJEXT)
     
    937941@AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-FindFunction.Po@am__quote@
    938942@AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-GenPoly.Po@am__quote@
     943@AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Po@am__quote@
    939944@AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-Lvalue.Po@am__quote@
    940945@AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-PolyMutator.Po@am__quote@
     
    13881393@am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o GenPoly/driver_cfa_cpp-DeclMutator.obj `if test -f 'GenPoly/DeclMutator.cc'; then $(CYGPATH_W) 'GenPoly/DeclMutator.cc'; else $(CYGPATH_W) '$(srcdir)/GenPoly/DeclMutator.cc'; fi`
    13891394
     1395GenPoly/driver_cfa_cpp-InstantiateGeneric.o: GenPoly/InstantiateGeneric.cc
     1396@am__fastdepCXX_TRUE@   $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT GenPoly/driver_cfa_cpp-InstantiateGeneric.o -MD -MP -MF GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.o `test -f 'GenPoly/InstantiateGeneric.cc' || echo '$(srcdir)/'`GenPoly/InstantiateGeneric.cc
     1397@am__fastdepCXX_TRUE@   $(AM_V_at)$(am__mv) GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Po
     1398@AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='GenPoly/InstantiateGeneric.cc' object='GenPoly/driver_cfa_cpp-InstantiateGeneric.o' libtool=no @AMDEPBACKSLASH@
     1399@AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
     1400@am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.o `test -f 'GenPoly/InstantiateGeneric.cc' || echo '$(srcdir)/'`GenPoly/InstantiateGeneric.cc
     1401
     1402GenPoly/driver_cfa_cpp-InstantiateGeneric.obj: GenPoly/InstantiateGeneric.cc
     1403@am__fastdepCXX_TRUE@   $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT GenPoly/driver_cfa_cpp-InstantiateGeneric.obj -MD -MP -MF GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.obj `if test -f 'GenPoly/InstantiateGeneric.cc'; then $(CYGPATH_W) 'GenPoly/InstantiateGeneric.cc'; else $(CYGPATH_W) '$(srcdir)/GenPoly/InstantiateGeneric.cc'; fi`
     1404@am__fastdepCXX_TRUE@   $(AM_V_at)$(am__mv) GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Po
     1405@AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='GenPoly/InstantiateGeneric.cc' object='GenPoly/driver_cfa_cpp-InstantiateGeneric.obj' libtool=no @AMDEPBACKSLASH@
     1406@AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
     1407@am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.obj `if test -f 'GenPoly/InstantiateGeneric.cc'; then $(CYGPATH_W) 'GenPoly/InstantiateGeneric.cc'; else $(CYGPATH_W) '$(srcdir)/GenPoly/InstantiateGeneric.cc'; fi`
     1408
    13901409InitTweak/driver_cfa_cpp-GenInit.o: InitTweak/GenInit.cc
    13911410@am__fastdepCXX_TRUE@   $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT InitTweak/driver_cfa_cpp-GenInit.o -MD -MP -MF InitTweak/$(DEPDIR)/driver_cfa_cpp-GenInit.Tpo -c -o InitTweak/driver_cfa_cpp-GenInit.o `test -f 'InitTweak/GenInit.cc' || echo '$(srcdir)/'`InitTweak/GenInit.cc
  • src/Parser/ExpressionNode.cc

    r9706554 r71a3593  
    529529//##############################################################################
    530530
    531 CommaExprNode::CommaExprNode(): CompositeExprNode( new OperatorNode( OperatorNode::Comma )) {}
    532 
    533 CommaExprNode::CommaExprNode( ExpressionNode *exp ) : CompositeExprNode( new OperatorNode( OperatorNode::Comma ), exp ) {
    534 }
    535 
    536 CommaExprNode::CommaExprNode( ExpressionNode *exp1, ExpressionNode *exp2) : CompositeExprNode( new OperatorNode( OperatorNode::Comma ), exp1, exp2) {
    537 }
    538 
    539 // CommaExprNode *CommaExprNode::add_to_list( ExpressionNode *exp ) {
    540 //      add_arg( exp );
    541 //
    542 //      return this;
    543 // }
    544 
    545 CommaExprNode::CommaExprNode( const CommaExprNode &other ) : CompositeExprNode( other ) {
    546 }
    547 
    548 //##############################################################################
    549 
    550531ValofExprNode::ValofExprNode( StatementNode *s ): body( s ) {}
    551532
  • src/Parser/ParseNode.h

    r9706554 r71a3593  
    324324  private:
    325325        std::list< Label > labels;
    326 };
    327 
    328 class CommaExprNode : public CompositeExprNode {
    329   public:
    330         CommaExprNode();
    331         CommaExprNode( ExpressionNode * );
    332         CommaExprNode( ExpressionNode *, ExpressionNode * );
    333         CommaExprNode( const CommaExprNode &other );
    334 
    335         // virtual CommaExprNode *add_to_list( ExpressionNode * );
    336         virtual CommaExprNode *clone() const { return new CommaExprNode( *this ); }
    337326};
    338327
     
    567556};
    568557
    569 class NullStmtNode : public CompoundStmtNode {
    570   public:
    571         Statement *build() const;
    572         void print( std::ostream &, int indent = 0 ) const;
    573 };
    574 
    575558class InitializerNode : public ParseNode {
    576559  public:
  • src/Parser/StatementNode.cc

    r9706554 r71a3593  
    417417}
    418418
    419 
    420 void NullStmtNode::print( ostream &os, int indent ) const {
    421         os << string( indent, ' ' ) << "Null Statement:" << endl;
    422 }
    423 
    424 Statement *NullStmtNode::build() const {
    425         return new NullStmt;
    426 }
    427 
    428419// Local Variables: //
    429420// tab-width: 4 //
  • src/Parser/TypeData.cc

    r9706554 r71a3593  
    510510                return buildVariable();
    511511        } else {
    512                 return new ObjectDecl( name, sc, linkage, bitfieldWidth, build(), init, isInline, isNoreturn );
     512                return new ObjectDecl( name, sc, linkage, bitfieldWidth, build(), init, std::list< Attribute * >(),  isInline, isNoreturn );
    513513        } // if
    514514        return 0;
  • src/ResolvExpr/Resolver.cc

    r9706554 r71a3593  
    2424#include "SynTree/Initializer.h"
    2525#include "SymTab/Indexer.h"
     26#include "SymTab/Autogen.h"
    2627#include "Common/utility.h"
    2728#include "InitTweak/InitTweak.h"
     
    4142
    4243                virtual void visit( ArrayType * at );
     44                virtual void visit( PointerType * at );
    4345
    4446                virtual void visit( ExprStmt *exprStmt );
     
    5254                virtual void visit( BranchStmt *branchStmt );
    5355                virtual void visit( ReturnStmt *returnStmt );
    54                 virtual void visit( ImplicitCtorDtorStmt * impCtorDtorStmt );
    5556
    5657                virtual void visit( SingleInit *singleInit );
     
    5960          private:
    6061        typedef std::list< Initializer * >::iterator InitIterator;
     62
     63                template< typename PtrType >
     64                void handlePtrType( PtrType * type );
    6165
    6266          void resolveAggrInit( AggregateDecl *, InitIterator &, InitIterator & );
     
    192196        }
    193197
     198        template< typename PtrType >
     199        void Resolver::handlePtrType( PtrType * type ) {
     200                if ( type->get_dimension() ) {
     201                        CastExpr *castExpr = new CastExpr( type->get_dimension(), SymTab::SizeType->clone() );
     202                        Expression *newExpr = findSingleExpression( castExpr, *this );
     203                        delete type->get_dimension();
     204                        type->set_dimension( newExpr );
     205                }
     206        }
     207
    194208        void Resolver::visit( ArrayType * at ) {
    195                 if ( at->get_dimension() ) {
    196                         BasicType arrayLenType = BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
    197                         CastExpr *castExpr = new CastExpr( at->get_dimension(), arrayLenType.clone() );
    198                         Expression *newExpr = findSingleExpression( castExpr, *this );
    199                         delete at->get_dimension();
    200                         at->set_dimension( newExpr );
    201                 }
     209                handlePtrType( at );
    202210                Visitor::visit( at );
     211        }
     212
     213        void Resolver::visit( PointerType * pt ) {
     214                handlePtrType( pt );
     215                Visitor::visit( pt );
    203216        }
    204217
     
    422435
    423436        void Resolver::visit( ListInit * listInit ) {
    424                 InitIterator iter = listInit->begin_initializers();
    425                 InitIterator end = listInit->end_initializers();
     437                InitIterator iter = listInit->begin();
     438                InitIterator end = listInit->end();
    426439
    427440                if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {
     
    521534                // implicitly generated, there's no way for it to have side effects, so get rid of it
    522535                // to clean up generated code.
    523                 if ( InitTweak::isInstrinsicSingleArgCallStmt( ctorInit->get_ctor() ) ) {
     536                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->get_ctor() ) ) {
    524537                        delete ctorInit->get_ctor();
    525538                        ctorInit->set_ctor( NULL );
    526539                }
    527                 if ( InitTweak::isInstrinsicSingleArgCallStmt( ctorInit->get_ctor() ) ) {
     540
     541                // xxx - todo
     542                // if ( InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
     543                //      // can reduce the constructor down to a SingleInit using the
     544                //      // second argument from the ctor call
     545                // }
     546
     547                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->get_dtor() ) ) {
    528548                        delete ctorInit->get_dtor();
    529549                        ctorInit->set_dtor( NULL );
    530550                }
    531         }
    532 
    533         void Resolver::visit( ImplicitCtorDtorStmt * impCtorDtorStmt ) {
    534                 // before resolving ctor/dtor, need to remove type qualifiers from the first argument (the object being constructed).
    535                 // Do this through a cast expression to greatly simplify the code.
    536                 Expression * callExpr = InitTweak::getCtorDtorCall( impCtorDtorStmt );
    537                 assert( callExpr );
    538                 Expression *& constructee = InitTweak::getCallArg( callExpr, 0 );
    539                 Type * type = 0;
    540 
    541                 // need to find the type of the first argument, which is unfortunately not uniform since array construction
    542                 // includes an untyped '+' expression.
    543                 if ( UntypedExpr * plusExpr = dynamic_cast< UntypedExpr * >( constructee ) ) {
    544                         // constructee is <array>+<index>
    545                         // get Variable <array>, then get the base type of the VariableExpr - this is the type that needs to be fixed
    546                         Expression * arr = InitTweak::getCallArg( plusExpr, 0 );
    547                         assert( dynamic_cast< VariableExpr * >( arr ) || dynamic_cast< MemberExpr *>( arr ) );
    548                         assert( arr && arr->get_results().size() == 1 );
    549                         type = arr->get_results().front()->clone();
    550                 } else {
    551                         // otherwise, constructing a plain object, which means the object's address is being taken.
    552                         // Need to get the type of the VariableExpr object, because the AddressExpr is rebuilt and uses the
    553                         // type of the VariableExpr to do so.
    554                         assert( constructee->get_results().size() == 1 );
    555                         AddressExpr * addrExpr = dynamic_cast< AddressExpr * > ( constructee );
    556                         assert( addrExpr && addrExpr->get_results().size() == 1 );
    557                         type = addrExpr->get_results().front()->clone();
    558                 }
    559                 // cast to T* with qualifiers removed.
    560                 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
    561                 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
    562                 // remove lvalue as a qualifier, this can change to
    563                 //   type->get_qualifiers() = Type::Qualifiers();
    564                 Type * base = InitTweak::getPointerBase( type );
    565                 assert( base );
    566                 base->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
    567                 // if pointer has lvalue qualifier, cast won't appear in output
    568                 type->set_isLvalue( false );
    569                 constructee = new CastExpr( constructee, type );
    570 
    571                 // finally, resolve the ctor/dtor
    572                 impCtorDtorStmt->get_callStmt()->accept( *this );
    573551        }
    574552} // namespace ResolvExpr
  • src/SymTab/Autogen.cc

    r9706554 r71a3593  
    2626
    2727namespace SymTab {
     28        Type * SizeType = 0;
     29
    2830        class AutogenerateRoutines : public Visitor {
    2931                public:
     
    5961        bool isUnnamedBitfield( ObjectDecl * obj ) {
    6062                return obj != NULL && obj->get_name() == "" && obj->get_bitfieldWidth() != NULL;
    61         }
    62 
    63         template< typename OutputIterator >
    64         void makeScalarFunction( Expression *src, ObjectDecl *dstParam, DeclarationWithType *member, std::string fname, OutputIterator out ) {
    65                 ObjectDecl *obj = dynamic_cast<ObjectDecl *>( member );
    66                 // unnamed bit fields are not copied as they cannot be accessed
    67                 if ( isUnnamedBitfield( obj ) ) return;
    68 
    69                 // want to be able to generate assignment, ctor, and dtor generically,
    70                 // so fname is either ?=?, ?{}, or ^?{}
    71                 UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
    72 
    73                 UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
    74                 derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
    75 
    76                 // do something special for unnamed members
    77                 Expression *dstselect = new AddressExpr( new MemberExpr( member, derefExpr ) );
    78                 fExpr->get_args().push_back( dstselect );
    79 
    80                 if ( src ) {
    81                         fExpr->get_args().push_back( src );
    82                 }
    83 
    84                 Statement * callStmt = new ExprStmt( noLabels, fExpr );
    85                 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) ) ) {
    86                         // implicitly generated ctor/dtor calls should be wrapped
    87                         // so that later passes are aware they were generated.
    88                         // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
    89                         // because this causes the address to be taken at codegen, which is illegal in C.
    90                         callStmt = new ImplicitCtorDtorStmt( callStmt );
    91                 }
    92                 *out++ = callStmt;
    9363        }
    9464
     
    203173        }
    204174
    205         void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) {
    206                 if ( isGeneric ) {
    207                         // rewrite member type in terms of the type variables on this operator
    208                         field = field->clone();
    209                         genericSubs.apply( field );
    210 
    211                         if ( src ) {
    212                                 genericSubs.apply( src );
    213                         }
     175        void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout, bool forward = true ) {
     176                if ( isDynamicLayout && src ) {
     177                        genericSubs.apply( src );
    214178                }
    215179
     
    219183                }
    220184
     185                InitTweak::InitExpander srcParam( src );
     186
    221187                // assign to destination (and return value if generic)
    222                 if ( ArrayType *array = dynamic_cast< ArrayType * >( field->get_type() ) ) {
    223                         UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
    224                         derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
    225                         Expression *dstselect = new MemberExpr( field, derefExpr );
    226 
    227                         makeArrayFunction( src, dstselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
    228                         if ( isGeneric && returnVal ) {
    229                                 UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) );
    230                                 derefRet->get_args().push_back( new VariableExpr( returnVal ) );
    231                                 Expression *retselect = new MemberExpr( field, derefRet );
    232 
    233                                 makeArrayFunction( src, retselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
    234                         }
    235                 } else {
    236                         makeScalarFunction( src, dstParam, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
    237                         if ( isGeneric && returnVal ) makeScalarFunction( src, returnVal, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
     188                UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
     189                derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
     190                Expression *dstselect = new MemberExpr( field, derefExpr );
     191                genImplicitCall( srcParam, dstselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
     192
     193                if ( isDynamicLayout && returnVal ) {
     194                        UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) );
     195                        derefRet->get_args().push_back( new VariableExpr( returnVal ) );
     196                        Expression *retselect = new MemberExpr( field, derefRet );
     197                        genImplicitCall( srcParam, retselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
    238198                } // if
    239199        }
    240200
    241201        template<typename Iterator>
    242         void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) {
     202        void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout, bool forward = true ) {
    243203                for ( ; member != end; ++member ) {
    244204                        if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate
     
    276236
    277237                                Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : NULL;
    278                                 makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isGeneric, forward );
     238                                makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isDynamicLayout, forward );
    279239                        } // if
    280240                } // for
     
    284244        /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.
    285245        template<typename Iterator>
    286         void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric ) {
     246        void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout ) {
    287247                FunctionType * ftype = func->get_functionType();
    288248                std::list<DeclarationWithType*> & params = ftype->get_parameters();
     
    310270                                        // matching parameter, initialize field with copy ctor
    311271                                        Expression *srcselect = new VariableExpr(*parameter);
    312                                         makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isGeneric );
     272                                        makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isDynamicLayout );
    313273                                        ++parameter;
    314274                                } else {
    315275                                        // no matching parameter, initialize field with default ctor
    316                                         makeStructMemberOp( dstParam, NULL, field, func, genericSubs, isGeneric );
     276                                        makeStructMemberOp( dstParam, NULL, field, func, genericSubs, isDynamicLayout );
    317277                                }
    318278                        }
     
    324284
    325285                // Make function polymorphic in same parameters as generic struct, if applicable
    326                 bool isGeneric = false;  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
     286                bool isDynamicLayout = false;  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
    327287                std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters();
    328288                std::list< Expression* > structParams;  // List of matching parameters to put on types
    329289                TypeSubstitution genericSubs; // Substitutions to make to member types of struct
    330290                for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) {
    331                         isGeneric = true;
     291                        if ( (*param)->get_kind() == TypeDecl::Any ) isDynamicLayout = true;
    332292                        TypeDecl *typeParam = cloneAndRename( *param, "_autoassign_" + aggregateDecl->get_name() + "_" + (*param)->get_name() );
    333293                        assignType->get_forall().push_back( typeParam );
     
    389349                        FunctionDecl * ctor = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, memCtorType->clone(), new CompoundStmt( noLabels ), true, false );
    390350                        ctor->fixUniqueId();
    391                         makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, genericSubs, isGeneric );
     351                        makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, genericSubs, isDynamicLayout );
    392352                        memCtors.push_back( ctor );
    393353                }
     
    395355
    396356                // generate appropriate calls to member ctor, assignment
    397                 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, genericSubs, isGeneric );
    398                 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, genericSubs, isGeneric );
    399                 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, genericSubs, isGeneric );
     357                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, genericSubs, isDynamicLayout );
     358                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, genericSubs, isDynamicLayout );
     359                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, genericSubs, isDynamicLayout );
    400360                // needs to do everything in reverse, so pass "forward" as false
    401                 makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, genericSubs, isGeneric, false );
    402 
    403                 if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
     361                makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, genericSubs, isDynamicLayout, false );
     362
     363                if ( ! isDynamicLayout ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
    404364
    405365                declsToAdd.push_back( assignDecl );
     
    414374
    415375                // Make function polymorphic in same parameters as generic union, if applicable
    416                 bool isGeneric = false; // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
     376                bool isDynamicLayout = false; // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
    417377                std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters();
    418378                std::list< Expression* > unionParams;  // List of matching parameters to put on types
    419379                for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) {
    420                         isGeneric = true;
     380                        if ( (*param)->get_kind() == TypeDecl::Any ) isDynamicLayout = true;
    421381                        TypeDecl *typeParam = cloneAndRename( *param, "_autoassign_" + aggregateDecl->get_name() + "_" + (*param)->get_name() );
    422382                        assignType->get_forall().push_back( typeParam );
     
    454414
    455415                makeUnionFieldsAssignment( srcParam, dstParam, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
    456                 if ( isGeneric ) makeUnionFieldsAssignment( srcParam, returnVal, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
    457 
    458                 if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
     416                if ( isDynamicLayout ) makeUnionFieldsAssignment( srcParam, returnVal, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
     417                else assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
    459418
    460419                // body of assignment and copy ctor is the same
  • src/SymTab/Autogen.h

    r9706554 r71a3593  
    2222#include "SynTree/Declaration.h"
    2323#include "SynTree/Initializer.h"
     24#include "InitTweak/InitTweak.h"
    2425
    2526namespace SymTab {
    26   /// Generates assignment operators, constructors, and destructor for aggregate types as required
    27   void autogenerateRoutines( std::list< Declaration * > &translationUnit );
     27        /// Generates assignment operators, constructors, and destructor for aggregate types as required
     28        void autogenerateRoutines( std::list< Declaration * > &translationUnit );
    2829
    29   // originally makeArrayAssignment - changed to Function because it is now used for ctors and dtors as well
    30   // admittedly not a great name change. This used to live in Validate.cc, but has been moved so it can be reused elsewhere
     30        /// returns true if obj's name is the empty string and it has a bitfield width
     31        bool isUnnamedBitfield( ObjectDecl * obj );
    3132
    32   /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
    33   /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
    34   template< typename OutputIterator >
    35   void makeArrayFunction( Expression *srcParam, Expression *dstParam, ArrayType *array, std::string fname, OutputIterator out, bool forward = true ) {
    36     static UniqueName indexName( "_index" );
     33        /// size_t type - set when size_t typedef is seen. Useful in a few places,
     34        /// such as in determining array dimension type
     35        extern Type * SizeType;
    3736
    38     // for a flexible array member nothing is done -- user must define own assignment
    39     if ( ! array->get_dimension() ) return;
     37        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
     38        template< typename OutputIterator >
     39        Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false, bool forward = true );
    4040
    41     Expression * begin, * end, * update, * cmp;
    42     if ( forward ) {
    43       // generate: for ( int i = 0; i < 0; ++i )
    44       begin = new NameExpr( "0" );
    45       end = array->get_dimension()->clone();
    46       cmp = new NameExpr( "?<?" );
    47       update = new NameExpr( "++?" );
    48     } else {
    49       // generate: for ( int i = N-1; i >= 0; --i )
    50       begin = new UntypedExpr( new NameExpr( "?-?" ) );
    51       ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() );
    52       ((UntypedExpr*)begin)->get_args().push_back( new NameExpr( "1" ) );
    53       end = new NameExpr( "0" );
    54       cmp = new NameExpr( "?>=?" );
    55       update = new NameExpr( "--?" );
    56     }
     41        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     42        /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
     43        template< typename OutputIterator >
     44        Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false ) {
     45                // want to be able to generate assignment, ctor, and dtor generically,
     46                // so fname is either ?=?, ?{}, or ^?{}
     47                UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
    5748
    58     ObjectDecl *index = new ObjectDecl( indexName.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), NULL );
     49                // do something special for unnamed members
     50                dstParam = new AddressExpr( dstParam );
     51                if ( addCast ) {
     52                        // cast to T* with qualifiers removed, so that qualified objects can be constructed
     53                        // and destructed with the same functions as non-qualified objects.
     54                        // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
     55                        // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
     56                        // remove lvalue as a qualifier, this can change to
     57                        //   type->get_qualifiers() = Type::Qualifiers();
     58                        assert( type );
     59                        Type * castType = type->clone();
     60                        castType->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
     61                        castType->set_isLvalue( true ); // xxx - might not need this
     62                        dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) );
     63                }
     64                fExpr->get_args().push_back( dstParam );
    5965
    60     UntypedExpr *init = new UntypedExpr( new NameExpr( "?=?" ) );
    61     init->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
    62     init->get_args().push_back( begin );
    63     index->set_init( new SingleInit( init, std::list<Expression*>() ) );
     66                Statement * listInit = srcParam.buildListInit( fExpr );
    6467
    65     UntypedExpr *cond = new UntypedExpr( cmp );
    66     cond->get_args().push_back( new VariableExpr( index ) );
    67     cond->get_args().push_back( end );
     68                std::list< Expression * > args = *++srcParam;
     69                fExpr->get_args().splice( fExpr->get_args().end(), args );
    6870
    69     UntypedExpr *inc = new UntypedExpr( update );
    70     inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
     71                *out++ = new ExprStmt( noLabels, fExpr );
    7172
    72     // want to be able to generate assignment, ctor, and dtor generically,
    73     // so fname is either ?=?, ?{}, or ^?{}
    74     UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
     73                srcParam.clearArrayIndices();
    7574
    76     UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?+?" ) );
    77     dstIndex->get_args().push_back( dstParam );
    78     dstIndex->get_args().push_back( new VariableExpr( index ) );
    79     fExpr->get_args().push_back( dstIndex );
     75                return listInit;
     76        }
    8077
    81     // srcParam is NULL for default ctor/dtor
    82     if ( srcParam ) {
    83       UntypedExpr *srcIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
    84       srcIndex->get_args().push_back( srcParam );
    85       srcIndex->get_args().push_back( new VariableExpr( index ) );
    86       fExpr->get_args().push_back( srcIndex );
    87     }
     78        /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
     79        /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
     80        template< typename OutputIterator >
     81        void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, bool addCast = false, bool forward = true ) {
     82                static UniqueName indexName( "_index" );
    8883
    89     std::list<Statement *> initList;
    90     CompoundStmt * block = new CompoundStmt( noLabels );
    91     block->get_kids().push_back( new DeclStmt( noLabels, index ) );
    92     block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, new ExprStmt( noLabels, fExpr ) ) );
     84                // for a flexible array member nothing is done -- user must define own assignment
     85                if ( ! array->get_dimension() ) return ;
    9386
    94     Statement * stmt = block;
    95     if ( fname == "?{}" || fname == "^?{}" ) {
    96       // implicitly generated ctor/dtor calls should be wrapped
    97       // so that later passes are aware they were generated
    98       stmt = new ImplicitCtorDtorStmt( stmt );
    99     }
    100     *out++ = stmt;
    101   }
     87                Expression * begin, * end, * update, * cmp;
     88                if ( forward ) {
     89                        // generate: for ( int i = 0; i < 0; ++i )
     90                        begin = new NameExpr( "0" );
     91                        end = array->get_dimension()->clone();
     92                        cmp = new NameExpr( "?<?" );
     93                        update = new NameExpr( "++?" );
     94                } else {
     95                        // generate: for ( int i = N-1; i >= 0; --i )
     96                        begin = new UntypedExpr( new NameExpr( "?-?" ) );
     97                        ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() );
     98                        ((UntypedExpr*)begin)->get_args().push_back( new NameExpr( "1" ) );
     99                        end = new NameExpr( "0" );
     100                        cmp = new NameExpr( "?>=?" );
     101                        update = new NameExpr( "--?" );
     102                }
     103
     104                ObjectDecl *index = new ObjectDecl( indexName.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), NULL );
     105
     106                UntypedExpr *init = new UntypedExpr( new NameExpr( "?=?" ) );
     107                init->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
     108                init->get_args().push_back( begin );
     109                index->set_init( new SingleInit( init, std::list<Expression*>() ) );
     110
     111                UntypedExpr *cond = new UntypedExpr( cmp );
     112                cond->get_args().push_back( new VariableExpr( index ) );
     113                cond->get_args().push_back( end );
     114
     115                UntypedExpr *inc = new UntypedExpr( update );
     116                inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
     117
     118                UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
     119                dstIndex->get_args().push_back( dstParam );
     120                dstIndex->get_args().push_back( new VariableExpr( index ) );
     121                dstParam = dstIndex;
     122
     123                // srcParam must keep track of the array indices to build the
     124                // source parameter and/or array list initializer
     125                srcParam.addArrayIndex( new VariableExpr( index ), array->get_dimension()->clone() );
     126
     127                // for stmt's body, eventually containing call
     128                CompoundStmt * body = new CompoundStmt( noLabels );
     129                Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->get_kids() ), array->get_base(), addCast, forward );
     130
     131                // block containing for stmt and index variable
     132                std::list<Statement *> initList;
     133                CompoundStmt * block = new CompoundStmt( noLabels );
     134                block->get_kids().push_back( new DeclStmt( noLabels, index ) );
     135                if ( listInit ) block->get_kids().push_back( listInit );
     136                block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, body ) );
     137
     138                *out++ = block;
     139        }
     140
     141        template< typename OutputIterator >
     142        Statement * genCall( InitTweak::InitExpander &  srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast, bool forward ) {
     143                if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
     144                        genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
     145                        return 0;
     146                } else {
     147                        return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
     148                }
     149        }
     150
     151        /// inserts into out a generated call expression to function fname with arguments dstParam
     152        /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
     153        /// object being constructed. The function wraps constructor and destructor calls in an
     154        /// ImplicitCtorDtorStmt node.
     155        template< typename OutputIterator >
     156        void genImplicitCall( InitTweak::InitExpander &  srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
     157                ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
     158                assert( obj );
     159                // unnamed bit fields are not copied as they cannot be accessed
     160                if ( isUnnamedBitfield( obj ) ) return;
     161
     162                bool addCast = (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && obj->get_bitfieldWidth() == NULL ) );
     163                std::list< Statement * > stmts;
     164                genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->get_type(), addCast, forward );
     165
     166                // currently genCall should produce at most one element, but if that changes then the next line needs to be updated to grab the statement which contains the call
     167                assert( stmts.size() <= 1 );
     168                if ( stmts.size() == 1 ) {
     169                        Statement * callStmt = stmts.front();
     170                        if ( addCast ) {
     171                                // implicitly generated ctor/dtor calls should be wrapped
     172                                // so that later passes are aware they were generated.
     173                                // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
     174                                // because this causes the address to be taken at codegen, which is illegal in C.
     175                                callStmt = new ImplicitCtorDtorStmt( callStmt );
     176                        }
     177                        *out++ = callStmt;
     178                }
     179        }
    102180} // namespace SymTab
    103181#endif // AUTOGEN_H
  • src/SymTab/FixFunction.cc

    r9706554 r71a3593  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixFunction.cc -- 
     7// FixFunction.cc --
    88//
    99// Author           : Richard C. Bilson
     
    4444
    4545        Type * FixFunction::mutate(ArrayType *arrayType) {
    46                 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), maybeClone( arrayType->get_base()->clone() ), maybeClone( arrayType->get_dimension() ), arrayType->get_isVarLen(), arrayType->get_isStatic() );
     46                // need to recursively mutate the base type in order for multi-dimensional arrays to work.
     47                PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->get_base()->clone()->acceptMutator( *this ), maybeClone( arrayType->get_dimension() ), arrayType->get_isVarLen(), arrayType->get_isStatic() );
    4748                delete arrayType;
    4849                return pointerType;
  • src/SymTab/Validate.cc

    r9706554 r71a3593  
    174174
    175175                virtual void visit( FunctionDecl *funcDecl );
    176 };
     176        };
    177177
    178178        class CompoundLiteral : public GenPoly::DeclMutator {
     
    191191                EliminateTypedef::eliminateTypedef( translationUnit );
    192192                HoistStruct::hoistStruct( translationUnit );
     193                autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs Pass1
    193194                acceptAll( translationUnit, pass1 );
    194195                acceptAll( translationUnit, pass2 );
    195196                ReturnChecker::checkFunctionReturns( translationUnit );
    196                 mutateAll( translationUnit, compoundliteral );
    197                 autogenerateRoutines( translationUnit );
     197                compoundliteral.mutateDeclarationList( translationUnit );
    198198                acceptAll( translationUnit, pass3 );
    199199                VerifyCtorDtor::verify( translationUnit );
     
    490490                EliminateTypedef eliminator;
    491491                mutateAll( translationUnit, eliminator );
     492                if ( eliminator.typedefNames.count( "size_t" ) ) {
     493                        // grab and remember declaration of size_t
     494                        SizeType = eliminator.typedefNames["size_t"].first->get_base()->clone();
     495                } else {
     496                        // xxx - missing global typedef for size_t - default to long unsigned int, even though that may be wrong
     497                        // eventually should have a warning for this case.
     498                        SizeType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
     499                }
    492500                filter( translationUnit, isTypedef, true );
     501
    493502        }
    494503
     
    518527        Declaration *EliminateTypedef::mutate( TypedefDecl * tyDecl ) {
    519528                Declaration *ret = Mutator::mutate( tyDecl );
     529
    520530                if ( typedefNames.count( tyDecl->get_name() ) == 1 && typedefNames[ tyDecl->get_name() ].second == scopeLevel ) {
    521531                        // typedef to the same name from the same scope
  • src/SynTree/Declaration.cc

    r9706554 r71a3593  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Declaration.cc -- 
     7// Declaration.cc --
    88//
    99// Author           : Richard C. Bilson
     
    2020#include "Initializer.h"
    2121#include "Type.h"
     22#include "Attribute.h"
    2223#include "Common/utility.h"
    2324
  • src/SynTree/Declaration.h

    r9706554 r71a3593  
    6464class DeclarationWithType : public Declaration {
    6565  public:
    66         DeclarationWithType( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage );
     66        DeclarationWithType( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, const std::list< Attribute * > & attributes );
    6767        DeclarationWithType( const DeclarationWithType &other );
    6868        virtual ~DeclarationWithType();
     
    7575        int get_scopeLevel() const { return scopeLevel; }
    7676        void set_scopeLevel( int newValue ) { scopeLevel = newValue; }
     77
     78        std::list< Attribute * >& get_attributes() { return attributes; }
     79        const std::list< Attribute * >& get_attributes() const { return attributes; }
    7780
    7881        virtual DeclarationWithType *clone() const = 0;
     
    8790        // shadowed identifiers can be accessed
    8891        int scopeLevel = 0;
     92
     93        std::list< Attribute * > attributes;
    8994};
    9095
     
    9297        typedef DeclarationWithType Parent;
    9398  public:
    94         ObjectDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, Expression *bitfieldWidth, Type *type, Initializer *init, bool isInline = false, bool isNoreturn = false );
     99        ObjectDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, Expression *bitfieldWidth, Type *type, Initializer *init, const std::list< Attribute * > attributes = std::list< Attribute * >(), bool isInline = false, bool isNoreturn = false );
    95100        ObjectDecl( const ObjectDecl &other );
    96101        virtual ~ObjectDecl();
     
    131136        std::list< std::string >& get_oldIdents() { return oldIdents; }
    132137        std::list< Declaration* >& get_oldDecls() { return oldDecls; }
    133         std::list< Attribute * >& get_attributes() { return attributes; }
    134138
    135139        virtual FunctionDecl *clone() const { return new FunctionDecl( *this ); }
     
    143147        std::list< std::string > oldIdents;
    144148        std::list< Declaration* > oldDecls;
    145         std::list< Attribute * > attributes;
    146149};
    147150
  • src/SynTree/DeclarationWithType.cc

    r9706554 r71a3593  
    1616#include "Declaration.h"
    1717#include "Type.h"
     18#include "Attribute.h"
    1819#include "Common/utility.h"
    1920
    20 DeclarationWithType::DeclarationWithType( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage )
    21                 : Declaration( name, sc, linkage ) {
     21DeclarationWithType::DeclarationWithType( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, const std::list< Attribute * > & attributes )
     22                : Declaration( name, sc, linkage ), attributes( attributes ) {
    2223}
    2324
    2425DeclarationWithType::DeclarationWithType( const DeclarationWithType &other )
    2526                : Declaration( other ), mangleName( other.mangleName ), scopeLevel( other.scopeLevel ) {
     27        cloneAll( other.attributes, attributes );
    2628}
    2729
    2830DeclarationWithType::~DeclarationWithType() {
     31        deleteAll( attributes );
    2932}
    3033
  • src/SynTree/Expression.cc

    r9706554 r71a3593  
    344344}
    345345
     346//// is this right? It's cloning the member, but the member is a declaration so probably shouldn't be cloned...
    346347MemberExpr::MemberExpr( const MemberExpr &other ) :
    347                 Expression( other ), member( maybeClone( other.member ) ), aggregate( maybeClone( other.aggregate ) ) {
     348                Expression( other ), member( other.member ), aggregate( maybeClone( other.aggregate ) ) {
    348349}
    349350
    350351MemberExpr::~MemberExpr() {
    351         delete member;
     352        // delete member;
    352353        delete aggregate;
    353354}
  • src/SynTree/FunctionDecl.cc

    r9706554 r71a3593  
    2323
    2424FunctionDecl::FunctionDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, FunctionType *type, CompoundStmt *statements, bool isInline, bool isNoreturn, std::list< Attribute * > attributes )
    25                 : Parent( name, sc, linkage ), type( type ), statements( statements ), attributes( attributes ) {
     25                : Parent( name, sc, linkage, attributes ), type( type ), statements( statements ) {
    2626        set_isInline( isInline );
    2727        set_isNoreturn( isNoreturn );
     
    3434FunctionDecl::FunctionDecl( const FunctionDecl &other )
    3535        : Parent( other ), type( maybeClone( other.type ) ), statements( maybeClone( other.statements ) ) {
    36                 cloneAll( other.attributes, attributes );
    3736}
    3837
     
    4039        delete type;
    4140        delete statements;
    42         deleteAll( attributes );
    4341}
    4442
     
    6967        } // if
    7068
    71         printAll( attributes, os, indent );
     69        printAll( get_attributes(), os, indent );
    7270
    7371        if ( get_storageClass() != DeclarationNode::NoStorageClass ) {
  • src/SynTree/Initializer.h

    r9706554 r71a3593  
    9393        std::list<Initializer*> &get_initializers() { return initializers; }
    9494
    95         std::list<Initializer*>::iterator begin_initializers() { return initializers.begin(); }
    96         std::list<Initializer*>::iterator end_initializers() { return initializers.end(); }
     95        typedef std::list<Initializer*>::iterator iterator;
     96        iterator begin() { return initializers.begin(); }
     97        iterator end() { return initializers.end(); }
    9798
    9899        virtual ListInit *clone() const { return new ListInit( *this ); }
  • src/SynTree/Label.h

    r9706554 r71a3593  
    2424class Label {
    2525  public:
    26         Label( const std::string & name = "", Statement * labelled = 0 ) : name( name ), labelled( labelled ) {}
     26        Label( const std::string & name = "", Statement * labelled = 0, const std::list< Attribute * > & attributes = std::list< Attribute * >() ) : name( name ), labelled( labelled ), attributes( attributes ) {}
    2727        Label( const char * name, Statement * labelled = 0 ) : name( name ), labelled( labelled ) {}
    2828
  • src/SynTree/ObjectDecl.cc

    r9706554 r71a3593  
    1818#include "Initializer.h"
    1919#include "Expression.h"
     20#include "Attribute.h"
    2021#include "Common/utility.h"
    2122#include "Statement.h"
    2223
    23 ObjectDecl::ObjectDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, Expression *bitfieldWidth, Type *type, Initializer *init, bool isInline, bool isNoreturn )
    24         : Parent( name, sc, linkage ), type( type ), init( init ), bitfieldWidth( bitfieldWidth ) {
     24ObjectDecl::ObjectDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, Expression *bitfieldWidth, Type *type, Initializer *init, const std::list< Attribute * > attributes, bool isInline, bool isNoreturn )
     25        : Parent( name, sc, linkage, attributes ), type( type ), init( init ), bitfieldWidth( bitfieldWidth ) {
    2526        set_isInline( isInline );
    2627        set_isNoreturn( isNoreturn );
     
    4546                os << LinkageSpec::toString( get_linkage() ) << " ";
    4647        } // if
     48
     49        printAll( get_attributes(), os, indent );
    4750
    4851        if ( get_storageClass() != DeclarationNode::NoStorageClass ) {
     
    8083        } // if
    8184
     85        // xxx - should printShort print attributes?
     86
    8287        if ( get_storageClass() != DeclarationNode::NoStorageClass ) {
    8388                os << DeclarationNode::storageName[ get_storageClass() ] << ' ';
  • src/main.cc

    r9706554 r71a3593  
    2828#include "GenPoly/Box.h"
    2929#include "GenPoly/CopyParams.h"
     30#include "GenPoly/InstantiateGeneric.h"
    3031#include "CodeGen/Generate.h"
    3132#include "CodeGen/FixNames.h"
     
    4243#include "InitTweak/GenInit.h"
    4344#include "InitTweak/FixInit.h"
    44 #include "InitTweak/FixGlobalInit.h"
    4545//#include "Explain/GenProlog.h"
    4646//#include "Try/Visit.h"
     
    282282                OPTPRINT( "fixNames" )
    283283                CodeGen::fixNames( translationUnit );
    284                 OPTPRINT( "fixGlobalInit" );
    285                 InitTweak::fixGlobalInit( translationUnit, filename, libcfap || treep );
    286284                OPTPRINT( "tweakInit" )
    287285                InitTweak::genInit( translationUnit );
     
    304302                }
    305303
     304                // fix ObjectDecl - replaces ConstructorInit nodes
    306305                OPTPRINT( "fixInit" )
    307                 // fix ObjectDecl - replaces ConstructorInit nodes
    308                 InitTweak::fix( translationUnit );
     306                InitTweak::fix( translationUnit, filename, libcfap || treep );
    309307                if ( ctorinitp ) {
    310308                        dump ( translationUnit );
     
    312310                }
    313311
     312                OPTPRINT("instantiateGenerics")
     313                GenPoly::instantiateGeneric( translationUnit );
    314314                OPTPRINT( "copyParams" );
    315315                GenPoly::copyParams( translationUnit );
  • src/tests/.expect/64/extension.txt

    r9706554 r71a3593  
    100100    ((void)((__extension__ __a__i_2 , __extension__ __b__i_2) , __extension__ __c__i_2));
    101101}
    102 __attribute__ ((constructor(),)) static void _init_extension(void){
    103     int _global_init0;
    104     ((void)((*((int *)(&__a__i_1)))=_global_init0) /* ?{} */);
    105     int _global_init1;
    106     ((void)((*((int *)(&__b__i_1)))=_global_init1) /* ?{} */);
    107     int _global_init2;
    108     ((void)((*((int *)(&__c__i_1)))=_global_init2) /* ?{} */);
    109 }
    110 __attribute__ ((destructor(),)) static void _destroy_extension(void){
    111     ((void)((*((int *)(&__c__i_1)))) /* ^?{} */);
    112     ((void)((*((int *)(&__b__i_1)))) /* ^?{} */);
    113     ((void)((*((int *)(&__a__i_1)))) /* ^?{} */);
    114 }
  • src/tests/init_once.c

    r9706554 r71a3593  
    9292init_once y = x;
    9393
     94void static_variable() {
     95        static init_once x;
     96}
     97
    9498int main() {
    9599        // local variables
     
    179183                }
    180184        }
     185
     186        // function-scoped static variable
     187        for (int i = 0; i < 10; i++) {
     188                static_variable();
     189        }
    181190}
    182191
Note: See TracChangeset for help on using the changeset viewer.