Changes in / [22854f8:cb91437]


Ignore:
Files:
40 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • doc/generic_types/generic_types.tex

    r22854f8 rcb91437  
    1 % take of review (for line numbers) and anonymous (for anonymization) on submission
    21\documentclass[format=acmlarge, anonymous, review]{acmart}
    32
    4 \usepackage{listings}   % For code listings
     3\citestyle{acmauthoryear}
    54
    6 % Useful macros
    7 \newcommand{\CFA}{C$\mathbf\forall$} % Cforall symbolic name
    8 \newcommand{\CC}{\rm C\kern-.1em\hbox{+\kern-.25em+}} % C++ symbolic name
    9 \newcommand{\CCeleven}{\rm C\kern-.1em\hbox{+\kern-.25em+}11} % C++11 symbolic name
    10 \newcommand{\CCfourteen}{\rm C\kern-.1em\hbox{+\kern-.25em+}14} % C++14 symbolic name
    11 \newcommand{\CCseventeen}{\rm C\kern-.1em\hbox{+\kern-.25em+}17} % C++17 symbolic name
    12 
     5\newcommand{\CFA}{C$\mathbf\forall$}
    136\newcommand{\TODO}{\textbf{TODO}}
    14 \newcommand{\eg}{\textit{e}.\textit{g}.}
    15 \newcommand{\ie}{\textit{i}.\textit{e}.}
    16 \newcommand{\etc}{\textit{etc}.}
    17 
    18 % CFA programming language, based on ANSI C (with some gcc additions)
    19 \lstdefinelanguage{CFA}[ANSI]{C}{
    20         morekeywords={_Alignas,_Alignof,__alignof,__alignof__,asm,__asm,__asm__,_At,_Atomic,__attribute,__attribute__,auto,
    21                 _Bool,catch,catchResume,choose,_Complex,__complex,__complex__,__const,__const__,disable,dtype,enable,__extension__,
    22                 fallthrough,fallthru,finally,forall,ftype,_Generic,_Imaginary,inline,__label__,lvalue,_Noreturn,one_t,otype,restrict,_Static_assert,
    23                 _Thread_local,throw,throwResume,trait,try,typeof,__typeof,__typeof__,zero_t},
    24 }%
    25 
    26 \lstset{
    27 language=CFA,
    28 columns=fullflexible,
    29 basicstyle=\linespread{0.9}\sf,                                                 % reduce line spacing and use sanserif font
    30 stringstyle=\tt,                                                                                % use typewriter font
    31 tabsize=4,                                                                                              % 4 space tabbing
    32 xleftmargin=\parindent,                                                                 % indent code to paragraph indentation
    33 % extendedchars=true,                                                                   % allow ASCII characters in the range 128-255
    34 % escapechar=§,                                                                                 % LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
    35 mathescape=true,                                                                                % LaTeX math escape in CFA code $...$
    36 keepspaces=true,                                                                                %
    37 showstringspaces=false,                                                                 % do not show spaces with cup
    38 showlines=true,                                                                                 % show blank lines at end of code
    39 aboveskip=4pt,                                                                                  % spacing above/below code block
    40 belowskip=3pt,
    41 % replace/adjust listing characters that look bad in sanserif
    42 literate={-}{\raisebox{-0.15ex}{\texttt{-}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
    43         {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {_}{\makebox[1.2ex][c]{\rule{1ex}{0.1ex}}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    44         {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{$\rightarrow$}2,
    45 % moredelim=**[is][\color{red}]{®}{®},                                  % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
    46 % moredelim=**[is][\color{blue}]{ß}{ß},                                 % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
    47 % moredelim=**[is][\color{OliveGreen}]{¢}{¢},                   % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"
    48 % moredelim=[is][\lstset{keywords={}}]{¶}{¶},                   % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
    49 }% lstset
    50 
    51 % inline code @...@
    52 \lstMakeShortInline@
    53 
    54 % ACM Information
    55 \citestyle{acmauthoryear}
    567
    578\acmJournal{PACMPL}
     
    7021}
    7122\email{a3moss@uwaterloo.ca}
    72 
    73 \author{Robert Schluntz}
    74 \affiliation{%
    75         \institution{University of Waterloo}
    76         \department{David R. Cheriton School of Computer Science}
    77         \streetaddress{Davis Centre, University of Waterloo}
    78         \city{Waterloo}
    79         \state{ON}
    80         \postcode{N2L 3G1}
    81         \country{Canada}
    82 }
    83 \email{rschlunt@uwaterloo.ca}
    84 
    85 \author{Peter Buhr}
    86 \affiliation{%
    87         \institution{University of Waterloo}
    88         \department{David R. Cheriton School of Computer Science}
    89         \streetaddress{Davis Centre, University of Waterloo}
    90         \city{Waterloo}
    91         \state{ON}
    92         \postcode{N2L 3G1}
    93         \country{Canada}
    94 }
    95 \email{pabuhr@uwaterloo.ca}
    9623
    9724\terms{generic, types}
     
    12249\ccsdesc[300]{Software and its engineering~Source code generation}
    12350
     51% \abstract{Abstract goes here.}
    12452\begin{abstract}
    12553\TODO{} Write abstract.
     
    13159
    13260\section{Introduction \& Background}
     61\CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or Cforall.} is an evolutionary modernization of the C programming language which aims to add modern language features to C while maintaining both source compatibility with C and a familiar mental model for programmers. This paper describes how generic types are designed and implemented in \CFA{}, and how they interact with \CFA{}'s polymorphic functions.
    13362
    134 \CFA{}\footnote{Pronounced ``C-for-all'', and written \CFA{} or Cforall.} is an evolutionary extension of the C programming language which aims to add modern language features to C while maintaining both source compatibility with C and a familiar mental model for programmers. This paper describes how generic types are designed and implemented in \CFA{}, and how they interact with \CFA{}'s polymorphic functions.
    135 
    136 \subsection{Polymorphic Functions}
    137 
    138 \CFA{}'s polymorphism was originally formalized by \citet{Ditchfield92}, and first implemented by \citet{Bilson03}. The signature feature of \CFA{} is parametric-polymorphic functions; such functions are written using a @forall@ clause (which gives the language its name):
    139 \begin{lstlisting}
    140 forall(otype T)
    141 T identity(T x) {is_
    142     return x;
    143 }
    144 
    145 int forty_two = identity(42); // T is bound to int, forty_two == 42
    146 \end{lstlisting}
    147 The @identity@ function above can be applied to any complete object type (or ``@otype@''). The 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. The \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. If this extra information is not needed, the type parameter can be declared as @dtype T@, where @dtype@ is short for ``data type''.
    148 
    149 Here, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; preliminary experiments have shown this overhead to be similar to \CC{} virtual function calls. An advantage of this design is that, unlike \CC{} template functions, \CFA{} @forall@ functions are compatible with separate compilation.
    150 
    151 Since bare polymorphic types do not provide a great range of available operations, \CFA{} provides a \emph{type assertion} mechanism to provide further information about a type:
    152 \begin{lstlisting}
    153 forall(otype T | { T twice(T); })
    154 T four_times(T x) {
    155     return twice( twice(x) );
    156 }
    157 
    158 double twice(double d) { return d * 2.0; } // (1)
    159 
    160 double magic = four_times(10.5); // T is bound to double, uses (1) to satisfy type assertion
    161 \end{lstlisting}
    162 These type assertions may be either variable or function declarations that depend on a polymorphic type variable. @four_times@ can only be called with an argument for which there exists a function named @twice@ that can take that argument and return another value of the same type; a pointer to the appropriate @twice@ function is passed as an additional implicit parameter to the call of @four_times@.
    163 
    164 Monomorphic specializations of polymorphic functions can themselves be used to satisfy type assertions. For instance, @twice@ could have been defined using the \CFA{} syntax for operator overloading as:
    165 \begin{lstlisting}
    166 forall(otype S | { S ?+?(S, S); })
    167 S twice(S x) { return x + x; }  // (2)
    168 \end{lstlisting}
    169 This version of @twice@ works for any type @S@ that has an addition operator defined for it, and it could have been used to satisfy the type assertion on @four_times@.
    170 The compiler accomplishes this by creating a wrapper function calling @twice // (2)@ with @S@ bound to @double@, then providing this wrapper function to @four_times@\footnote{\lstinline@twice // (2)@ could also have had a type parameter named \lstinline@T@; \CFA{} specifies renaming of the type parameters, which would avoid the name conflict with the type variable \lstinline@T@ of \lstinline@four_times@.}.
    171 
    172 \subsection{Traits}
    173 
    174 \CFA{} provides \emph{traits} as a means to name a group of type assertions, as in the example below:
    175 \begin{lstlisting}
    176 trait has_magnitude(otype T) {
    177     bool ?<?(T, T);  // comparison operator for T
    178     T -?(T);  // negation operator for T
    179     void ?{}(T*, zero_t);  // constructor from 0 literal
    180 };
    181 
    182 forall(otype M | has_magnitude(M))
    183 M abs( M m ) {
    184     M zero = { 0 };  // uses zero_t constructor from trait
    185     return m < zero ? -m : m;
    186 }
    187 
    188 forall(otype M | has_magnitude(M))
    189 M max_magnitude( M a, M b ) {
    190     return abs(a) < abs(b) ? b : a;
    191 }
    192 \end{lstlisting}
    193 
    194 @otype@ is essentially syntactic sugar for the following trait:
    195 \begin{lstlisting}
    196 trait otype(dtype T | sized(T)) {
    197         // sized is a compiler-provided pseudo-trait for types with known size & alignment
    198         void ?{}(T*);  // default constructor
    199         void ?{}(T*, T);  // copy constructor
    200         T ?=?(T*, T);  // assignment operator
    201         void ^?{}(T*);  // destructor
    202 };
    203 \end{lstlisting}
    204 
    205 Semantically, traits are simply a named lists of type assertions, but they may be used for many of the same purposes that interfaces in Java or abstract base classes in \CC{} are used for. Unlike 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 implementation of an interface in Go, as opposed to the nominal inheritance model of Java and \CC{}. Nominal inheritance can be simulated with traits using marker variables or functions:
    206 \begin{lstlisting}
    207 trait nominal(otype T) {
    208     T is_nominal;
    209 };
    210 
    211 int is_nominal;  // int now satisfies the nominal trait
    212 {
    213     char is_nominal; // char satisfies the nominal trait
    214 }
    215 // char no longer satisfies the nominal trait here 
    216 \end{lstlisting}
    217 
    218 Traits, however, are significantly more powerful than nominal-inheritance interfaces; firstly, due to the scoping rules of the declarations that satisfy a trait's type assertions, a type may not satisfy a trait everywhere that the type is declared, as with @char@ and the @nominal@ trait above. Secondly, traits may be used to declare a relationship among multiple types, a property that may be difficult or impossible to represent in nominal-inheritance type systems:
    219 \begin{lstlisting}
    220 trait pointer_like(otype Ptr, otype El) {
    221     lvalue El *?(Ptr); // Ptr can be dereferenced into a modifiable value of type El
    222 }
    223 
    224 struct list {
    225     int value;
    226     list *next;  // may omit "struct" on type names
    227 };
    228 
    229 typedef list *list_iterator;
    230 
    231 lvalue int *?( list_iterator it ) {
    232     return it->value;
    233 }
    234 \end{lstlisting}
    235 
    236 In the example above, @(list_iterator, int)@ satisfies @pointer_like@ by the user-defined dereference function, and @(list_iterator, list)@ also satisfies @pointer_like@ by the built-in dereference operator for pointers. Given a declaration @list_iterator it@, @*it@ can be either an @int@ or a @list@, with the meaning disambiguated by context (\eg, @int x = *it;@ interprets @*it@ as an @int@, while @(*it).value = 42;@ interprets @*it@ as a @list@).
    237 While a nominal-inheritance system with associated types could model one of those two relationships by making @El@ an associated type of @Ptr@ in the @pointer_like@ implementation, few such systems could model both relationships simultaneously.
    238 
    239 \section{Generic Types}
    240 
    241 The generic types design for \CFA{} must integrate efficiently and naturally with the existing polymorphic functions in \CFA{}, while retaining backwards compatibility with C; maintaining separate compilation is a particularly important constraint on the design. However, where the concrete parameters of the generic type are known, there should not be extra overhead for the use of a generic type.
    242 
    243 A 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:
    244 \begin{lstlisting}
    245 forall(otype R, otype S) struct pair {
    246     R first;
    247     S second;
    248 };
    249 
    250 forall(otype T)
    251 T value( pair(const char*, T) *p ) { return p->second; }
    252 
    253 forall(dtype F, otype T)
    254 T value_p( pair(F*, T*) p ) { return *p.second; }
    255 
    256 pair(const char*, int) p = { "magic", 42 };
    257 int magic = value( &p );
    258 
    259 pair(void*, int*) q = { 0, &p.second };
    260 magic = value_p( q );
    261 double d = 1.0;
    262 pair(double*, double*) r = { &d, &d };
    263 d = value_p( r );
    264 \end{lstlisting}
    265 
    266 \CFA{} classifies generic types as either \emph{concrete} or \emph{dynamic}. Dynamic generic types vary in their in-memory layout depending on their type parameters, while concrete generic types have a fixed memory layout regardless of type parameters. A type may have polymorphic parameters but still be concrete; \CFA{} refers to such types as \emph{dtype-static}. Polymorphic pointers are an example of dtype-static types -- @forall(dtype T) T*@ is a polymorphic type, but for any @T@ chosen, @T*@ will have exactly the same in-memory representation as a @void*@, and can therefore be represented by a @void*@ in code generation.
    267 
    268 The \CFA{} compiler instantiates concrete generic types by template-expanding them to fresh struct types; concrete generic types can therefore be used with zero runtime overhead. To enable interoperation between equivalent instantiations of a generic type, the compiler saves the set of instantiations currently in scope and re-uses the generated struct declarations where appropriate. As an example, the concrete instantiation for @pair(const char*, int)@ would look something like this:
    269 \begin{lstlisting}
    270 struct _pair_conc1 {
    271         const char* first;
    272         int second;
    273 };
    274 \end{lstlisting}
    275 
    276 A concrete generic type with dtype-static parameters is also expanded to a struct type, but this struct type is used for all matching instantiations. In the example above, the @pair(F*, T*)@ parameter to @value_p@ is such a type; its expansion would look something like this, and be used as the type of the variables @q@ and @r@ as well, with casts for member access where appropriate:
    277 \begin{lstlisting}
    278 struct _pair_conc0 {
    279         void* first;
    280         void* second;
    281 };
    282 \end{lstlisting}
    283 
    284 \TODO{} Maybe move this after the rest of the discussion.
    285 This re-use of dtype-static struct instantiations enables some useful programming patterns at zero runtime cost. The most important such pattern is using @forall(dtype T) T*@ as a type-checked replacement for @void*@, as in this example, which takes a @qsort@ or @bsearch@-compatible comparison routine and creates a similar lexicographic comparison for pairs of pointers:
    286 \begin{lstlisting}
    287 forall(dtype T)
    288 int lexcmp( pair(T*, T*)* a, pair(T*, T*)* b, int (*cmp)(T*, T*) ) {
    289         int c = cmp(a->first, b->first);
    290         if ( c == 0 ) c = cmp(a->second, b->second);
    291         return c;
    292 }
    293 \end{lstlisting}
    294 Since @pair(T*, T*)@ is a concrete type, there are no added implicit parameters to @lexcmp@, so the code generated by \CFA{} will be effectively identical to a version of this written in standard C using @void*@, yet the \CFA{} version will be type-checked to ensure that the fields of both pairs and the arguments to the comparison function match in type.
    295 
    296 \TODO{} The second is zero-cost ``tag'' structs.
    297 
    298 \section{Tuples}
    299 
    300 \TODO{} Integrate Rob's work
    301 
    302 \TODO{} Check if we actually can use ttype parameters on generic types (if they set the complete flag, it should work, or nearly so).
    303 
    304 \section{Related Work}
    305 
    306 \TODO{} Talk about \CC{}, Cyclone, \etc{}
    307 
    308 \section{Conclusion}
    309 
    310 \TODO{}
     63\CFA{}'s polymorphism was originally formalized by \citet{Ditchfield92}, and first implemented by \citet{Bilson03}.
    31164
    31265\bibliographystyle{ACM-Reference-Format}
  • src/GenPoly/Box.cc

    r22854f8 rcb91437  
    12981298                        FunctionType * ftype = functionDecl->get_functionType();
    12991299                        if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) {
    1300                                 if ( functionDecl->get_name() != "?=?" && ! isPrefix( functionDecl->get_name(), "_thunk" ) && ! isPrefix( functionDecl->get_name(), "_adapter" ) ) { // xxx - remove check for ?=? once reference types are in; remove check for prefix once thunks properly use ctor/dtors
     1300                                if ( functionDecl->get_name() != "?=?" && ! isPrefix( functionDecl->get_name(), "_thunk" ) ) { // xxx - remove check for ?=? once reference types are in; remove check for prefix once thunks properly use ctor/dtors
    13011301                                        assert( ftype->get_returnVals().size() == 1 );
    13021302                                        DeclarationWithType * retval = ftype->get_returnVals().front();
  • src/GenPoly/Specialize.cc

    r22854f8 rcb91437  
    168168        }
    169169
    170         struct EnvTrimmer : public Visitor {
    171                 TypeSubstitution * env, * newEnv;
    172                 EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
    173                 virtual void visit( TypeDecl * tyDecl ) {
    174                         // transfer known bindings for seen type variables
    175                         if ( Type * t = env->lookup( tyDecl->get_name() ) ) {
    176                                 newEnv->add( tyDecl->get_name(), t );
    177                         }
    178                 }
    179         };
    180 
    181         /// reduce environment to just the parts that are referenced in a given expression
    182         TypeSubstitution * trimEnv( ApplicationExpr * expr, TypeSubstitution * env ) {
    183                 if ( env ) {
    184                         TypeSubstitution * newEnv = new TypeSubstitution();
    185                         EnvTrimmer trimmer( env, newEnv );
    186                         expr->accept( trimmer );
    187                         return newEnv;
    188                 }
    189                 return nullptr;
    190         }
    191 
    192170        /// Generates a thunk that calls `actual` with type `funType` and returns its address
    193171        Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     
    233211                }
    234212
    235                 appExpr->set_env( trimEnv( appExpr, env ) );
     213                appExpr->set_env( maybeClone( env ) );
    236214                if ( inferParams ) {
    237215                        appExpr->get_inferParams() = *inferParams;
  • src/InitTweak/FixInit.cc

    r22854f8 rcb91437  
    5252        namespace {
    5353                typedef std::unordered_map< Expression *, TypeSubstitution * > EnvMap;
    54                 typedef std::unordered_map< int, int > UnqCount;
    5554
    5655                class InsertImplicitCalls final : public GenPoly::PolyMutator {
     
    7574                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    7675                        /// arguments and return value temporaries
    77                         static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap, UnqCount & unqCount );
     76                        static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap );
    7877
    7978                        typedef SymTab::Indexer Parent;
    8079                        using Parent::visit;
    8180
    82                         ResolveCopyCtors( const EnvMap & envMap, UnqCount & unqCount ) : envMap( envMap ), unqCount( unqCount ) {}
     81                        ResolveCopyCtors( const EnvMap & envMap ) : envMap( envMap ) {}
    8382
    8483                        virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ) override;
     
    9594                        TypeSubstitution * env;
    9695                        const EnvMap & envMap;
    97                         UnqCount & unqCount; // count the number of times each unique expr ID appears
    9896                };
    9997
     
    204202                class FixCopyCtors final : public GenPoly::PolyMutator {
    205203                  public:
    206                         FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
    207204                        /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
    208205                        /// and destructors
    209                         static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
     206                        static void fixCopyCtors( std::list< Declaration * > &translationUnit );
    210207
    211208                        typedef GenPoly::PolyMutator Parent;
     
    214211                        virtual Expression * mutate( UniqueExpr * unqExpr ) override;
    215212                        virtual Expression * mutate( StmtExpr * stmtExpr ) override;
    216 
    217                         UnqCount & unqCount;
    218213                };
    219214
     
    277272
    278273                EnvMap envMap;
    279                 UnqCount unqCount;
    280274
    281275                InsertImplicitCalls::insert( translationUnit, envMap );
    282                 ResolveCopyCtors::resolveImplicitCalls( translationUnit, envMap, unqCount );
     276                ResolveCopyCtors::resolveImplicitCalls( translationUnit, envMap );
    283277                InsertDtors::insert( translationUnit );
    284278                FixInit::fixInitializers( translationUnit );
    285279
    286280                // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
    287                 FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
     281                FixCopyCtors::fixCopyCtors( translationUnit );
    288282
    289283                GenStructMemberCalls::generate( translationUnit );
     
    304298                }
    305299
    306                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap, UnqCount & unqCount ) {
    307                         ResolveCopyCtors resolver( envMap, unqCount );
     300                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap ) {
     301                        ResolveCopyCtors resolver( envMap );
    308302                        acceptAll( translationUnit, resolver );
    309303                }
     
    335329                }
    336330
    337                 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    338                         FixCopyCtors fixer( unqCount );
     331                void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit ) {
     332                        FixCopyCtors fixer;
    339333                        mutateAll( translationUnit, fixer );
    340334                }
     
    526520                void ResolveCopyCtors::visit( UniqueExpr * unqExpr ) {
    527521                        static std::unordered_set< int > vars;
    528                         unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
    529522                        if ( vars.count( unqExpr->get_id() ) ) {
    530523                                // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     
    643636
    644637                Expression * FixCopyCtors::mutate( UniqueExpr * unqExpr ) {
    645                         unqCount[ unqExpr->get_id() ]--;
    646                         static std::unordered_map< int, std::list< Statement * > > dtors;
    647638                        static std::unordered_map< int, UniqueExpr * > unqMap;
    648639                        static std::unordered_set< int > addDeref;
     
    654645                                delete unqExpr->get_result();
    655646                                unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
    656                                 if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
    657                                         stmtsToAdd.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
    658                                 }
    659647                                if ( addDeref.count( unqExpr->get_id() ) ) {
    660648                                        // other UniqueExpr was dereferenced because it was an lvalue return, so this one should be too
     
    663651                                return unqExpr;
    664652                        }
    665                         FixCopyCtors fixer( unqCount );
    666                         unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
    667                         stmtsToAdd.splice( stmtsToAdd.end(), fixer.stmtsToAdd );
     653                        unqExpr = safe_dynamic_cast< UniqueExpr * >( Parent::mutate( unqExpr ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
    668654                        unqMap[unqExpr->get_id()] = unqExpr;
    669655                        if ( UntypedExpr * deref = dynamic_cast< UntypedExpr * >( unqExpr->get_expr() ) ) {
     
    675661                                getCallArg( deref, 0 ) = unqExpr;
    676662                                addDeref.insert( unqExpr->get_id() );
    677                                 if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
    678                                         stmtsToAdd.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
    679                                 } else { // remember dtors for last instance of unique expr
    680                                         dtors[ unqExpr->get_id() ] = fixer.stmtsToAddAfter;
    681                                 }
    682663                                return deref;
    683664                        }
  • src/libcfa/iostream.c

    r22854f8 rcb91437  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar 22 17:46:06 2017
    13 // Update Count     : 359
     12// Last Modified On : Wed Mar 22 17:21:23 2017
     13// Update Count     : 358
    1414//
    1515
     
    201201forall( dtype ostype, otype T, ttype Params | ostream( ostype ) | writeable( T ) | { ostype * ?|?( ostype *, Params ); } )
    202202ostype * ?|?( ostype * os, T arg, Params rest ) {
    203         forall( ttype Params ) ostype * prtTuple( T arg, Params rest ) {
     203        forall( ttype Params ) ostype * prtTuple( ostype * os, T arg, Params rest ) {
    204204                os | arg;                                                                               // print first argument
    205205                os | rest;                                                                              // print remaining arguments
     
    207207        } // prtTuple
    208208        sepSetCur( os, sepGetTuple( os ) );                                     // switch to tuple separator
    209         prtTuple( arg, rest );                                                          // recursively print tuple
     209        prtTuple( os, arg, rest );                                                      // recursively print tuple
    210210        sepSetCur( os, sepGet( os ) );                                          // switch to regular separator
    211211        return os;
Note: See TracChangeset for help on using the changeset viewer.