Changeset ad47ec4
- Timestamp:
- Aug 29, 2024, 2:38:39 PM (14 months ago)
- Branches:
- master
- Children:
- 9bb6c5f
- Parents:
- 960665c (diff), b965774 (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. - Files:
-
- 18 edited
-
doc/LaTeXmacros/common.sty (modified) (2 diffs)
-
doc/LaTeXmacros/common.tex (modified) (2 diffs)
-
doc/bibliography/pl.bib (modified) (6 diffs)
-
doc/theses/fangren_yu_MMath/content1.tex (modified) (1 diff)
-
doc/theses/fangren_yu_MMath/intro.tex (modified) (1 diff)
-
doc/theses/fangren_yu_MMath/uw-ethesis-frontpgs.tex (modified) (10 diffs)
-
doc/theses/fangren_yu_MMath/uw-ethesis.tex (modified) (5 diffs)
-
libcfa/src/common.hfa (modified) (3 diffs)
-
src/AST/Decl.hpp (modified) (1 diff)
-
src/AST/Expr.hpp (modified) (1 diff)
-
src/Parser/DeclarationNode.cpp (modified) (4 diffs)
-
src/Parser/ExpressionNode.cpp (modified) (2 diffs)
-
src/Parser/ExpressionNode.hpp (modified) (2 diffs)
-
src/Parser/InitializerNode.cpp (modified) (2 diffs)
-
src/Parser/TypeData.cpp (modified) (4 diffs)
-
src/Parser/parser.yy (modified) (1 diff)
-
tests/.expect/opt-params.txt (modified) (1 diff)
-
tests/opt-params.cfa (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
doc/LaTeXmacros/common.sty
r960665c rad47ec4 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon Jun 24 08:03:28202414 %% Update Count : 6 5913 %% Last Modified On : Sun Aug 25 11:52:19 2024 14 %% Update Count : 661 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 267 267 \usepackage{listings} % format program code 268 268 \usepackage{lstlang} 269 270 \lst@AddToHook{OnEmptyLine}{\addtocounter{lstnumber}{-1}}% remove empty line number increment from listings 269 271 270 272 \newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{#1}}} -
doc/LaTeXmacros/common.tex
r960665c rad47ec4 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon Jun 24 08:01:50 202414 %% Update Count : 6 6713 %% Last Modified On : Sun Aug 25 11:52:20 2024 14 %% Update Count : 673 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 271 271 272 272 \makeatletter 273 \lst@AddToHook{OnEmptyLine}{\addtocounter{lstnumber}{-1}}% remove empty line number increment from listings 274 273 275 \newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{#1}}} 274 276 \newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}} -
doc/bibliography/pl.bib
r960665c rad47ec4 2231 2231 } 2232 2232 2233 @article{Cargill91, 2234 keywords = {C++, multiple inheritance, implementation}, 2235 contributer = {pabuhr}, 2236 author = {Tom A. Cargill}, 2237 title = {Controversy: The Case Against Multiple Inheritance in {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}}, 2238 journal = {Computer Systems}, 2239 number = 1, 2240 volume = 4, 2241 month = {Winter}, 2242 year = 1991, 2243 pages = {69-82}, 2244 } 2245 2233 2246 @unpublished{Ditchfield:conversions, 2234 2247 contributer = {a3moss@uwaterloo.ca}, … … 3610 3623 number = 1, 3611 3624 month = jan, 3612 year = {1987},3625 year = 1987, 3613 3626 pages = {1-11}, 3614 3627 publisher = {ACM}, … … 5205 5218 author = {Hesselink, Wim H. and Buhr, Peter A.}, 5206 5219 title = {MCSH, a Lock with the Standard Interface}, 5207 issue_date = {June 2023},5220 journal = {ACM Trans. Parallel Comput.}, 5208 5221 publisher = {ACM}, 5209 5222 address = {New York, NY, USA}, 5210 5223 volume = 10, 5211 5224 number = 2, 5212 journal = {ACM Trans. Parallel Comput.}, 5213 issn = {2329-4949}, 5214 articleno = 11, 5215 numpages = 23, 5225 year = 2023, 5216 5226 month = jun, 5217 year = {2023},5227 pages = {1-23}, 5218 5228 } 5219 5229 … … 5605 5615 month = may, 5606 5616 year = 1987, 5617 } 5618 5619 @article{Stroustrup89, 5620 keywords = {C++, multiple inheritance, implementation}, 5621 contributer = {pabuhr}, 5622 author = {Bjarne Stroustrup}, 5623 title = {Multiple Inheritance for {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}}, 5624 journal = {Computer Systems}, 5625 number = 4, 5626 volume = 2, 5627 month = {Fall}, 5628 year = 1989, 5629 pages = {367-395}, 5607 5630 } 5608 5631 … … 5787 5810 5788 5811 @inproceedings{Thompson90new, 5789 keywords = {Plan 9},5812 keywords = {Plan-9, unnamed substructures}, 5790 5813 contributer = {pabuhr@plg}, 5791 5814 title = {A New {C} Compiler}, … … 5794 5817 year = 1990, 5795 5818 pages = {41-51}, 5796 note = {\url{http ://doc.cat-v.org/bell_labs/new_c_compilers/new_c_compiler.pdf}},5819 note = {\url{https://doc.cat-v.org/bell_labs/new_c_compilers/new_c_compiler.pdf}}, 5797 5820 } 5798 5821 -
doc/theses/fangren_yu_MMath/content1.tex
r960665c rad47ec4 2 2 \label{c:content1} 3 3 4 This chapter discusses some recent additions to the \CFA language and their interactions with the type system. 4 This chapter discusses some recent additions to the \CFA language and their interactions with the type system. 5 5 6 6 7 \section{Reference Types} 7 8 8 Reference types are added to \CFA by Robert Schluntz in conjunction to his work on resource management. \CFA reference type is similar to \CC reference type but with its own added features. 9 10 The main difference between \CFA and \CC references is that \CC references are immutable, while \CFA supports reference rebinding operations. In \CC, references are mostly used in function parameters for pass-by-reference semantics, and in class members, which must be initialized during construction. Merely declaring a variable of reference type has little use as it only creates an alias of an existing variable. In contrast, \CFA reference variables can be reassigned (rebinded) and reference to reference is also allowed. 11 12 This example is taken from the feature demonstration page of \CFA: \footnote{Currently there are no plans of introducing \CC rvalue references to \CFA. Readers should not confuse the multi-reference declarations with \CC rvalue reference syntax.} 13 14 \begin{cfa} 9 Reference types were added to \CFA by Robert Schluntz and Aaron Moss~\cite{Moss18}. 10 The \CFA reference type generalizes the \CC reference type (and its equivalent in other modern programming languages) by providing both mutable and immutable forms and cascading referencing and dereferencing. 11 Specifically, \CFA attempts to extend programmer intuition about pointers to references. 12 That is, use a pointer when its primary purpose is manipulating the address of storage, \eg a top/head/tail pointer or link field in a mutable data structure. 13 Here, manipulating the pointer address is the primary operation, while dereferencing the pointer to its value is the secondary operation. 14 For example, \emph{within} a data structure, \eg stack or queue, all operations involve pointer addresses and the pointer may never be dereferenced because the referenced object is opaque. 15 Alternatively, use a reference when its primary purpose is to alias a value, \eg a function parameter that does not copy the argument (performance reason). 16 Here, manipulating the value is the primary operation, while changing the pointer address is the secondary operation. 17 Succinctly, if the address often changes, use a pointer; 18 if the value often changes, use a reference. 19 Note, \CC made the reference address immutable starting a \emph{belief} that immutability is a fundamental aspect of a reference's pointer, resulting in a semantic asymmetry between the pointer and reference. 20 \CFA adopts a uniform policy between pointers and references where mutability is a settable property at the point of declaration. 21 22 The following examples shows how pointers and references are treated uniformly in \CFA. 23 \begin{cfa}[numbers=left,numberblanklines=false] 15 24 int x = 1, y = 2, z = 3; 16 int * p1 = &x, ** p2 = &p1, *** p3 = &p2, // pointers to x17 & r1 = x, && r2 = r1, &&& r3 = r2; // references to x25 int * p1 = &x, ** p2 = &p1, *** p3 = &p2, $\C{// pointers to x}$ 26 @&@ r1 = x, @&&@ r2 = r1, @&&&@ r3 = r2; $\C{// references to x}$ 18 27 int * p4 = &z, & r4 = z; 19 28 20 *p1 = 3; **p2 = 3; ***p3 = 3; // change x21 r1 = 3; r2 = 3; r3 = 3; // change x: implicit dereference *r1, **r2, ***r322 **p3 = &y; *p3 = &p4; // change p1, p229 *p1 = 3; **p2 = 3; ***p3 = 3; $\C{// different ways to change x to 3}$ 30 r1 = 3; r2 = 3; r3 = 3; $\C{// change x: implicit dereference *r1, **r2, ***r3}$ 31 **p3 = &y; *p3 = &p4; $\C{// change p1, p2}$ 23 32 // cancel implicit dereferences (&*)**r3, (&(&*)*)*r3, &(&*)r4 24 &r3 = &y; &&r3 = &&r4; // change r1, r2 25 \end{cfa} 26 27 A different syntax is required for reassigning to a reference variable itself, since auto-deferencing is always performed and the expression \texttt{r1} would mean the \texttt{int} variable that \texttt{r1} referenced to instead. Using \CFA's reference types (including multi-references) we can actually describe the "lvalue" rules in C by types only, and the concept of lvalue could have been completely dropped off. However, since the cfa-cc program is not a full compiler but a transpiler from \CFA to C, lvalueness is still used in some places for code generation purposes, while the type checker now works on just types without needing to consider lvalueness of an expression. 28 29 The current typing rules used in \CFA can be summarized as follows: 30 33 @&@r3 = @&@y; @&&@r3 = @&&@r4; $\C{// change r1, r2}$ 34 \end{cfa} 35 Like pointers, reference can be cascaded, \ie a reference to a reference, \eg @&& r2@.\footnote{ 36 \CC uses \lstinline{&&} for rvalue reference a feature for move semantics and handling the \lstinline{const} Hell problem.} 37 Usage of a reference variable automatically performs the same number of dereferences as the number of references in its declaration, \eg @r3@ becomes @***r3@. 38 Finally, to reassign a reference's address needs a mechanism to stop the auto-referencing, which is accomplished by using a single reference to cancel all the auto-dereferencing, \eg @&r3 = &y@ resets @r3@'s address to point to @y@. 39 \CFA's reference type (including multi-de/references) is powerful enough to describe the lvalue rules in C by types only. 40 As a result, the \CFA type checker now works on just types without using the notion of lvalue in an expression. 41 (\CFA internals still use lvalue for code generation purposes.) 42 43 The current reference typing rules in \CFA are summarized as follows: 31 44 \begin{enumerate} 32 \item For a variable x with declared type T, the variable-expression x has type reference to T, even if T itself is a reference type. 33 \item For an expression e with type $T\&_1...\&_n$ i.e. T followed by n references, where T is not a reference type, the expression \&T (address of T) has type T* followed by n-1 references. 34 \item For an expression e with type T* followed by n references, *T has type T followed by n+1 references. This is the reverse of previous rule, such that address-of and dereference operators are perfect inverses. 35 \item When matching parameter and argument types in a function call context, the number of references on the argument type is always stripped off to match the number of references on the parameter type \footnote{\CFA allows rvalue expressions be converted to reference values by implicitly creating a temporary variable, with some restrictions.}. In an assignment context, the left-hand side operand type is always reduced to a single reference. 45 \item For a variable $x$ with declared type $T$, the variable-expression $x$ has type reference to $T$, even if $T$ itself is a reference type. 46 \item For an expression $e$ with type $T\ \&_1...\&_n$, \ie $T$ followed by $n$ references, where $T$ is not a reference type, the expression $\&T$ (address of $T$) has type $T *$ followed by $n - 1$ references. 47 \item For an expression $e$ with type $T *\&_1...\&_n$, \ie $T *$ followed by $n$ references, the expression $* T$ (dereference $T$) has type $T$ followed by $n + 1$ references. 48 This is the reverse of the previous rule, such that address-of and dereference operators are perfect inverses. 49 \item When matching parameter and argument types in a function call context, the number of references on the argument type is stripped off to match the number of references on the parameter type.\footnote{ 50 \CFA handles the \lstinline{const} Hell problem by allowing rvalue expressions to be converted to reference values by implicitly creating a temporary variable, with some restrictions.} 51 In an assignment context, the left-hand-side operand-type is always reduced to a single reference. 36 52 \end{enumerate} 37 38 Under this ruleset, in a function call context, a type parameter will never be bound to a reference type. For example given the declarations 39 40 \begin{cfa} 41 forall (T) void f (T&); 42 43 int &x; 44 \end{cfa} 45 46 The call f(x); will apply implicit dereference once to x so the call is typed f(int\&) with T=int, rather than with T=int\&. 47 48 While initially the design of reference types in \CFA seeks to make it more like a "real" data type than reference in \CC, which mostly only serves the purpose of choosing argument-passing methods (by-value or by-reference) in function calls, the inherent ambiguity of auto-dereferencing still limits the behavior of reference types in \CFA polymorphic functions. Moreover, there is also some discrepancy of how the reference types are treated in initialization and assignment expressions. In the former case no implicit dereference is applied at all (see line 3 of example code) and in the latter case there is actually no assignment operators defined for reference types; the reassignment of reference variables uses the assignment operators for pointer types instead. There is also an annoying issue (although purely syntactic) that to pass in a null value for reference initialization one has to write \texttt{int \& r1 = *0p;} which looks like dereferencing a null pointer, but the dereferencing operation does not actually happen and the expression is eventually translated into initializing the underlying pointer value to null. 49 50 This second point of difference would prevent the type system to treat reference types the same way as other types in many cases even if we allow type variables to be bound to reference types. This is because \CFA uses the common "object" trait (constructor, destructor and assignment operators) to handle passing dynamic concrete type arguments into polymorphic functions, and the reference types are handled differently in these contexts so they do not satisfy this common interface. 51 52 When generic types are introduced to \CFA, some thoughts had been put into allowing reference types as type arguments. While it is possible to write a declaration such as \texttt{vector(int\&)} for a container of reference variables, it will be disallowed in assertion checking if the generic type in question requires the object trait for the type argument (a fairly common use case) and even if the object trait can be made as non-required, the current type system often misbehaves by adding undesirable auto-dereference and operate on the referenced-to value rather than the reference variable itself as intended. Some tweaks would have to be made to accommodate reference types in polymorphic contexts and we are still not sure of what can or cannot be achieved. Currently we have to reside on using pointer types and giving up the benefits of auto-dereference operations on reference types. 53 53 Under this ruleset, a type parameter is never bound to a reference type in a function-call context. 54 \begin{cfa} 55 forall( T ) void f( T & ); 56 int & x; 57 f( x ); // implicit dereference 58 \end{cfa} 59 The call applies an implicit dereference once to @x@ so the call is typed @f( int & )@ with @T = int@, rather than with @T = int &@. 60 61 As for a pointer type, a reference type may have qualifiers, where @const@ is most interesting. 62 \begin{cfa} 63 int x = 3; $\C{// mutable}$ 64 const int cx = 5; $\C{// immutable}$ 65 int * const cp = &x, $\C{// immutable pointer}$ 66 & const cr = cx; 67 const int * const ccp = &cx, $\C{// immutable value and pointer}$ 68 & const ccr = cx; 69 // pointer 70 *cp = 7; 71 cp = &x; $\C{// error, assignment of read-only variable}$ 72 *ccp = 7; $\C{// error, assignment of read-only location}$ 73 ccp = &cx; $\C{// error, assignment of read-only variable}$ 74 // reference 75 cr = 7; 76 cr = &x; $\C{// error, assignment of read-only variable}$ 77 *ccr = 7; $\C{// error, assignment of read-only location}$ 78 ccr = &cx; $\C{// error, assignment of read-only variable}$ 79 \end{cfa} 80 Interestingly, C does not give a warning/error if a @const@ pointer is not initialized, while \CC does. 81 Hence, type @& const@ is similar to \CC reference, but \CFA does not preclude initialization with a non-variable address. 82 For example, in system's programming, there are cases where an immutable address is initialized to a specific memory location. 83 \begin{cfa} 84 int & const mem_map = *0xe45bbc67@p@; $\C{// hardware mapped registers ('p' for pointer)}$ 85 \end{cfa} 86 Finally, qualification is generalized across all pointer/reference declarations. 87 \begin{cfa} 88 const * const * const * const ccccp = ... 89 const & const & const & const ccccr = ... 90 \end{cfa} 91 92 In the initial \CFA reference design, the goal was to make the reference type a \emph{real} data type \vs a restricted \CC reference, which is mostly used for choosing the argument-passing method, by-value or by-reference. 93 However, there is an inherent ambiguity for auto-dereferencing: every argument expression involving a reference variable can potentially mean passing the reference's value or address. 94 Without any restrictions, this ambiguity limits the behaviour of reference types in \CFA polymorphic functions, where a type @T@ can bind to a reference or non-reference type. 95 This ambiguity prevents the type system treating reference types the same way as other types in many cases even if type variables could be bound to reference types. 96 The reason is that \CFA uses a common \emph{object} trait (constructor, destructor and assignment operators) to handle passing dynamic concrete type arguments into polymorphic functions, and the reference types are handled differently in these contexts so they do not satisfy this common interface. 97 98 Moreover, there is also some discrepancy in how the reference types are treated in initialization and assignment expressions. 99 For example, in line 3 of the previous example code: 100 \begin{cfa} 101 int @&@ r1 = x, @&&@ r2 = r1, @&&&@ r3 = r2; $\C{// references to x}$ 102 \end{cfa} 103 each initialization expression is implicitly dereferenced to match the types, \eg @&x@, because an address is always required and a variable normally returns its value; 104 \CC does the same implicit dereference when initializing its reference variables. 105 For lines 6 and 9 of the previous example code: 106 \begin{cfa} 107 r1 = 3; r2 = 3; r3 = 3; $\C{// change x: implicit dereference *r1, **r2, ***r3}$ 108 @&@r3 = @&@y; @&&@r3 = @&&@r4; $\C{// change r1, r2}$ 109 \end{cfa} 110 there are no actual assignment operators defined for reference types that can be overloaded; 111 instead, all reference assignments are handled by semantic actions in the type system. 112 In fact, the reassignment of reference variables is setup internally to use the assignment operators for pointer types. 113 Finally, there is an annoying issue (although purely syntactic) for setting a mutable reference to a specific address like null, @int & r1 = *0p@, which looks like dereferencing a null pointer. 114 Here, the expression is rewritten as @int & r1 = &(*0p)@, like the variable dereference of @x@ above. 115 However, the implicit @&@ needs to be cancelled for an address, which is done with the @*@, i.e., @&*@ cancel each other, giving @0p@. 116 Therefore, the dereferencing operation does not actually happen and the expression is translated into directly initializing the reference variable with the address. 117 Note, the same explicit reference is used in \CC to set a reference variable to null. 118 \begin{c++} 119 int & ip = @*@(int *)nullptr; 120 \end{c++} 121 which is used in certain systems-programming situations. 122 123 When generic types were introduced to \CFA~\cite{Moss19}, some thought was given to allow reference types as type arguments. 124 \begin{cfa} 125 forall( T ) 126 struct vector { T t; }; 127 vector( int @&@ ) vec; $\C{// vector of references to ints}$ 128 \end{cfa} 129 While it is possible to write a reference type as the argument to a generic type, it is disallowed in assertion checking, if the generic type requires the object trait for the type argument (a fairly common use case). 130 Even if the object trait can be made optional, the current type system often misbehaves by adding undesirable auto-dereference on the referenced-to value rather than the reference variable itself, as intended. 131 Some tweaks are necessary to accommodate reference types in polymorphic contexts and it is unclear what can or cannot be achieved. 132 Currently, there are contexts where \CFA programmer must use pointer types, giving up the benefits of auto-dereference operations and better syntax from reference types. 54 133 55 134 56 135 \section{Tuple Types} 57 136 58 The addition of tuple types to \CFA can be traced back to the original design by David Till in K-W C, a predecessor project of \CFA. The introduction of tuples was aiming to eliminate the need of having output parameters or defining an aggregate type in order to return multiple values from a function. In the K-W C design, tuples can be thought of as merely a syntactic sugar as it is not allowed to define a variable with tuple type. The usage of tuples are restricted to argument passing and assignments, and the translator implementation converts tuple assignments by expanding the tuple assignment expressions to assignments of each component, creating temporary variables to avoid unexpected side effects when necessary. As in the case of a function returning multiple values (thereafter called MVR functions), a struct type is created for the returning tuple and the values are extracted by field access operations. 59 60 In an early implementation of tuples in \CFA made by Rodolfo Gabriel Esteves, a different strategy is taken to handle MVR functions. The return values are converted to output parameters passed in by pointers. When the return values of a MVR function are directly used in an assignment expression, the addresses of the left-hand operands can be directly passed in to the function; composition of MVR functions is handled by creating temporaries for the returns. 61 62 Suppose we have a function returning two values as follows: 63 64 \begin{cfa} 65 [int, int] gives_two(); 66 67 int x,y; 68 [x,y] = gives_two(); 69 \end{cfa} 70 71 The K-W C implementation translates the program to 72 73 \begin{cfa} 74 struct _tuple2 { int _0; int _1; } 75 struct _tuple2 gives_two(); 76 int x,y; 77 struct _tuple2 _tmp = gives_two(); 78 x = _tmp._0; y = _tmp._1; 79 \end{cfa} 80 81 While the Rodolfo implementation translates it to 82 83 \begin{cfa} 84 void gives_two(int *, int *); 85 int x,y; 86 gives_two(&x, &y); 87 \end{cfa} 88 89 and inside the body of the function \text{gives\_two}, the return statement is rewritten to assignments into the passed-in addresses. 90 91 The latter implementation looks much more concise, and in the case of returning values having nontrivial types (e.g. structs), this implementation can also save some unnecessary copying. 92 93 Interestingly, in Robert Schluntz's rework of the tuple type, the implementation got reverted back to struct-based, and it remained in the current version of cfa-cc translator. During the same time of his work, generic types were being added into \CFA independently as another feature, and the tuple type was changed to use the same implementation techniques of generic types. Consequently, it made tuples become first-class values in \CFA. 94 95 However, upon further investigation, making tuple types first-class has very little benefits in \CFA, mainly because that function call semantics with tuples are designed to be unstructured, and that since operator overloading in \CFA are implemented by treating every overloadable operator as functions, tuple types are very rarely used in a structured way. When a tuple-type expression appears in a function call (except assignment expressions, which are handled differently by mass- or multiple-assignment expansions), it is always flattened, and the tuple structure of function parameter is not considered a part of the function signature, for example 96 97 \begin{cfa} 98 void f(int, int); 99 void f([int, int]); 100 \end{cfa} 101 102 are considered to have the same signature (a function taking two ints and returning nothing), and therefore not valid overloads. Furthermore, ordinary polymorphic type parameters are not allowed to have tuple types in order to restrict the expression resolution algorithm to not create too many argument-parameter matching options, such that the type-checking problem remains tractable and does not take too long to compute. Therefore tuple types are never present in any fixed-argument function calls. 103 104 A type-safe variadic argument signature was proposed using \CFA's \texttt{forall} clause and a new tuple parameter type, denoted previously by the \texttt{ttype} keyword and now by the ellipsis syntax similar to \CC's template parameter pack. 105 106 The C \texttt{printf} function, for example, can be rewritten using the new variadic argument, in favor of the C untyped \texttt{va\_list} interface as 107 108 \begin{cfa} 109 forall (TT...) int printf(char *fmt, TT args); 110 \end{cfa} 111 112 Note that this is just for illustration purposes, as type assertions are needed to actually achieve type safety, and \CFA's I/O library does not use a format string since argument types are inferred by the type system. 113 114 There are two common patterns for using the variadic function in \CFA: one is to forward the arguments to another function 115 116 \begin{cfa} 117 forall(T*, TT... | {void ?{}(T &, TT);}) 118 T* new (T, TT) { return ((T*)malloc()){TT}; } 119 \end{cfa} 120 121 and the other is structural recursion which extracts arguments one at a time 122 123 \begin{cfa} 124 forall( ostype &, T, Params... | { ostype & ?|?( ostype &, T); ostype & ?|?( ostype &, Params ); } ) 125 ostype & ?|?( ostype & os, T arg, Params rest ); 126 \end{cfa} 127 128 The above is the actual implementation of variadic print function in \CFA. \texttt{ostype} represents the output stream, similar to \CC's \texttt{ostream} interface. Note that recursion must be used in order to extract type information of the first argument in the list, as opposed to C \texttt{va\_list} variadics which uses a loop to extract each argument, and generally requires some companion data that provides type information, such as the format string in \texttt{printf}. 129 130 Variadic polymorphic functions are somehow currently the only place tuple types are used in functions. And just like the case for user-defined generic types, many wrapper functions need to be generated to implement polymorphism with variadics. However, note that the only permitted operations on polymorphic function parameters are given by the assertion (trait) functions, and those eventually need to be supplied flattened tuple arguments, packing the variadic arguments into a rigid struct type and generating all the required wrapper functions become mostly wasted work. Interested readers can refer to pages 77-80 of Robert Schluntz's thesis to see how verbose the translator output needs to be to implement a simple variadic call with 3 arguments, and it will quickly become even worse if the number of arguments is increased: for a call with 5 arguments the translator would have to generate concrete struct types for a 4-tuple and a 3-tuple along with all the polymorphic type data for them! Instead, a much simpler approach of putting all variadic arguments into a data array and providing an offset array to retrieve each individual argument can be utilized. This method is very similar to how the C \texttt{va\_list} object is used, with \CFA type resolver validating and generating the required type information to guarantee type safety. 131 132 The print function example 133 134 \begin{cfa} 135 forall(T, Params... | { void print(T); void print(Params ); }) 136 void print(T arg , Params rest) { 137 print(arg); 138 print(rest); 137 The addition of tuple types to \CFA can be traced back to the original design by David Till in \mbox{K-W C}~\cite{Till89,Buhr94a}, a predecessor project of \CFA. 138 The primary purpose of tuples is to eliminate output parameters or creating an aggregate type to return multiple values from a function, called a multiple-value-returning (MVR) function. 139 The following examples shows the two techniques for a function returning three values. 140 \begin{cquote} 141 \begin{tabular}{@{}l@{\hspace{20pt}}l@{}} 142 \begin{cfa} 143 144 int foo( int &p2, int &p3 ); // in/out parameters 145 int x, y = 3, z = 4; 146 x = foo( y, z ); // return 3 values 147 \end{cfa} 148 & 149 \begin{cfa} 150 struct Ret { int x, y, z; }; 151 Ret foo( int p2, int p3 ); // multiple return values 152 Ret ret = { .y = 3, .z = 4 }; 153 ret = foo( ret.y, ret.z ); // return 3 values 154 \end{cfa} 155 \end{tabular} 156 \end{cquote} 157 where K-W C allows direct return of multiple values. 158 \begin{cfa} 159 @[int, int, int]@ foo( int p2, int p3 ); 160 @[x, y, z]@ = foo( y, z ); // return 3 values into a tuple 161 \end{cfa} 162 Along with simplifying returning multiple values, tuples can be extended to simplify a number of other common context that normally require multiple statements and/or additional declarations, all of which reduces coding time and errors. 163 \begin{cfa} 164 [x, y, z] = 3; $\C[2in]{// x = 3; y = 3; z = 3, where types are different}$ 165 [x, y] = [y, x]; $\C{// int tmp = x; x = y; y = tmp;}$ 166 void bar( int, int, int ); 167 @bar@( foo( 3, 4 ) ); $\C{// int t0, t1, t2; [t0, t1, t2] = foo( 3, 4 ); bar( t0, t1, t2 );}$ 168 x = foo( 3, 4 )@.1@; $\C{// int t0, t1, t2; [t0, t1, t2] = foo( 3, 4 ); x = t1;}\CRT$ 169 \end{cfa} 170 For the call to @bar@, the three results from @foo@ are \newterm{flattened} into individual arguments. 171 Flattening is how tuples interact with parameter and subscript lists, and with other tuples, \eg: 172 \begin{cfa} 173 [ [ x, y ], z, [a, b, c] ] = [2, [3, 4], foo( 3, 4) ] $\C{// structured}$ 174 [ x, y, z, a, b, c] = [2, 3, 4, foo( 3, 4) ] $\C{// flattened, where foo results are t0, t1, t2}$ 175 \end{cfa} 176 177 Note, the \CFA type-system supports complex composition of tuples and C type conversions using a costing scheme giving lower cost to widening conversions that do not truncate a value. 178 \begin{cfa} 179 [ int, int ] foo$\(_1\)$( int ); $\C{// overloaded foo functions}$ 180 [ double ] foo$\(_2\)$( int ); 181 void bar( int, double, double ); 182 bar( foo( 3 ), foo( 3 ) ); 183 \end{cfa} 184 The type resolver only has the tuple return types to resolve the call to @bar@ as the @foo@ parameters are identical, which involves unifying the flattened @foo@ return values with @bar@'s parameter list. 185 However, no combination of @foo@s is an exact match with @bar@'s parameters; 186 thus, the resolver applies C conversions to obtain a best match. 187 The resulting minimal cost expression is @bar( foo@$_1$@( 3 ), foo@$_2$@( 3 ) )@, where the two possible coversions are (@int@, {\color{red}@int@}, @double@) to (@int@, {\color{red}@double@}, @double@) with a safe (widening) conversion from @int@ to @double@ versus ({\color{red}@double@}, {\color{red}@int@}, {\color{red}@int@}) to ({\color{red}@int@}, {\color{red}@double@}, {\color{red}@double@}) with one unsafe (narrowing) conversion from @double@ to @int@ and two safe conversions from @int@ to @double@. 188 The programming language Go provides a similar but simplier tuple mechanism, as it does not have overloaded functions. 189 190 The K-W C tuples are merely syntactic sugar, as there is no mechanism to define a variable with tuple type. 191 For the tuple-returning implementation, an implicit @struct@ type is created for the returning tuple and the values are extracted by field access operations. 192 For the tuple-assignment implementation, the left-hand tuple expression is expanded into assignments of each component, creating temporary variables to avoid unexpected side effects. 193 For example, a structure is returned from @foo@ and its fields are individually assigned to the left-hand variables, @x@, @y@, @z@. 194 195 In the second implementation of \CFA tuples by Rodolfo Gabriel Esteves~\cite{Esteves04}, a different strategy is taken to handle MVR functions. 196 The return values are converted to output parameters passed in by pointers. 197 When the return values of a MVR function are directly used in an assignment expression, the addresses of the left-hand operands can be directly passed into the function; 198 composition of MVR functions is handled by creating temporaries for the returns. 199 For example, given a function returning two values: 200 \begin{cfa} 201 [int, int] gives_two() { int r1, r2; ... return [ r1, r2 ]; } 202 int x, y; 203 [x, y] = gives_two(); 204 \end{cfa} 205 The K-W C implementation translates the program to: 206 \begin{cfa} 207 struct _tuple2 { int _0; int _1; } 208 struct _tuple2 gives_two(); 209 int x, y; 210 struct _tuple2 _tmp = gives_two(); 211 x = _tmp._0; y = _tmp._1; 212 \end{cfa} 213 While the Rodolfo implementation translates it to: 214 \begin{cfa} 215 void gives_two( int * r1, int * r2 ) { ... *r1 = ...; *r2 = ...; return; } 216 int x, y; 217 gives_two( &x, &y ); 218 \end{cfa} 219 and inside the body of the function @gives_two@, the return statement is rewritten as assignments into the passed-in argument addresses. 220 This implementation looks more concise, and in the case of returning values having nontrivial types (\eg aggregates), this implementation saves unnecessary copying. 221 For example, 222 \begin{cfa} 223 [ x, y ] gives_two(); 224 int x, y; 225 [ x, y ] = gives_two(); 226 \end{cfa} 227 becomes 228 \begin{cfa} 229 void gives_two( int &, int & ); 230 int x, y; 231 gives_two( x, y ); 232 \end{cfa} 233 eliminiating any copying in or out of the call. 234 The downside is indirection within @gives_two@ to access values, unless values get hoisted into registers for some period of time, which is common. 235 236 Interestingly, in the third implementation of \CFA tuples by Robert Schluntz~\cite[\S~3]{Schluntz17}, the tuple type reverts back to structure based, where it remains in the current version of the cfa-cc translator. 237 The reason for the reversion was to make tuples become first-class types in \CFA, \ie allow tuple variables. 238 This extension was possible, because in parallel with Schluntz's work, generic types were being added independently by Moss~\cite{Moss19}, and the tuple variables leveraged the same implementation techniques as the generic variables. 239 240 However, after experience gained building the \CFA runtime system, making tuple-types first-class seems to add little benefit. 241 The main reason is that tuples usages are largely unstructured, 242 \begin{cfa} 243 [int, int] foo( int, int ); $\C[2in]{// unstructured function}$ 244 typedef [int, int] Pair; $\C{// tuple type}$ 245 Pair bar( Pair ); $\C{// structured function}$ 246 int x = 3, y = 4; 247 [x, y] = foo( x, y ); $\C{// unstructured call}$ 248 Pair ret = [3, 4]; $\C{// tuple variable}$ 249 ret = bar( ret ); $\C{// structured call}\CRT$ 250 \end{cfa} 251 Basically, creating the tuple-type @Pair@ is largely equivalent to creating a @struct@ type, and creating more types and names defeats the simplicity that tuples are trying to achieve. 252 Furthermore, since operator overloading in \CFA is implemented by treating operators as overloadable functions, tuple types are very rarely used in a structured way. 253 When a tuple-type expression appears in a function call (except assignment expressions, which are handled differently by mass- or multiple-assignment expansions), it is always flattened, and the tuple structure of function parameter is not considered a part of the function signatures. 254 For example, 255 \begin{cfa} 256 void f( int, int ); 257 void f( [int, int] ); 258 f( 3, 4 ); // ambiguous call 259 \end{cfa} 260 the two prototypes for @foo@ have the same signature (a function taking two @int@s and returning nothing), and therefore invalid overloads. 261 Note, the ambiguity error occurs at the call rather than at the second declaration of @f@, because it is possible to have multiple equivalent prototype definitions of a function. 262 Furthermore, ordinary polymorphic type-parameters are not allowed to have tuple types. 263 \begin{cfa} 264 forall( T ) T foo( T ); 265 int x, y, z; 266 [x, y, z] = foo( [x, y, z] ); // substitute tuple type for T 267 \end{cfa} 268 Without this restriction, the expression resolution algorithm can create too many argument-parameter matching options. 269 For example, with multiple type parameters, 270 \begin{cfa} 271 forall( T, U ) void f( T, U ); 272 f( [1, 2, 3, 4] ); 273 \end{cfa} 274 the call to @f@ can be interpreted as @T = [1]@ and @U = [2, 3, 4, 5]@, or @T = [1, 2]@ and @U = [3, 4, 5]@, and so on. 275 The restriction ensures type checking remains tractable and does not take too long to compute. 276 Therefore, tuple types are never present in any fixed-argument function calls. 277 278 Finally, a type-safe variadic argument signature was added by Robert Schluntz~\cite[\S~4.1.2]{Schluntz17} using @forall@ and a new tuple parameter-type, denoted by the keyword @ttype @ in Schluntz's implementation, but changed to the ellipsis syntax similar to \CC's template parameter pack. 279 For C variadics, the number and types of the arguments must be conveyed in some way, \eg @printf@ uses a format string indicating the number and types of the arguments. 280 \VRef[Figure]{f:CVariadicMaxFunction} shows an $N$ argument @maxd@ function using the C untyped @va_list@ interface. 281 In the example, the first argument is the number of following arguments, and the following arguments are assumed to be @double@; 282 looping is used to traverse the argument pack from left to right. 283 The @va_list@ interface is walking up (by address) the stack looking at the arguments pushed by the caller. 284 (Magic knowledge is needed for arguments pushed using registers.) 285 286 \begin{figure} 287 \begin{cfa} 288 double maxd( int @count@, ... ) { 289 double max = 0; 290 va_list args; 291 va_start( args, count ); 292 for ( int i = 0; i < count; i += 1 ) { 293 double num = va_arg( args, double ); 294 if ( num > max ) max = num; 139 295 } 140 \end{cfa} 141 142 using the offset array approach, can be converted to pseudo-\CFA code (ignoring type assertions for T) as 143 144 \begin{cfa} 145 void print(T arg, char* _data_rest, size_t* _offset_rest) { 146 print(arg); 147 print(*((typeof rest.0)*) _data_rest, // first element of rest 148 _data_rest + _offset_rest[0], // remainder of data 149 _offset_rest + 1); // remainder of offset array 150 } 151 \end{cfa} 152 153 where the fixed-arg polymorphism for T can be handled by the standard \texttt{void*}-based \CFA polymorphic calling conventions, and the type information can all be deduced at the call site. 154 155 Turning tuples into first-class values in \CFA does have a few benefits, namely allowing pointers to tuples and arrays of tuples to exist. However it seems very unlikely that these types can have realistic use cases that are hard to achieve without them. And indeed having the pointer-to-tuple type to exist at all will potentially forbid the simple offset-array implementation of variadic polymorphism (in case that a type assertion requests the pointer type \texttt{Params*} in the above example, forcing the tuple type to be materialized as a struct), and thus incurring a high cost. Perhaps it is of best interest to keep tuples as non-first-class, as Rodolfo originally describes them to "[does] not enforce a particular memory layout, and in particular, [does] not guarantee that the components of a tuple occupy a contiguous region of memory," and therefore to be able to use the simplified implementations for MVR and variadic functions. 156 157 One final topic worth discussing is that the strategy of converting return values to output parameters can be utilized to implement copy elision, which is relevant for \CFA since constructors are introduced to the language. However, the first example given in this section 158 159 \begin{cfa} 160 int x,y; 161 [x,y] = gives_two(); 162 \end{cfa} 163 164 actually \textit{cannot} have copy elision applied, since the call to \texttt{gives\_two} appears in an \textit{assignment} context rather than an initialization context, as the variables x and y may be already initialized. Unfortunately \CFA currently does not support declaring variables in tuple form: 165 166 \begin{cfa} 167 [int x, int y] = gives_two(); // NOT ALLOWED 168 \end{cfa} 169 170 It is possible to declare a tuple-typed variable and call MVR functions in initialization context 171 172 \begin{cfa} 173 [int, int] ret = gives_two(); // OK 174 \end{cfa} 175 176 but using the values is more awkward as we cannot give them separate names and have to use \texttt{ret.0} or \texttt{ret.1} to extract the values. If copy elision semantics were to be added to \CFA it would be preferable to allow declaring variables in tuple form to have the benefit of eliding copy construction while giving each variable a unique name. 177 178 \section{Plan-9 Struct Inheritance} 179 180 Plan-9 Inheritance is a non-standard C feature originally introduced by the C dialect used in Bell Labs' Plan-9 research operating system, and is supported by mainstream C compilers such as GCC and Clang. This feature allows an aggregate type (struct or union) to be embedded into another one with implicit access semantics similar to anonymous substructures. 181 182 In standard C, it is possible to define a field with an anonymous struct or union type within another. This is often utilized to implement a tagged union: 183 184 \begin{cfa} 185 296 va_end(args); 297 return max; 298 } 299 printf( "%g\n", maxd( @4@, 25.0, 27.3, 26.9, 25.7 ) ); 300 \end{cfa} 301 \caption{C Variadic Maximum Function} 302 \label{f:CVariadicMaxFunction} 303 \end{figure} 304 305 There are two common patterns for using the variadic functions in \CFA. 306 \begin{enumerate}[leftmargin=*] 307 \item 308 Argument forwarding to another function, \eg: 309 \begin{cfa} 310 forall( T *, TT ... | { @void ?{}( T &, TT );@ } ) // constructor assertion 311 T * new( TT tp ) { return ((T *)malloc())@{@ tp @}@; } // call constructor on storage 312 \end{cfa} 313 Note, the assertion on @T@ requires it to have a constructor @?{}@. 314 The function @new@ calls @malloc@ to obtain storage and then invokes @T@'s constructor passing the tuple pack by flattening it over the constructor's arguments, \eg: 315 \begin{cfa} 316 struct S { int i, j; }; 317 void ?{}( S & s, int i, int j ) { s.[ i, j ] = [ i, j ]; } // constructor 318 S * sp = new( 3, 4 ); // flatten [3, 4] into call ?{}( 3, 4 ); 319 \end{cfa} 320 \item 321 Structural recursion for processing the argument-pack values one at a time, \eg: 322 \begin{cfa} 323 forall( T | { int ?>?( T, T ); } ) 324 T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; } 325 $\vspace{-10pt}$ 326 forall( T, TT ... | { T max( T, T ); T max( TT ); } ) 327 T max( T arg, TT args ) { return max( arg, max( args ) ); } 328 \end{cfa} 329 The first non-recursive @max@ function is the polymorphic base-case for the recursion, \ie, find the maximum of two identically typed values with a greater-than (@>@) operator. 330 The second recursive @max@ function takes two parameters, a @T@ and a @TT@ tuple pack, handling all argument lengths greater than two. 331 The recursive function computes the maximum for the first argument and the maximum value of the rest of the tuple pack. 332 The call of @max@ with one argument is the recursive call, where the tuple pack is converted into two arguments by taking the first value (lisp @car@) from the tuple pack as the first argument (flattening) and the remaining pack becomes the second argument (lisp @cdr@). 333 The recursion stops when the argument pack is empty. 334 For example, @max( 2, 3, 4 )@ matches with the recursive function, which performs @return max( 2, max( [3, 4] ) )@ and one more step yields @return max( 2, max( 3, 4 ) )@, so the tuple pack is empty. 335 \end{enumerate} 336 337 As an aside, polymorphic functions are precise with respect to their parameter types, \eg @max@ states all argument values must be the same type, which logically makes sense. 338 However, this precision precludes normal C conversions among the base types, \eg, this mix-mode call @max( 2h, 2l, 3.0f, 3.0ld )@ fails because the types are not the same. 339 Unfortunately, this failure violates programmer intuition because there are specialized two-argument non-polymorphic versions of @max@ that work, \eg @max( 3, 3.5 )@. 340 Allowing C conversions for polymorphic types will require a significant change to the type resolver. 341 342 Currently in \CFA, variadic polymorphic functions are the only place tuple types are used. 343 And because \CFA compiles polymorphic functions versus template expansion, many wrapper functions are generated to implement both user-defined generic-types and polymorphism with variadics. 344 Fortunately, the only permitted operations on polymorphic function parameters are given by the list of assertion (trait) functions. 345 Nevertheless, this small set of functions eventually need to be called with flattened tuple arguments. 346 Unfortunately, packing the variadic arguments into a rigid @struct@ type and generating all the required wrapper functions is significant work and largely wasted because most are never called. 347 Interested readers can refer to pages 77-80 of Robert Schluntz's thesis to see how verbose the translator output is to implement a simple variadic call with 3 arguments. 348 As the number of arguments increases, \eg a call with 5 arguments, the translator generates a concrete @struct@ types for a 4-tuple and a 3-tuple along with all the polymorphic type data for them. 349 An alternative approach is to put the variadic arguments into an array, along with an offset array to retrieve each individual argument. 350 This method is similar to how the C @va_list@ object is used (and how \CFA accesses polymorphic fields in a generic type), but the \CFA variadics generate the required type information to guarantee type safety. 351 For example, given the following heterogeneous, variadic, typed @print@ and usage. 352 \begin{cquote} 353 \begin{tabular}{@{}ll@{}} 354 \begin{cfa} 355 forall( T, TT ... | { void print( T ); void print( TT ); } ) 356 void print( T arg , TT rest ) { 357 print( arg ); 358 print( rest ); 359 } 360 \end{cfa} 361 & 362 \begin{cfa} 363 void print( int i ) { printf( "%d ", i ); } 364 void print( double d ) { printf( "%g ", d ); } 365 ... // other types 366 int i = 3 ; double d = 3.5; 367 print( i, d ); 368 \end{cfa} 369 \end{tabular} 370 \end{cquote} 371 it would look like the following using the offset-array implementation approach. 372 \begin{cfa} 373 void print( T arg, char * _data_rest, size_t * _offset_rest ) { 374 print( arg ); 375 print( *((typeof rest.0)*) _data_rest, $\C{// first element of rest}$ 376 _data_rest + _offset_rest[0], $\C{// remainder of data}$ 377 _offset_rest + 1); $\C{// remainder of offset array}$ 378 } 379 \end{cfa} 380 where the fixed-arg polymorphism for @T@ can be handled by the standard @void *@-based \CFA polymorphic calling conventions, and the type information can all be deduced at the call site. 381 Note, the variadic @print@ supports heterogeneous types because the polymorphic @T@ is not returned (unlike variadic @max@), so there is no cascade of type relationships. 382 383 Turning tuples into first-class values in \CFA does have a few benefits, namely allowing pointers to tuples and arrays of tuples to exist. 384 However, it seems unlikely that these types have realistic use cases that cannot be achieved without them. 385 And having a pointer-to-tuple type potentially forbids the simple offset-array implementation of variadic polymorphism. 386 For example, in the case where a type assertion requests the pointer type @TT *@ in the above example, it forces the tuple type to be a @struct@, and thus incurring a high cost. 387 My conclusion is that tuples should not be structured (first-class), rather they should be unstructured. 388 This agrees with Rodolfo's original describes 389 \begin{quote} 390 As such, their [tuples] use does not enforce a particular memory layout, and in particular, does not guarantee that the components of a tuple occupy a contiguous region of memory.~\cite[pp.~74--75]{Esteves04} 391 \end{quote} 392 allowing the simplified implementations for MVR and variadic functions. 393 394 Finally, a missing feature for tuples is using an MVR in an initialization context. 395 Currently, this feature is \emph{only} possible when declaring a tuple variable. 396 \begin{cfa} 397 [int, int] ret = gives_two(); $\C{// no constructor call (unstructured)}$ 398 Pair ret = gives_two(); $\C{// constructor call (structured)}$ 399 \end{cfa} 400 However, this forces the programer to use a tuple variable and possibly a tuple type to support a constructor, when they actually want separate variables with separate constructors. 401 And as stated previously, type variables (structured tuples) are rare in general \CFA programming so far. 402 To address this issue, while retaining the ability to leverage constructors, the following new tuple-like declaration syntax is proposed. 403 \begin{cfa} 404 [ int x, int y ] = gives_two(); 405 \end{cfa} 406 where the semantics is: 407 \begin{cfa} 408 T t0, t1; 409 [ t0, t1 ] = gives_two(); 410 T x = t0; // constructor call 411 T y = t1; // constructor call 412 \end{cfa} 413 and the implementation performs as much copy elision as possible. 414 415 416 \section{\lstinline{inline} Substructure} 417 418 C allows an anonymous aggregate type (@struct@ or @union@) to be embedded (nested) within another one, \eg a tagged union. 419 \begin{cfa} 420 struct S { 421 unsigned int tag; 422 union { $\C{// anonymous nested aggregate}$ 423 int x; double y; char z; 424 }; 425 } s; 426 \end{cfa} 427 The @union@ field-names are hoisted into the @struct@, so there is direct access, \eg @s.x@; 428 hence, field names must be unique. 429 For a nested anonymous @struct@, both field names and values are hoisted. 430 \begin{cquote} 431 \begin{tabular}{@{}l@{\hspace{35pt}}l@{}} 432 original & rewritten \\ 433 \begin{cfa} 434 struct S { 435 struct { int i, j; }; 436 struct { int k, l; }; 437 }; 438 \end{cfa} 439 & 440 \begin{cfa} 441 struct S { 442 int i, j; 443 int k, l; 444 }; 445 \end{cfa} 446 \end{tabular} 447 \end{cquote} 448 449 As an aside, C nested \emph{named} aggregates behave in a (mysterious) way because the nesting is allowed but there is no ability to use qualification to access an inner type, like the \CC type operator `@::@'. 450 In fact, all named nested aggregates are hoisted to global scope, regardless of the nesting depth. 451 \begin{cquote} 452 \begin{tabular}{@{}l@{\hspace{35pt}}l@{}} 453 original & rewritten \\ 454 \begin{cfa} 455 struct S { 456 struct T { 457 int i, j; 458 }; 459 struct U { 460 int k, l; 461 }; 462 }; 463 \end{cfa} 464 & 465 \begin{cfa} 186 466 struct T { 187 unsigned int tag; 188 union { 189 int x; 190 double y; 191 char z; 192 }; 193 } t; 194 \end{cfa} 195 196 The union fields can be directly accessed using their names, such as \texttt{T.x}. With Plan-9 extensions enabled, the same can be applied to a struct or union type defined elsewhere. \CFA uses the inline specifier to denote the anonymously embedded field. 197 198 In GCC it is possible to simply use\texttt{struct B \{struct A;\}} 199 for the Plan-9 feature; since \CFA no longer requires the struct and union keywords in variable declarations, having a keyword to denote Plan-9 inheritance is preferable. 200 201 \begin{cfa} 202 struct A {int x;}; 203 204 struct B { 205 inline A; 206 int y; 207 }; 208 209 B b; 210 b.x; // accesses the embedded struct A's field 211 \end{cfa} 212 213 As the \CFA translator simply just reduce the source code to C, usually the non-standard C features do not need any special treatment, and are directly passed down to the C compiler. However, the Plan-9 semantics allow implicit conversions from the outer type to the inner type, which means the type checking algorithm must take that information into account. Therefore, the \CFA translator must implement the Plan-9 features and insert the type conversions into the translated code output. In the current version of \CFA, this is the only kind of implicit type conversion other than the standard C conversions. 214 215 Since variable overloading is possible, \CFA's implementation of Plan-9 inheritance allows duplicate field names. When an outer field and an embedded field have the same name and type, the inner field is shadowed and cannot be accessed directly by name. While such definitions are allowed, using duplicate names is not good practice in general and should be avoided if possible. 216 217 Plan-9 fields can be nested, and a struct definition can contain multiple Plan-9 embedded fields. In particular, the "diamond pattern" can occur and result in a nested field to be embedded twice. 218 219 \begin{cfa} 220 struct A {int x;}; 221 struct B {inline A;}; 222 struct C {inline A;}; 223 224 struct D { 225 inline B; 226 inline C; 227 }; 228 229 D d; 230 \end{cfa} 231 232 In the above example, the expression \texttt{d.x} becomes ambiguous, since it can refer to the indirectly embedded field either from B or from C. It is still possible to disambiguate the expression by first casting the outer struct to one of the directly embedded type, such as \texttt{((B)d).x} 233 234 235 236 467 int i, j; 468 }; 469 struct U { 470 int k, l; 471 }; 472 struct S { 473 }; 474 \end{cfa} 475 \end{tabular} 476 \end{cquote} 477 Hence, the possible accesses are: 478 \begin{cfa} 479 struct S s; // s cannot access any fields 480 struct T t; t.i; t.j; 481 struct U u; u.k; u.l; 482 \end{cfa} 483 and the hoisted type names can clash with global types names. 484 For good reasons, \CC chose to change this semantics~\cite[C.1.2.3.3]{C++}: 485 \begin{description}[leftmargin=*,topsep=3pt,itemsep=0pt,parsep=0pt] 486 \item[Change:] A struct is a scope in C++, not in C. 487 \item[Rationale:] Class scope is crucial to C++, and a struct is a class. 488 \item[Effect on original feature:] Change to semantics of well-defined feature. 489 \item[Difficulty of converting:] Semantic transformation. 490 \item[How widely used:] C programs use @struct@ extremely frequently, but the change is only noticeable when @struct@, enumeration, or enumerator names are referred to outside the @struct@. 491 The latter is probably rare. 492 \end{description} 493 However, there is no syntax to access from a variable through a type to a field. 494 \begin{cfa} 495 struct S s; @s::T@.i; @s::U@.k; 496 \end{cfa} 497 498 As an aside, \CFA also provides a backwards compatible \CC nested-type. 499 \begin{cfa} 500 struct S { 501 @auto@ struct T { 502 int i, j; 503 }; 504 @auto@ struct U { 505 int k, l; 506 }; 507 }; 508 \end{cfa} 509 The keyword @auto@ denotes a local (scoped) declaration, and here, it implies a local (scoped) type, using dot as the type qualifier, \eg @S.T t@. 510 Alternatively, \CFA could adopt the \CC non-compatible change for nested types, since it may have already forced certain coding changes in C libraries that must be parsed by \CC. 511 512 % https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html 513 514 A polymorphic extension to nested aggregates appears in the Plan-9 C dialect, used in the Bell Labs' Plan-9 research operating system. 515 The feature is called \newterm{unnamed substructures}~\cite[\S~3.3]{Thompson90new}, which continues to be supported by @gcc@ and @clang@ using the extension (@-fplan9-extensions@). 516 The goal is to provided the same effect of the nested aggregate with the aggregate type defined elsewhere, which requires it be named. 517 \begin{cfa} 518 union U { $\C{// unnested named}$ 519 int x; double y; char z; 520 } u; 521 struct W { 522 int i; double j; char k; 523 } w; 524 struct S { 525 @struct W;@ $\C{// Plan-9 substructure}$ 526 unsigned int tag; 527 @union U;@ $\C{// Plan-9 substructure}$ 528 } s; 529 \end{cfa} 530 Note, the position of the substructure is normally unimportant. 531 Like the anonymous nested types, the aggregate field names are hoisted into @struct S@, so there is direct access, \eg @s.x@ and @s.i@. 532 However, like the implicit C hoisting of nested structures, the field names must be unique and the type names are now at a different scope level, unlike type nesting in \CC. 533 In addition, a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls, providing containment inheritance with implicit subtyping, \ie @U@ $\subset$ @S@ and @W@ $\subset$ @S@. 534 For example: 535 \begin{cfa} 536 void f( union U * u ); 537 void g( struct W * ); 538 union U * up; 539 struct W * wp; 540 struct S * sp; 541 up = sp; $\C{// assign pointer to U in S}$ 542 wp = sp; $\C{// assign pointer to W in S}$ 543 f( &s ); $\C{// pass pointer to U in S}$ 544 g( &s ); $\C{// pass pointer to W in S}$ 545 \end{cfa} 546 547 \CFA extends the Plan-9 substructure by allowing polymorphism for values and pointers. 548 The extended substructure is denoted using @inline@, allowing backwards compatibility to existing Plan-9 features. 549 \begin{cfa} 550 struct S { 551 @inline@ W; $\C{// extended Plan-9 substructure}$ 552 unsigned int tag; 553 @inline@ U; $\C{// extended Plan-9 substructure}$ 554 } s; 555 \end{cfa} 556 Note, like \CC, \CFA allows optional prefixing of type names with their kind, \eg @struct@, @union@, and @enum@, unless there is ambiguity with variable names in the same scope. 557 The following shows both value and pointer polymorphism. 558 \begin{cfa} 559 void f( U, U * ); $\C{// value, pointer}$ 560 void g( W, W * ); $\C{// value, pointer}$ 561 U u, * up; 562 S s, * sp; 563 W w, * wp; 564 u = s; up = sp; $\C{// value, pointer}$ 565 w = s; wp = sp; $\C{// value, pointer}$ 566 f( s, &s ); $\C{// value, pointer}$ 567 g( s, &s ); $\C{// value, pointer}$ 568 \end{cfa} 569 570 In general, non-standard C features (@gcc@) do not need any special treatment, as they are directly passed through to the C compiler. 571 However, the Plan-9 semantics allow implicit conversions from the outer type to the inner type, which means the \CFA type resolver must take this information into account. 572 Therefore, the \CFA translator must implement the Plan-9 features and insert necessary type conversions into the translated code output. 573 In the current version of \CFA, this is the only kind of implicit type conversion other than the standard C conversions. 574 575 Since variable overloading is possible in \CFA, \CFA's implementation of Plan-9 polymorphism allows duplicate field names. 576 When an outer field and an embedded field have the same name and type, the inner field is shadowed and cannot be accessed directly by name. 577 While such definitions are allowed, duplicate field names is not good practice in general and should be avoided if possible. 578 Plan-9 fields can be nested, and a struct definition can contain multiple Plan-9 embedded fields. 579 In particular, the \newterm{diamond pattern}~\cite[\S~6.1]{Stroustrup89}\cite[\S~4]{Cargill91} can occur and result in a nested field to be embedded twice. 580 \begin{cfa} 581 struct A { int x; }; 582 struct B { inline A; }; 583 struct C { inline A; }; 584 struct D { 585 inline B; 586 inline C; 587 }; 588 D d; 589 \end{cfa} 590 In the above example, the expression @d.x@ becomes ambiguous, since it can refer to the indirectly embedded field either from @B@ or from @C@. 591 It is still possible to disambiguate the expression by first casting the outer struct to one of the directly embedded type, such as @((B)d).x@. -
doc/theses/fangren_yu_MMath/intro.tex
r960665c rad47ec4 1 1 \chapter{Introduction} 2 2 3 Testing glossy abbreviations \gls{foo} and \gls{bar}, and glossy definitions \gls{git} and \gls{gulp}. 3 This thesis is exploratory work I did to understand, fix, and extend the \CFA type-system, specifically, the type resolver used to select polymorphic types among overloaded names. 4 The \CFA type-system has a number of unique features making it different from all other programming languages. 4 5 5 And use the glossy abbreviations \gls{foo} and \gls{bar}, and definitions \gls{git} and \gls{gulp} again. 6 Overloading allows programmers to use the most meaningful names without fear of name clashes within a program or from external sources, like include files. 7 \begin{quote} 8 There are only two hard things in Computer Science: cache invalidation and naming things. --- Phil Karlton 9 \end{quote} 10 Experience from \CC and \CFA developers is that the type system implicitly and correctly disambiguates the majority of overloaded names, \ie it is rare to get an incorrect selection or ambiguity, even among hundreds of overloaded (variables and) functions. 11 In many cases, a programmer has no idea there are name clashes, as they are silently resolved, simplifying the development process. 12 Depending on the language, ambiguous cases are resolved using some form of qualification and/or casting. 13 14 One of the key goals in \CFA is to push the boundary on overloading, and hence, overload resolution. 15 16 17 \subsection{Operator Overloading} 18 19 Virtually all programming languages overload the arithmetic operators across the basic types using the number and type of parameters and returns. 20 Like \CC, \CFA also allows these operators to be overloaded with user-defined types. 21 The syntax for operator names uses the @'?'@ character to denote a parameter, \eg prefix and infix increment operators: @?++@, @++?@, and @?+?@. 22 \begin{cfa} 23 struct S { int i, j }; 24 S @?+?@( S op1, S op2 ) { return (S){ op1.i + op2.i, op1.j + op2.j }; } 25 S s1, s2; 26 s1 = s1 @+@ s2; $\C[1.75in]{// infix call}$ 27 s1 = @?+?@( s1, s2 ); $\C{// direct call}\CRT$ 28 \end{cfa} 29 The type system examines each call size and selects the best matching overloaded function based on the number and types of the arguments. 30 If there are mixed-mode operands, @2 + 3.5@, the type system, like in C/\CC, attempts (safe) conversions, converting the argument type(s) to the parameter type(s). 31 32 33 \subsection{Function Overloading} 34 35 Both \CFA and \CC allow function names to be overloaded, as long as their prototypes differ in the number and type of parameters and returns. 36 \begin{cfa} 37 void f( void ); $\C[1.75in]{// (1): no parameter}$ 38 void f( char ); $\C{// (2): overloaded on the number and parameter type}$ 39 void f( int, int ); $\C{// (3): overloaded on the number and parameter type}$ 40 f( 'A' ); $\C{// select (2)}\CRT$ 41 \end{cfa} 42 In this case, the name @f@ is overloaded depending on the number and parameter types. 43 The type system examines each call size and selects the best match based on the number and types of the arguments. 44 Here, there is a perfect match for the call, @f( 'A' )@ with the number and parameter type of function (2). 45 46 Ada, Scala, and \CFA type-systems also use the return type in resolving a call, to pinpoint the best overloaded name. 47 \begin{cfa} 48 int f( void ); $\C[1.75in]{// (4); overloaded on return type}$ 49 double f( void ); $\C{// (5); overloaded on return type}$ 50 int i = f(); $\C{// select (4)}$ 51 double d = f(); $\C{// select (5)}\CRT$ 52 \end{cfa} 53 54 55 \subsection{Variable Overloading} 56 Unlike almost all programming languages, \CFA has variable overloading within a scope, along with shadow overloading in nested scopes. 57 \begin{cfa} 58 void foo( double d ); 59 int v; $\C[1.75in]{// (1)}$ 60 double v; $\C{// (2) variable overloading}$ 61 foo( v ); $\C{// select (2)}$ 62 { 63 int v; $\C{// (3) shadow overloading}$ 64 double v; $\C{// (4) and variable overloading}$ 65 foo( v ); $\C{// select (4)}\CRT$ 66 } 67 \end{cfa} 68 The \CFA type system simply treats overloaded variables as an overloaded function returning a value with no parameters. 69 Hence, no significant effort is required to support this feature. -
doc/theses/fangren_yu_MMath/uw-ethesis-frontpgs.tex
r960665c rad47ec4 24 24 25 25 \Large 26 Fangren Yu \\26 Fangren Yu \\ 27 27 28 28 \vspace*{3.0cm} … … 30 30 \normalsize 31 31 A thesis \\ 32 presented to the University of Waterloo \\ 32 presented to the University of Waterloo \\ 33 33 in fulfillment of the \\ 34 34 thesis requirement for the degree of \\ … … 43 43 \vspace*{1.0cm} 44 44 45 \copyright {}Fangren Yu \the\year \\45 \copyright\ Fangren Yu \the\year \\ 46 46 \end{center} 47 47 \end{titlepage} … … 63 63 The following served on the Examining Committee for this thesis. The decision of the Examining Committee is by majority vote. 64 64 \bigskip 65 65 66 66 \noindent 67 67 \begin{tabbing} 68 68 Internal-External Member: \= \kill % using longest text to define tab length 69 External Examiner: \> Bruce Bruce \\ 69 External Examiner: \> Bruce Bruce \\ 70 70 \> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\ 71 \end{tabbing} 71 \end{tabbing} 72 72 \bigskip 73 73 74 74 \noindent 75 75 \begin{tabbing} … … 81 81 \end{tabbing} 82 82 \bigskip 83 83 84 84 \noindent 85 85 \begin{tabbing} … … 89 89 \end{tabbing} 90 90 \bigskip 91 91 92 92 \noindent 93 93 \begin{tabbing} … … 97 97 \end{tabbing} 98 98 \bigskip 99 99 100 100 \noindent 101 101 \begin{tabbing} … … 114 114 \addcontentsline{toc}{chapter}{Author's Declaration} 115 115 \begin{center}\textbf{Author's Declaration}\end{center} 116 116 117 117 \noindent 118 118 I hereby declare that I am the sole author of this thesis. This is a true copy of the thesis, including any required final revisions, as accepted by my examiners. 119 119 120 120 \bigskip 121 121 122 122 \noindent 123 123 I understand that my thesis may be made electronically available to the public. … … 179 179 \phantomsection % allows hyperref to link to the correct page 180 180 181 \begin{comment} 181 182 % L I S T O F A B B R E V I A T I O N S 182 183 % --------------------------- … … 186 187 \phantomsection % allows hyperref to link to the correct page 187 188 188 \begin{comment}189 189 % L I S T O F S Y M B O L S 190 190 % --------------------------- -
doc/theses/fangren_yu_MMath/uw-ethesis.tex
r960665c rad47ec4 91 91 % cfa macros used in the document 92 92 \input{common} 93 %\usepackage input{common}93 %\usepackage{common} 94 94 \CFAStyle % CFA code-style 95 \lstset{language=CFA} % default language 96 \lstset{basicstyle=\linespread{0.9}\sf} % CFA typewriter font 95 \lstset{language=cfa,belowskip=-1pt} % set default language to CFA 96 \lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 97 98 \newcommand{\PAB}[1]{{\color{red}PAB: #1}} 97 99 \newcommand{\newtermFont}{\emph} 98 100 \newcommand{\Newterm}[1]{\newtermFont{#1}} 99 101 %\renewcommand{\newterm}[1]{\newtermFont{#1}} 100 \newcommand{\uC}{$\mu$\CC}101 \newcommand{\PAB}[1]{{\color{red}PAB: #1}}102 102 103 103 % Hyperlinks make it very easy to navigate an electronic document. … … 108 108 \usepackage[dvips,pagebackref=true]{hyperref} % with basic options 109 109 %\usepackage[pdftex,pagebackref=true]{hyperref} 110 % N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing.110 % N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing. 111 111 \hypersetup{ 112 112 plainpages=false, % needed if Roman numbers in frontpages … … 140 140 \urlstyle{sf} 141 141 142 \usepackage[automake,toc,abbreviations]{glossaries-extra} % Exception to the rule of hyperref being the last add-on package143 \renewcommand*{\glstextformat}[1]{\textcolor{black}{#1}}142 %\usepackage[automake,toc,abbreviations]{glossaries-extra} % Exception to the rule of hyperref being the last add-on package 143 %\renewcommand*{\glstextformat}[1]{\textcolor{black}{#1}} 144 144 % If glossaries-extra is not in your LaTeX distribution, get it from CTAN (http://ctan.org/pkg/glossaries-extra), 145 145 % although it's supposed to be in both the TeX Live and MikTeX distributions. There are also documentation and … … 182 182 183 183 % Define Glossary terms (This is properly done here, in the preamble and could also be \input{} from a separate file...) 184 \usepackage[automake,toc,abbreviations]{glossaries-extra} % Exception to the rule of hyperref being the last add-on package185 \renewcommand*{\glstextformat}[1]{\textcolor{black}{#1}}186 \input{glossary}187 \makeglossaries184 %\usepackage[automake,toc,abbreviations]{glossaries-extra} % Exception to the rule of hyperref being the last add-on package 185 %\renewcommand*{\glstextformat}[1]{\textcolor{black}{#1}} 186 %\input{glossary} 187 %\makeglossaries 188 188 189 189 %====================================================================== … … 258 258 % GLOSSARIES (Lists of definitions, abbreviations, symbols, etc. provided by the glossaries-extra package) 259 259 % ----------------------------- 260 \printglossary 261 \cleardoublepage262 \phantomsection % allows hyperref to link to the correct page260 %\printglossaries 261 %\cleardoublepage 262 %\phantomsection % allows hyperref to link to the correct page 263 263 264 264 %---------------------------------------------------------------------- -
libcfa/src/common.hfa
r960665c rad47ec4 10 10 // Created On : Wed Jul 11 17:54:36 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Aug 14 17:01:47 202313 // Update Count : 3812 // Last Modified On : Sat Aug 24 08:01:36 2024 13 // Update Count : 43 14 14 // 15 15 … … 66 66 67 67 static inline __attribute__((always_inline)) { 68 forall( T | { int ?<?( T, T ); } )69 T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; }70 71 forall( T, Ts... | { T min( T, T ); T min( T, T, Ts ); } )72 T min( T v1, T v2, T v3, Ts vs ) { return min( min( v1, v2 ), v3, vs ); }73 74 forall( T | { int ?>?( T, T ); } )75 T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; }76 77 forall( T, Ts... | { T max( T, T ); T max( T, T, Ts ); } )78 T max( T v1, T v2, T v3, Ts vs ) { return max( max( v1, v2 ), v3, vs ); }79 80 forall( T | { T min( T, T ); T max( T, T ); } )81 T clamp( T value, T min_val, T max_val ) { return max( min_val, min( value, max_val ) ); }82 83 forall( T )84 void swap( T & v1, T & v2 ) { T temp = v1; v1 = v2; v2 = temp; }85 86 68 // Specializations 87 69 char min( char v1, char v2 ) { return v1 < v2 ? v1 : v2; } … … 100 82 long long int max( long long int v1, long long int v2 ) { return v1 > v2 ? v1 : v2; } 101 83 unsigned long long int max( unsigned long long int v1, unsigned long long int v2 ) { return v1 > v2 ? v1 : v2; } 84 85 // Polymorphic 86 forall( T | { int ?<?( T, T ); } ) 87 T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; } 88 89 forall( T, Ts ... | { T min( T, T ); T min( Ts ); } ) 90 T min( T arg, Ts args ) { return min( arg, min( args ) ); } 91 92 forall( T | { int ?>?( T, T ); } ) 93 T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; } 94 95 forall( T, Ts ... | { T max( T, T ); T max( Ts ); } ) 96 T max( T arg, Ts args ) { return max( arg, max( args ) ); } 97 98 forall( T | { T min( T, T ); T max( T, T ); } ) 99 T clamp( T value, T min_val, T max_val ) { return max( min_val, min( value, max_val ) ); } 100 101 forall( T ) 102 void swap( T & v1, T & v2 ) { T temp = v1; v1 = v2; v2 = temp; } 102 103 } // distribution 103 104 -
src/AST/Decl.hpp
r960665c rad47ec4 50 50 : ParseNode( loc ), name( name ), storage( storage ), linkage( linkage ) {} 51 51 52 Decl* set_extension( bool ex ) { extension = ex; return this; }53 54 52 /// Ensures this node has a unique ID 55 53 void fixUniqueId(); -
src/AST/Expr.hpp
r960665c rad47ec4 187 187 : ParseNode( loc ), result( res ), env(), inferred() {} 188 188 189 Expr * set_extension( bool ex ) { extension = ex; return this; }190 189 virtual bool get_lvalue() const; 191 190 -
src/Parser/DeclarationNode.cpp
r960665c rad47ec4 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Feb 23 18:25:57 202413 // Update Count : 15 3312 // Last Modified On : Thu Aug 22 14:11:47 2024 13 // Update Count : 1555 14 14 // 15 15 … … 134 134 os << endl << string( indent + 2, ' ' ) << "with initializer "; 135 135 initializer->printOneLine( os ); 136 os << " maybe constructed? " << initializer->get_maybeConstructed(); 136 if ( ! initializer->get_maybeConstructed() ) { 137 os << " constructed with @= "; 138 } // if 137 139 } // if 138 140 … … 957 959 isDelete ? nullptr : maybeBuild( initializer ), 958 960 copy( attributes ) 959 )->set_extension( extension ); 961 ); 962 decl->extension = extension; 960 963 if ( isDelete ) { 961 964 auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl ); … … 999 1002 assert( type ); 1000 1003 1001 // Some types are parsed as declarations and, syntactically, can have 1002 // initializers. However, semantically, this is meaningless. 1003 if ( initializer ) { 1004 SemanticError( this, "Initializer on type declaration " ); 1004 // Some types are parsed as declarations and, syntactically, can have initializers, which are not support (possibly 1005 // meaningless). 1006 if ( initializer && initializer->get_maybeConstructed() ) { // no @= 1007 SemanticError( location, "default initialization for parameter %s is unsupport for a function-pointer declaration.", 1008 (this->name) ? this->name->c_str() : "anonymous" ); 1005 1009 } 1006 1010 -
src/Parser/ExpressionNode.cpp
r960665c rad47ec4 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat May 16 13:17:07 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Dec 14 18:57:07 202313 // Update Count : 108 711 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Aug 23 10:22:00 2024 13 // Update Count : 1088 14 14 // 15 15 … … 780 780 } // build_compoundLiteral 781 781 782 ast::Expr * build_va_arg( const CodeLocation & location, 783 ExpressionNode * function, DeclarationNode * declaration ) { 784 return build_func( location, 785 new ExpressionNode( 786 build_varref( location, new std::string( "__builtin_va_arg" ) ) ), 787 function->set_last( new ExpressionNode( new ast::TypeExpr( location, 788 maybeMoveBuildType( declaration ) ) ) ) 789 ); 790 } 791 782 792 // Local Variables: // 783 793 // tab-width: 4 // -
src/Parser/ExpressionNode.hpp
r960665c rad47ec4 43 43 ast::Expr * build() { 44 44 ast::Expr * node = expr.release(); 45 node-> set_extension( this->get_extension() );45 node->extension = this->extension; 46 46 node->location = this->location; 47 47 return node; … … 83 83 ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node ); 84 84 ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids ); 85 ast::Expr * build_va_arg( const CodeLocation &, ExpressionNode * function, DeclarationNode * type ); 85 86 86 87 ast::Expr * build_enum_pos_expr( const CodeLocation &, ast::Expr * expr_node ); -
src/Parser/InitializerNode.cpp
r960665c rad47ec4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:20:24 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue A pr 4 11:18:00 202313 // Update Count : 2 711 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Aug 20 22:36:22 2024 13 // Update Count : 28 14 14 // 15 15 … … 86 86 } // if 87 87 88 InitializerNode * moreInit;88 InitializerNode * moreInit; 89 89 if ( ( moreInit = next ) ) { 90 90 moreInit->printOneLine( os ); -
src/Parser/TypeData.cpp
r960665c rad47ec4 1540 1540 1541 1541 1542 // The argument flag (is/is not var-args) of a computed property. 1543 static ast::ArgumentFlag argumentFlag( const TypeData * td ) { 1544 assert( td->kind == TypeData::Function ); 1545 bool isVaArgs = !td->function.params || td->function.params->hasEllipsis; 1546 return (isVaArgs) ? ast::VariableArgs : ast::FixedArgs; 1547 } // argumentFlag 1548 1549 1542 1550 ast::FunctionDecl * buildFunctionDecl( 1543 1551 const TypeData * td, … … 1549 1557 std::vector<ast::ptr<ast::Attribute>> && attributes ) { 1550 1558 assert( td->kind == TypeData::Function ); 1551 // For some reason FunctionDecl takes a bool instead of an ArgumentFlag.1552 bool isVarArgs = !td->function.params || td->function.params->hasEllipsis;1553 1559 ast::CV::Qualifiers cvq = buildQualifiers( td ); 1554 1560 std::vector<ast::ptr<ast::TypeDecl>> forall; … … 1604 1610 std::move( attributes ), 1605 1611 funcSpec, 1606 (isVarArgs) ? ast::VariableArgs : ast::FixedArgs1612 argumentFlag( td ) 1607 1613 ); 1608 1614 buildList( td->function.withExprs, decl->withExprs ); … … 1656 1662 assert( td->kind == TypeData::Function ); 1657 1663 ast::FunctionType * ft = new ast::FunctionType( 1658 ( !td->function.params || td->function.params->hasEllipsis ) 1659 ? ast::VariableArgs : ast::FixedArgs, 1664 argumentFlag( td ), 1660 1665 buildQualifiers( td ) 1661 1666 ); -
src/Parser/parser.yy
r960665c rad47ec4 792 792 { $$ = new ExpressionNode( build_func( yylloc, $1, $3 ) ); } 793 793 | VA_ARG '(' primary_expression ',' declaration_specifier_nobody abstract_parameter_declarator_opt ')' 794 // { SemanticError( yylloc, "va_arg is currently unimplemented." ); $$ = nullptr; } 795 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, new string( "__builtin_va_arg" ) ) ), 796 $3->set_last( (ExpressionNode *)($6 ? $6->addType( $5 ) : $5) ) ) ); } 794 { $$ = new ExpressionNode( build_va_arg( yylloc, $3, ( $6 ? $6->addType( $5 ) : $5 ) ) ); } 797 795 | postfix_expression '`' identifier // CFA, postfix call 798 796 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); } -
tests/.expect/opt-params.txt
r960665c rad47ec4 1 opt-params.cfa:12:1 error: Initializer on type declaration i: int 2 with initializer maybe constructed? 1 3 4 opt-params.cfa:13:1 error: Initializer on type declaration int 5 with initializer maybe constructed? 1 6 7 opt-params.cfa:14:1 error: Initializer on type declaration int 8 with initializer maybe constructed? 1 9 10 opt-params.cfa:15:1 error: Initializer on type declaration int 11 with initializer maybe constructed? 1 12 1 opt-params.cfa:13:1 error: default initialization for parameter i is unsupport for a function-pointer declaration. 2 opt-params.cfa:13:1 error: default initialization for parameter j is unsupport for a function-pointer declaration. 3 opt-params.cfa:14:1 error: default initialization for parameter anonymous is unsupport for a function-pointer declaration. 4 opt-params.cfa:15:1 error: default initialization for parameter anonymous is unsupport for a function-pointer declaration. 5 opt-params.cfa:16:1 error: default initialization for parameter anonymous is unsupport for a function-pointer declaration. 6 opt-params.cfa:17:1 error: default initialization for parameter i is unsupport for a function-pointer declaration. 7 opt-params.cfa:18:1 error: default initialization for parameter i is unsupport for a function-pointer declaration. -
tests/opt-params.cfa
r960665c rad47ec4 9 9 // This is a slightly weird way to do it, but it let's us try all the cases 10 10 // before any of the errors cause compilation to stop. 11 11 12 void bad_cases( 12 int (*fee)( int i = 10 ), 13 int (*fie)( int = 10 ), 14 void feo( int (*p)( int = 10 ) ), 15 void fum( int (*)( int = 10 ) ) 13 int (*f1)( int i = 10, int j = 5 ), 14 int (*f2)( int = 10 ), 15 void f3( int (*p)( int = 10 ) ), 16 void f4( int (*)( int = 10 ) ), 17 void f5( int (*p)( int i = 10 ) ), 18 void f6( int (*)( int i = 10 ) ) 16 19 ); 20
Note:
See TracChangeset
for help on using the changeset viewer.