Changeset 5600747


Ignore:
Timestamp:
Mar 8, 2018, 9:23:32 AM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
4c11fce, ab0203df
Parents:
e5d4e5c (diff), fb11446e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
21 edited

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    re5d4e5c r5600747  
    14391439    contributer = {pabuhr@plg},
    14401440    author      = {Peter A. Buhr},
    1441     title       = {$\mu${C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Annotated Reference Manual, Version 6.1.0},
     1441    title       = {$\mu${C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Annotated Reference Manual, Version 7.0.0},
    14421442    institution = {School of Computer Science, University of Waterloo},
    14431443    address     = {Waterloo, Ontario, Canada, N2L 3G1},
    1444     month       = jul,
    1445     year        = 2015,
    1446     note        = {\href{http://plg.uwaterloo.ca/~usystem/pub/uSystem/u++-6.1.0.sh}{http://\-plg.\-uwaterloo.\-ca/\-$\sim$usystem/\-pub/\-uSystem/\-u++-6.1.0.sh}},
     1444    month       = dec,
     1445    year        = 2017,
     1446    note        = {\href{http://plg.uwaterloo.ca/~usystem/pub/uSystem/u++-7.0.0.sh}{http://\-plg.\-uwaterloo.\-ca/\-$\sim$usystem/\-pub/\-uSystem/\-u++-7.0.0.sh}},
    14471447}
    14481448
  • doc/papers/general/Paper.tex

    re5d4e5c r5600747  
    5858\setlength{\parindentlnth}{\parindent}
    5959
     60\newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{\lst@basicstyle{#1}}}}
    6061\newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}}
    6162\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
     
    231232All of the features discussed in this paper are working, unless a feature states it is a future feature for completion.
    232233
     234Finally, it is impossible to describe a programming language without usages before definitions.
     235Therefore, syntax and semantics appear before explanations;
     236hence, patience is necessary until details are presented.
     237
    233238
    234239\section{Polymorphic Functions}
     
    263268\end{cfa}
    264269\CFA maximizes the ability to reuse names to aggressively address the naming problem.
    265 In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction for a programmer.
     270In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction.
    266271In the above, the name @max@ has a consistent meaning, and a programmer only needs to remember the single concept: maximum.
    267272To prevent significant ambiguities, \CFA uses the return type in selecting overloads, \eg in the assignment to @m@, the compiler use @m@'s type to unambiguously select the most appropriate call to function @max@ (as does Ada).
    268273As is shown later, there are a number of situations where \CFA takes advantage of available type information to disambiguate, where other programming languages generate ambiguities.
    269274
    270 \Celeven added @_Generic@ expressions, which can be used in preprocessor macros to provide a form of ad-hoc polymorphism; however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading.
    271 The macro wrapping the generic expression imposes some limitations; as an example, it could not implement the example above, because the variables @max@ would collide with the functions @max@.
    272 Ergonomic limitations of @_Generic@ include the necessity to put a fixed list of supported types in a single place and manually dispatch to appropriate overloads, as well as possible namespace pollution from the functions dispatched to, which must all have distinct names.
    273 Though name-overloading removes a major use-case for @_Generic@ expressions, \CFA implements @_Generic@ for backwards-compatibility purposes. \TODO{actually implement that}
     275\Celeven added @_Generic@ expressions, which is used in preprocessor macros to provide a form of ad-hoc polymorphism;
     276however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading.
     277The macro wrapping the generic expression imposes some limitations;
     278\eg, it cannot implement the example above, because the variables @max@ are ambiguous with the functions @max@.
     279Ergonomic limitations of @_Generic@ include the necessity to put a fixed list of supported types in a single place and manually dispatch to appropriate overloads, as well as possible namespace pollution from the dispatch functions, which must all have distinct names.
     280For backwards compatibility, \CFA supports @_Generic@ expressions, but it is an unnecessary mechanism. \TODO{actually implement that}
    274281
    275282% http://fanf.livejournal.com/144696.html
     
    286293int forty_two = identity( 42 );                         $\C{// T is bound to int, forty\_two == 42}$
    287294\end{cfa}
    288 The @identity@ function above can be applied to any complete \newterm{object type} (or @otype@).
     295This @identity@ function can be applied to any complete \newterm{object type} (or @otype@).
    289296The type variable @T@ is transformed into a set of additional implicit parameters encoding sufficient information about @T@ to create and return a variable of that type.
    290297The \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.
    291298If this extra information is not needed, \eg for a pointer, the type parameter can be declared as a \newterm{data type} (or @dtype@).
    292299
    293 In \CFA, the polymorphism runtime-cost is spread over each polymorphic call, due to passing more arguments to polymorphic functions;
     300In \CFA, the polymorphic runtime-cost is spread over each polymorphic call, because more arguments are passed to polymorphic functions;
    294301the experiments in Section~\ref{sec:eval} show this overhead is similar to \CC virtual-function calls.
    295302A design advantage is that, unlike \CC template-functions, \CFA polymorphic-functions are compatible with C \emph{separate compilation}, preventing compilation and code bloat.
     
    303310which works for any type @T@ with a matching addition operator.
    304311The polymorphism is achieved by creating a wrapper function for calling @+@ with @T@ bound to @double@, then passing this function to the first call of @twice@.
    305 There is now the option of using the same @twice@ and converting the result to @int@ on assignment, or creating another @twice@ with type parameter @T@ bound to @int@ because \CFA uses the return type~\cite{Cormack81,Baker82,Ada}, in its type analysis.
     312There is now the option of using the same @twice@ and converting the result to @int@ on assignment, or creating another @twice@ with type parameter @T@ bound to @int@ because \CFA uses the return type~\cite{Cormack81,Baker82,Ada} in its type analysis.
    306313The first approach has a late conversion from @double@ to @int@ on the final assignment, while the second has an eager conversion to @int@.
    307314\CFA minimizes the number of conversions and their potential to lose information, so it selects the first approach, which corresponds with C-programmer intuition.
     
    312319\begin{cfa}
    313320void * bsearch( const void * key, const void * base, size_t nmemb, size_t size,
    314                                 int (* compar)( const void *, const void * ));
    315 
    316 int comp( const void * t1, const void * t2 ) { return *(double *)t1 < *(double *)t2 ? -1 :
    317                                 *(double *)t2 < *(double *)t1 ? 1 : 0; }
    318 
     321                                         int (* compar)( const void *, const void * ));
     322int comp( const void * t1, const void * t2 ) {
     323         return *(double *)t1 < *(double *)t2 ? -1 : *(double *)t2 < *(double *)t1 ? 1 : 0;
     324}
    319325double key = 5.0, vals[10] = { /* 10 sorted float values */ };
    320326double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp );      $\C{// search sorted array}$
     
    324330forall( otype T | { int ?<?( T, T ); } ) T * bsearch( T key, const T * arr, size_t size ) {
    325331        int comp( const void * t1, const void * t2 ) { /* as above with double changed to T */ }
    326         return (T *)bsearch( &key, arr, size, sizeof(T), comp ); }
    327 
     332        return (T *)bsearch( &key, arr, size, sizeof(T), comp );
     333}
    328334forall( otype T | { int ?<?( T, T ); } ) unsigned int bsearch( T key, const T * arr, size_t size ) {
    329335        T * result = bsearch( key, arr, size ); $\C{// call first version}$
    330         return result ? result - arr : size; }  $\C{// pointer subtraction includes sizeof(T)}$
    331 
     336        return result ? result - arr : size;    $\C{// pointer subtraction includes sizeof(T)}$
     337}
    332338double * val = bsearch( 5.0, vals, 10 );        $\C{// selection based on return type}$
    333339int posn = bsearch( 5.0, vals, 10 );
     
    336342Providing a hidden @comp@ function in \CC is awkward as lambdas do not use C calling-conventions and template declarations cannot appear at block scope.
    337343As well, an alternate kind of return is made available: position versus pointer to found element.
    338 \CC's type-system cannot disambiguate between the two versions of @bsearch@ because it does not use the return type in overload resolution, nor can \CC separately compile a templated @bsearch@.
     344\CC's type-system cannot disambiguate between the two versions of @bsearch@ because it does not use the return type in overload resolution, nor can \CC separately compile a template @bsearch@.
    339345
    340346\CFA has replacement libraries condensing hundreds of existing C functions into tens of \CFA overloaded functions, all without rewriting the actual computations (see Section~\ref{sec:libraries}).
     
    382388\begin{cfa}
    383389trait otype( dtype T | sized(T) ) {  // sized is a pseudo-trait for types with known size and alignment
    384         void ?{}( T * );                                                $\C{// default constructor}$
    385         void ?{}( T *, T );                                             $\C{// copy constructor}$
    386         void ?=?( T *, T );                                             $\C{// assignment operator}$
    387         void ^?{}( T * ); };                                    $\C{// destructor}$
     390        void ?{}( T & );                                                $\C{// default constructor}$
     391        void ?{}( T &, T );                                             $\C{// copy constructor}$
     392        void ?=?( T &, T );                                             $\C{// assignment operator}$
     393        void ^?{}( T & ); };                                    $\C{// destructor}$
    388394\end{cfa}
    389395Given the information provided for an @otype@, variables of polymorphic type can be treated as if they were a complete type: stack-allocatable, default or copy-initialized, assigned, and deleted.
     
    429435One approach is to write bespoke data-structures for each context in which they are needed.
    430436While this approach is flexible and supports integration with the C type-checker and tooling, it is also tedious and error-prone, especially for more complex data structures.
    431 A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allows reuse of code with common functionality.
     437A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow reuse of code with common functionality.
    432438However, basing all polymorphism on @void *@ eliminates the type-checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is not otherwise needed.
    433439A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type-checked, but errors may be difficult to interpret.
    434 Furthermore, writing and using preprocessor macros can be unnatural and inflexible.
     440Furthermore, writing and using preprocessor macros is unnatural and inflexible.
    435441
    436442\CC, Java, and other languages use \newterm{generic types} to produce type-safe abstract data-types.
     
    444450        S second;
    445451};
    446 forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; }
    447 forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; }
    448 
    449 pair( const char *, int ) p = { "magic", 42 };
     452forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; } $\C{// dynamic}$
     453forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } $\C{// dtype-static (concrete)}$
     454
     455pair( const char *, int ) p = { "magic", 42 }; $\C{// concrete}$
    450456int i = value( p );
    451 pair( void *, int * ) q = { 0, &p.second };
     457pair( void *, int * ) q = { 0, &p.second }; $\C{// concrete}$
    452458i = value( q );
    453459double d = 1.0;
    454 pair( double *, double * ) r = { &d, &d };
     460pair( double *, double * ) r = { &d, &d }; $\C{// concrete}$
    455461d = value( r );
    456462\end{cfa}
     
    458464\CFA classifies generic types as either \newterm{concrete} or \newterm{dynamic}.
    459465Concrete types have a fixed memory layout regardless of type parameters, while dynamic types vary in memory layout depending on their type parameters.
    460 A type may have polymorphic parameters but still be concrete, called \newterm{dtype-static}.
     466A \newterm{dtype-static} type has polymorphic parameters but is still concrete.
    461467Polymorphic pointers are an example of dtype-static types, \eg @forall(dtype T) T *@ is a polymorphic type, but for any @T@, @T *@  is a fixed-sized pointer, and therefore, can be represented by a @void *@ in code generation.
    462468
     
    475481For example, the concrete instantiation for @pair( const char *, int )@ is:
    476482\begin{cfa}
    477 struct _pair_conc1 {
     483struct _pair_conc0 {
    478484        const char * first;
    479485        int second;
     
    482488
    483489A concrete generic-type with dtype-static parameters is also expanded to a structure type, but this type is used for all matching instantiations.
    484 In the above example, the @pair( F *, T * )@ parameter to @value_p@ is such a type; its expansion is below and it is used as the type of the variables @q@ and @r@ as well, with casts for member access where appropriate:
    485 \begin{cfa}
    486 struct _pair_conc0 {
     490In the above example, the @pair( F *, T * )@ parameter to @value@ is such a type; its expansion is below and it is used as the type of the variables @q@ and @r@ as well, with casts for member access where appropriate:
     491\begin{cfa}
     492struct _pair_conc1 {
    487493        void * first;
    488494        void * second;
     
    496502As mentioned in Section~\ref{sec:poly-fns}, @otype@ function parameters (in fact all @sized@ polymorphic parameters) come with implicit size and alignment parameters provided by the caller.
    497503Dynamic generic-types also have an \newterm{offset array} containing structure-member offsets.
    498 A dynamic generic-union needs no such offset array, as all members are at offset 0, but size and alignment are still necessary.
     504A dynamic generic-@union@ needs no such offset array, as all members are at offset 0, but size and alignment are still necessary.
    499505Access to members of a dynamic structure is provided at runtime via base-displacement addressing with the structure pointer and the member offset (similar to the @offsetof@ macro), moving a compile-time offset calculation to runtime.
    500506
     
    502508If a dynamic generic-type is declared to be passed or returned by value from a polymorphic function, the translator can safely assume the generic type is complete (\ie has a known layout) at any call-site, and the offset array is passed from the caller;
    503509if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro.
    504 As an example, @p.second@ in the @value@ function above is implemented as @*(p + _offsetof_pair[1])@, where @p@ is a @void *@, and @_offsetof_pair@ is the offset array passed into @value@ for @pair( const char *, T )@.
    505 The offset array @_offsetof_pair@ is generated at the call site as @size_t _offsetof_pair[] = { offsetof(_pair_conc1, first), offsetof(_pair_conc1, second) }@.
     510As an example, the body of the second @value@ function is implemented like this:
     511\begin{cfa}
     512_assign_T(_retval, p + _offsetof_pair[1]); $\C{// return *p.second}$
     513\end{cfa}
     514@_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T*@ (@void*@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.
     515@_offsetof_pair@ is the offset array passed into @value@; this array is generated at the call site as:
     516\begin{cfa}
     517size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) }
     518\end{cfa}
    506519
    507520In some cases the offset arrays cannot be statically generated.
     
    586599\subsection{Tuple Expressions}
    587600
    588 The addition of multiple-return-value functions (MRVF) are useless without a syntax for accepting multiple values at the call-site.
     601The addition of multiple-return-value functions (MRVF) are \emph{useless} without a syntax for accepting multiple values at the call-site.
    589602The simplest mechanism for capturing the return values is variable assignment, allowing the values to be retrieved directly.
    590603As such, \CFA allows assigning multiple values from a function into multiple variables, using a square-bracketed list of lvalue expressions (as above), called a \newterm{tuple}.
     
    817830Hence, function parameter and return lists are flattened for the purposes of type unification allowing the example to pass expression resolution.
    818831This relaxation is possible by extending the thunk scheme described by Bilson~\cite{Bilson03}.
    819 Whenever a candidate's parameter structure does not exactly match the formal parameter's structure, a thunk is generated to specialize calls to the actual function:
    820 \begin{cfa}
    821 int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); }
    822 \end{cfa}
    823 so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism.
    824 These thunks take advantage of gcc C nested-functions to produce closures that have the usual function-pointer signature.
     832% Whenever a candidate's parameter structure does not exactly match the formal parameter's structure, a thunk is generated to specialize calls to the actual function:
     833% \begin{cfa}
     834% int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); }
     835% \end{cfa}
     836% so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism.
     837% These thunks are generated locally using gcc nested-functions, rather hositing them to the external scope, so they can easily access local state.
    825838
    826839
     
    878891        print(arg);  print(rest);
    879892}
    880 void print( char * x ) { printf( "%s", x ); }
     893void print( const char * x ) { printf( "%s", x ); }
    881894void print( int x ) { printf( "%d", x ); }
    882895void print( S s ) { print( "{ ", s.x, ",", s.y, " }" ); }
     
    887900The polymorphic @print@ allows printing any list of types, where as each individual type has a @print@ function.
    888901The individual print functions can be used to build up more complicated @print@ functions, such as @S@, which cannot be done with @printf@ in C.
     902This mechanism is used to seamlessly print tuples in the \CFA I/O library (see Section~\ref{s:IOLibrary}).
    889903
    890904Finally, it is possible to use @ttype@ polymorphism to provide arbitrary argument forwarding functions.
     
    9901004\section{Control Structures}
    9911005
    992 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds to control structures to increase functionality and safety.
     1006\CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds control structures to increase functionality and safety.
    9931007
    9941008
     
    10251039\lstMakeShortInline@%
    10261040\end{cquote}
    1027 for a contiguous list:\footnote{gcc provides the same mechanism with awkward syntax, \lstinline@2 ... 42@, where spaces are required around the ellipse.}
     1041for a contiguous list:\footnote{gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}
    10281042\begin{cquote}
    10291043\lstDeleteShortInline@%
     
    10781092While the ability to fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in many errors from missing @break@ statements.
    10791093For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}).
     1094
    10801095Collectively, these enhancements reduce programmer burden and increase readability and safety.
    10811096
     
    12371252\end{figure}
    12381253
    1239 Both labelled @continue@ and @break@ are a @goto@ restricted in the following ways:
     1254With respect to safety, both labelled @continue@ and @break@ are a @goto@ restricted in the following ways:
    12401255\begin{itemize}
    12411256\item
     
    12501265With @goto@, the label is at the end of the control structure, which fails to convey this important clue early enough to the reader.
    12511266Finally, using an explicit target for the transfer instead of an implicit target allows new constructs to be added or removed without affecting existing constructs.
    1252 The implicit targets of the current @continue@ and @break@, \ie the closest enclosing loop or @switch@, change as certain constructs are added or removed.
     1267Otherwise, the implicit targets of the current @continue@ and @break@, \ie the closest enclosing loop or @switch@, change as certain constructs are added or removed.
    12531268
    12541269
    12551270\subsection{Exception Handling}
    12561271
    1257 The following framework for \CFA exception handling is in place, excluding a run-time type information and dynamic casts.
    1258 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling}).
     1272The following framework for \CFA exception handling is in place, excluding some run-time type-information and dynamic casts.
     1273\CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}.
    12591274Both mechanisms provide dynamic call to a handler using dynamic name-lookup, where fix-up has dynamic return and recovery has static return from the handler.
    12601275\CFA restricts exception types to those defined by aggregate type @exception@.
     
    13331348resume( $\emph{alternate-stack}$ )
    13341349\end{cfa}
    1335 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another coroutine or task~\cite{Delisle18}.
     1350These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task~\cite{Delisle18}.\footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.}
    13361351Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle returns.
    13371352
     
    13581373Specifying no exception type is shorthand for specifying all exception types.
    13591374Both @enable@ and @disable@ blocks can be nested, turning propagation on/off on entry, and on exit, the specified exception types are restored to their prior state.
     1375Coroutines and tasks start with non-local exceptions disabled, allowing handlers to be put in place, before non-local exceptions are explicitly enabled.
     1376\begin{cfa}
     1377void main( mytask & c ) {                                       $\C{// thread starts here}$
     1378        // non-local exceptions disabled
     1379        try {                                                                   $\C{// establish handles for non-local exceptions}$
     1380                enable {                                                        $\C{// allow non-local exception delivery}$
     1381                        // task body
     1382                }
     1383        // appropriate catchResume/catch handlers
     1384        }
     1385}
     1386\end{cfa}
    13601387
    13611388Finally, \CFA provides a Java like  @finally@ clause after the catch clauses:
     
    14611488Qualification or a cast is used to disambiguate.
    14621489
    1463 There is an interesting problem between parameters and the function @with@, \eg:
     1490There is an interesting problem between parameters and the function-body @with@, \eg:
    14641491\begin{cfa}
    14651492void ?{}( S & s, int i ) with ( s ) {           $\C{// constructor}$
     
    14671494}
    14681495\end{cfa}
    1469 Here, the assignment @s.i = i@ means @s.i = s.i@, which is meaningless, and there is no mechanism to qualify the parameter @i@, making the assignment impossible using the function @with@.
     1496Here, the assignment @s.i = i@ means @s.i = s.i@, which is meaningless, and there is no mechanism to qualify the parameter @i@, making the assignment impossible using the function-body @with@.
    14701497To solve this problem, parameters are treated like an initialized aggregate:
    14711498\begin{cfa}
     
    14751502} params;
    14761503\end{cfa}
    1477 and implicitly opened \emph{after} a function open, to give them higher priority:
    1478 \begin{cfa}
    1479 void ?{}( S & s, int i ) with ( s ) `with( $\emph{\color{red}params}$ )` {
    1480         s.i = i; j = 3; m = 5.5;
     1504and implicitly opened \emph{after} a function-body open, to give them higher priority:
     1505\begin{cfa}
     1506void ?{}( S & s, int `i` ) with ( s ) `with( $\emph{\color{red}params}$ )` {
     1507        s.i = `i`; j = 3; m = 5.5;
    14811508}
    14821509\end{cfa}
     
    15391566While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice.
    15401567
    1541 \CFA provides its own type, variable and function declarations, using a different syntax.
     1568\CFA provides its own type, variable and function declarations, using a different syntax~\cite[pp.~856--859]{Buhr94a}.
    15421569The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right.
    15431570The qualifiers have the same meaning but are ordered left to right to specify a variable's type.
     
    17741801int & r = *new( int );
    17751802...                                                                                     $\C{// non-null reference}$
    1776 delete &r;
     1803delete &r;                                                                      $\C{// unmanaged (programmer) memory-management}$
    17771804r += 1;                                                                         $\C{// undefined reference}$
    17781805\end{cfa}
     
    19211948Constructor calls seamlessly integrate with existing C initialization syntax, providing a simple and familiar syntax to C programmers and allowing constructor calls to be inserted into legacy C code with minimal code changes.
    19221949
    1923 In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@.
    1924 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@\footnote{%
     1950In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@\footnote{%
    19251951The symbol \lstinline+^+ is used for the destructor name because it was the last binary operator that could be used in a unary context.}.
     1952The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@.
    19261953Like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @?{}(x, ...)@ or @^{}(x, ...)@.
    19271954The constructor and destructor have return type @void@, and the first parameter is a reference to the object type to be constructed or destructed.
     
    19511978}
    19521979\end{cfa}
    1953 (Note, the example is purposely kept simple by using shallow-copy semantics.)
     1980(Note, the example is purposely simplified using shallow-copy semantics.)
    19541981An initialization constructor-call has the same syntax as a C initializer, except the initialization values are passed as arguments to a matching constructor (number and type of paremeters).
    19551982\begin{cfa}
     
    20042031C already includes limited polymorphism for literals -- @0@ can be either an integer or a pointer literal, depending on context, while the syntactic forms of literals of the various integer and float types are very similar, differing from each other only in suffix.
    20052032In keeping with the general \CFA approach of adding features while respecting the ``C-style'' of doing things, C's polymorphic constants and typed literal syntax are extended to interoperate with user-defined types, while maintaining a backwards-compatible semantics.
    2006 A trivial example is allowing the underscore, as in Ada, to separate prefixes, digits, and suffixes in all \CFA constants, \eg @0x`_`1.ffff`_`ffff`_`p`_`128`_`l@.
     2033
     2034A simple example is allowing the underscore, as in Ada, to separate prefixes, digits, and suffixes in all \CFA constants, \eg @0x`_`1.ffff`_`ffff`_`p`_`128`_`l@, where the underscore is also the standard separator in C identifiers.
     2035\CC uses a single quote as a separator but it is restricted among digits, precluding its use in the literal prefix or suffix, \eg @0x1.ffff@@`'@@ffffp128l@, and causes problems with most IDEs, which must be extended to deal with this alternate use of the single quote.
    20072036
    20082037
     
    20142043\begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}}
    20152044\begin{cfa}
    2016 20`_hh`     // signed char
    2017 21`_hhu`   // unsigned char
    2018 22`_h`       // signed short int
    2019 23`_uh`     // unsigned short int
    2020 24`z`         // size_t
    2021 \end{cfa}
    2022 &
    2023 \begin{cfa}
    2024 20`_L8`      // int8_t
    2025 21`_ul8`     // uint8_t
    2026 22`_l16`     // int16_t
    2027 23`_ul16`   // uint16_t
    2028 24`_l32`     // int32_t
    2029 \end{cfa}
    2030 &
    2031 \begin{cfa}
    2032 25`_ul32`      // uint32_t
    2033 26`_l64`        // int64_t
    2034 27`_l64u`      // uint64_t
    2035 26`_L128`     // int128
    2036 27`_L128u`   // unsigned int128
     204520_`hh`     // signed char
     204621_`hhu`   // unsigned char
     204722_`h`       // signed short int
     204823_`uh`     // unsigned short int
     204924_`z`       // size_t
     2050\end{cfa}
     2051&
     2052\begin{cfa}
     205320_`L8`      // int8_t
     205421_`ul8`     // uint8_t
     205522_`l16`     // int16_t
     205623_`ul16`   // uint16_t
     205724_`l32`     // int32_t
     2058\end{cfa}
     2059&
     2060\begin{cfa}
     206125_`ul32`      // uint32_t
     206226_`l64`        // int64_t
     206327_`l64u`      // uint64_t
     206426_`L128`     // int128
     206527_`L128u`   // unsigned int128
    20372066\end{cfa}
    20382067\end{tabular}
     
    20432072\subsection{0/1}
    20442073
    2045 In C, @0@ has the special property that it is the only ``false'' value; by the standard, any value which compares equal to @0@ is false, while any value that compares unequal to @0@ is true.
    2046 As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@) can be rewritten as @x != 0@ without changing its semantics.
    2047 The operator overloading feature of \CFA provides a natural means to implement this truth value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer.
    2048 To provide this precision, \CFA introduces a new type @zero_t@ as type type of literal @0@ (somewhat analagous to @nullptr_t@ and @nullptr@ in \CCeleven); @zero_t@ can only take the value @0@, but has implicit conversions to the integer and pointer types so that C code involving @0@ continues to work properly.
    2049 With this addition, the \CFA compiler rewrites @if (x)@ and similar expressions to @if ((x) != 0)@ or the appropriate analogue, and any type @T@ can be made ``truthy'' by defining an operator overload @int ?!=?(T, zero_t)@.
    2050 \CC makes types truthy by adding a conversion to @bool@; prior to the addition of explicit cast operators in \CCeleven this approach had the pitfall of making truthy types transitively convertable to any numeric type; our design for \CFA avoids this issue.
    2051 
    2052 \CFA also includes a special type for @1@, @one_t@; like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code.
    2053 The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where that is meaningful.
    2054 \TODO{Make this sentence true} In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@; analogous overloads for the decrement operators are present as well.
     2074In C, @0@ has the special property that it is the only ``false'' value;
     2075from the standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true.
     2076As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@\,) can be rewritten as @x != 0@ without changing its semantics.
     2077Operator overloading in \CFA provides a natural means to implement this truth-value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer.
     2078To provide this precision, \CFA introduces a new type @zero_t@ as the type of literal @0@ (somewhat analagous to @nullptr_t@ and @nullptr@ in \CCeleven);
     2079@zero_t@ can only take the value @0@, but has implicit conversions to the integer and pointer types so that C code involving @0@ continues to work.
     2080With this addition, \CFA rewrites @if (x)@ and similar expressions to @if ((x) != 0)@ or the appropriate analogue, and any type @T@ is ``truthy'' by defining an operator overload @int ?!=?(T, zero_t)@.
     2081\CC makes types truthy by adding a conversion to @bool@;
     2082prior to the addition of explicit cast operators in \CCeleven, this approach had the pitfall of making truthy types transitively convertable to any numeric type;
     2083\CFA avoids this issue.
     2084
     2085Similarly, \CFA also has a special type for @1@, @one_t@;
     2086like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code for operations @++@ and @--@.
     2087The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where it is meaningful.
     2088\TODO{Make this sentence true}
     2089In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@;
     2090analogous overloads for the decrement operators are present as well.
    20552091
    20562092
     
    20602096The left of Figure~\ref{f:UserLiteral} shows the \CFA alternative call-syntax (literal argument before function name), using the backquote, to convert basic literals into user literals.
    20612097The backquote is a small character, making the unit (function name) predominate.
    2062 For examples, the multi-precision integers in Section~\ref{s:MultiPrecisionIntegers} make use of user literals:
     2098For examples, the multi-precision integer-type in Section~\ref{s:MultiPrecisionIntegers} has user literals:
    20632099{\lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}}
    20642100\begin{cfa}
     
    20732109After which, user literals must match (no conversions);
    20742110hence, it is necessary to overload the unit with all appropriate types.
    2075 Finally, the use of the single quote as a separator is restricted to digits, precluding its use in the literal prefix or suffix, and causes problems with most IDEs, which must be extended to deal with this alternate use of the single quote.
    20762111
    20772112\begin{figure}
     
    21252160        w = 155|_lb|;
    21262161        w = 0b1111|_lb|;       // error, binary unsupported
    2127         w = 0${\color{red}'}$233|_lb|;          // quote separator
     2162        w = 0${\color{red}\LstBasicStyle{'}}$233|_lb|;          // quote separator
    21282163        w = 0x9b|_kg|;
    21292164        w = 5.5d|_st| + 8|_kg| + 25.01|_lb| + heavy;
     
    22812316\lstMakeShortInline@%
    22822317\end{cquote}
    2283 In additon, there are polymorphic functions, like @min@ and @max@, which work on any type with operators @?<?@ or @?>?@.
     2318In additon, there are polymorphic functions, like @min@ and @max@, that work on any type with operators @?<?@ or @?>?@.
    22842319
    22852320The following shows one example where \CFA \emph{extends} an existing standard C interface to reduce complexity and provide safety.
     
    22872322\begin{description}[topsep=3pt,itemsep=2pt,parsep=0pt]
    22882323\item[fill]
    2289 after allocation the storage is filled with a specified character.
     2324an allocation with a specified character.
    22902325\item[resize]
    2291 an existing allocation is decreased or increased in size.
     2326an existing allocation to decreased or increased its size.
    22922327In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied.
    22932328For an increase in storage size, new storage after the copied data may be filled.
    2294 \item[alignment]
    2295 an allocation starts on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
     2329\item[align]
     2330an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    22962331\item[array]
    2297 the allocation size is scaled to the specified number of array elements.
     2332allocation with a specified number of elements.
    22982333An array may be filled, resized, or aligned.
    22992334\end{description}
    23002335Table~\ref{t:StorageManagementOperations} shows the capabilities provided by C/\Celeven allocation-functions and how all the capabilities can be combined into two \CFA functions.
    23012336\CFA storage-management functions extend the C equivalents by overloading, providing shallow type-safety, and removing the need to specify the base allocation-size.
    2302 Figure~\ref{f:StorageAllocation} contrasts \CFA and C storage-allocation operation performing the same operations with the same type safety.
     2337Figure~\ref{f:StorageAllocation} contrasts \CFA and C storage-allocation performing the same operations with the same type safety.
    23032338
    23042339\begin{table}
     
    23072342\lstMakeShortInline~%
    23082343\begin{tabular}{@{}r|r|l|l|l|l@{}}
    2309 \multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
     2344\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & align & array \\
    23102345\hline
    23112346C               & ~malloc~                      & no                    & no            & no            & no    \\
     
    24432478\end{cfa}
    24442479\\
    2445 \textbf{output:}
    24462480&
    24472481\begin{cfa}[showspaces=true,aboveskip=0pt]
     
    25302564\begin{cfa}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt]
    25312565int main( int argc, char * argv[] ) {
    2532         ofstream out = { "cfa-out.txt" };
    25332566        int max = 0, val = 42;
    2534         stack( int ) s, t;
    2535 
    2536         REPEAT_TIMED( "push_int", N, push( s, val ); )
    2537         TIMED( "copy_int", t = s; )
    2538         TIMED( "clear_int", clear( s ); )
    2539         REPEAT_TIMED( "pop_int", N, int v = pop( t ); max = max( v, max ); )
    2540         REPEAT_TIMED( "print_int", N/2, out | val | ':' | val | endl; )
    2541 
    2542         pair( _Bool, char ) max = { false, '\0' }, val = { true, 'a' };
    2543         stack( pair( _Bool, char ) ) s, t;
    2544 
    2545         REPEAT_TIMED( "push_pair", N, push( s, val ); )
    2546         TIMED( "copy_pair", t = s; )
    2547         TIMED( "clear_pair", clear( s ); )
    2548         REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) v = pop( t ); max = max( v, max ); )
    2549         REPEAT_TIMED( "print_pair", N/2, out | val | ':' | val | endl; )
     2567        stack( int ) si, ti;
     2568
     2569        REPEAT_TIMED( "push_int", N, push( si, val ); )
     2570        TIMED( "copy_int", ti = si; )
     2571        TIMED( "clear_int", clear( si ); )
     2572        REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; )
     2573
     2574        pair( _Bool, char ) max = { (_Bool)0, '\0' }, val = { (_Bool)1, 'a' };
     2575        stack( pair( _Bool, char ) ) sp, tp;
     2576
     2577        REPEAT_TIMED( "push_pair", N, push( sp, val ); )
     2578        TIMED( "copy_pair", tp = sp; )
     2579        TIMED( "clear_pair", clear( sp ); )
     2580        REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; )
    25502581}
    25512582\end{cfa}
     
    26772708\subsection{Control Structures / Declarations / Literals}
    26782709
     2710Java has default fall through like C/\CC.
     2711Pascal/Ada/Go/Rust do not have default fall through.
     2712\Csharp does not have fall through but still requires a break.
     2713Python uses dictionary mapping. \\
     2714\CFA choose is like Rust match.
     2715
     2716Java has labelled break/continue. \\
     2717Languages with and without exception handling.
     2718
     2719Alternative C declarations. \\
     2720Different references \\
     2721Constructors/destructors
     2722
     27230/1 Literals \\
     2724user defined: D, Objective-C
    26792725
    26802726\section{Conclusion and Future Work}
     
    26832729While other programming languages purport to be a better C, they are in fact new and interesting languages in their own right, but not C extensions.
    26842730The purpose of this paper is to introduce \CFA, and showcase language features that illustrate the \CFA type-system and approaches taken to achieve the goal of evolutionary C extension.
    2685 The contributions are a powerful type-system using parametric polymorphism and overloading, generic types, and tuples, which all have complex interactions.
     2731The contributions are a powerful type-system using parametric polymorphism and overloading, generic types, tuples, advanced control structures, and extended declarations, which all have complex interactions.
    26862732The work is a challenging design, engineering, and implementation exercise.
    26872733On the surface, the project may appear as a rehash of similar mechanisms in \CC.
     
    26902736Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable.
    26912737
    2692 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, exceptions, concurrent primitives, modules, and user-defined conversions.
     2738There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, user-defined conversions, concurrent primitives, and modules.
    26932739(While all examples in the paper compile and run, a public beta-release of \CFA will take another 8--12 months to finalize these additional extensions.)
    26942740In addition, there are interesting future directions for the polymorphism design.
     
    27032749\section{Acknowledgments}
    27042750
    2705 The authors would like to recognize the design assistance of Glen Ditchfield, Richard Bilson, and Thierry Delisle on the features described in this paper, and thank Magnus Madsen for feedback in the writing.
    2706 This work is supported through a corporate partnership with Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are funded by the Natural Sciences and Engineering Research Council of Canada.
     2751The authors would like to recognize the design assistance of Glen Ditchfield, Richard Bilson, Thierry Delisle, and Andrew Beach on the features described in this paper, and thank Magnus Madsen for feedback in the writing.
     2752This work is supported through a corporate partnership with Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are partially funded by the Natural Sciences and Engineering Research Council of Canada.
    27072753
    27082754% the first author's \grantsponsor{NSERC-PGS}{NSERC PGS D}{http://www.nserc-crsng.gc.ca/Students-Etudiants/PG-CS/BellandPostgrad-BelletSuperieures_eng.asp} scholarship.
  • doc/papers/general/evaluation/Makefile

    re5d4e5c r5600747  
    22CFA = cfa
    33DEPFLAGS = -MMD -MP
     4ifdef DBG
     5CFLAGS = -O0 -ggdb -DN=500
     6else
    47CFLAGS = -O2
    58ifdef N
    69CFLAGS += -DN=$(N)
     10endif
    711endif
    812CXXFLAGS = $(CFLAGS) --std=c++14
     
    2731        $(COMPILE.cfa) $(OUTPUT_OPTION) -c $<
    2832
    29 COBJS = c-stack.o c-pair.o c-print.o c-bench.o
     33COBJS = c-stack.o c-pair.o c-bench.o
    3034CPPOBJS = cpp-bench.o
    3135CPPVOBJS = cpp-vstack.o cpp-vbench.o
    32 CFAOBJS = cfa-stack.o cfa-pair.o cfa-print.o cfa-bench.o
     36CFAOBJS = cfa-stack.o cfa-pair.o cfa-bench.o
    3337
    3438${COBJS} ${CPPOBJS} ${CPPVOBJS} ${CFAOBJS} : ${MAKEFILE_NAME}
    3539
    3640CFILES = bench.h $(patsubst c-bench.h,,$(COBJS:.o=.h)) $(COBJS:.o=.c)
    37 CPPFILES = bench.hpp cpp-stack.hpp cpp-pair.hpp cpp-print.hpp $(CPPOBJS:.o=.cpp)
    38 CPPVFILES = bench.hpp object.hpp cpp-vprint.hpp $(patsubst cpp-vbench.hpp,,$(CPPVOBJS:.o=.hpp)) $(CPPVOBJS:.o=.cpp)
     41CPPFILES = bench.hpp cpp-stack.hpp cpp-pair.hpp $(CPPOBJS:.o=.cpp)
     42CPPVFILES = bench.hpp object.hpp $(patsubst cpp-vbench.hpp,,$(CPPVOBJS:.o=.hpp)) $(CPPVOBJS:.o=.cpp)
    3943CFAFILES = bench.h $(patsubst cfa-bench.h,,$(CFAOBJS:.o=.h)) $(CFAOBJS:.o=.c)
    4044
  • doc/papers/general/evaluation/bench.h

    re5d4e5c r5600747  
    55long ms_between(clock_t start, clock_t end) { return (end - start) / (CLOCKS_PER_SEC / 1000); }
    66
     7#ifndef N
    78#define N 40000000
     9#endif
     10
    811#define TIMED(name, code) { \
    912        volatile clock_t _start, _end; \
  • doc/papers/general/evaluation/bench.hpp

    re5d4e5c r5600747  
    66long ms_between(clock_t start, clock_t end) { return (end - start) / (CLOCKS_PER_SEC / 1000); }
    77
     8#ifndef N
    89static const int N = 40000000;
     10#endif
     11
    912#define TIMED(name, code) { \
    1013        volatile clock_t _start, _end; \
  • doc/papers/general/evaluation/c-bench.c

    re5d4e5c r5600747  
    44#include "c-pair.h"
    55#include "c-stack.h"
    6 #include "c-print.h"
    76
    87_Bool* new_bool( _Bool b ) {
     
    3938
    4039int main(int argc, char** argv) {
    41         FILE * out = fopen("/dev/null", "w");
    4240        int maxi = 0, vali = 42;
    4341        struct stack si = new_stack(), ti;
     
    5048                if ( *xi > maxi ) { maxi = *xi; }
    5149                free(xi); )
    52         REPEAT_TIMED( "print_int", N/2, print( out, "dsds", vali, ":", vali, "\n" ); /***/ )
    5350
    5451        struct pair * maxp = new_pair( new_bool(0), new_char('\0') ),
     
    6764                        free_pair_bool_char( xp ); /***/
    6865                } )
    69         REPEAT_TIMED( "print_pair", N/2, print( out, "pbcspbcs", *valp, ":", *valp, "\n" ); /***/ )
    7066        free_pair_bool_char( maxp ); /***/
    7167        free_pair_bool_char( valp ); /***/
    72         fclose(out);
    7368}
  • doc/papers/general/evaluation/cfa-bench.c

    re5d4e5c r5600747  
    1 #include <fstream>
    2 #include <stdlib>
    3 #include <stdbool.h>
    41#include "bench.h"
    52#include "cfa-stack.h"
    63#include "cfa-pair.h"
    7 #include "cfa-print.h"
    84
    95int main( int argc, char * argv[] ) {
    10         ofstream out = { "/dev/null" };
    116        int max = 0, val = 42;
    12         stack( int ) s, t;
     7        stack( int ) si, ti;
    138
    14         REPEAT_TIMED( "push_int", N, push( s, val ); )
    15         TIMED( "copy_int", t = s; )
    16         TIMED( "clear_int", clear( s ); )
    17         REPEAT_TIMED( "pop_int", N, int x = pop( t ); max = max( x, max ); )
    18         REPEAT_TIMED( "print_int", N/2, out | val | ':' | val | endl; )
     9        REPEAT_TIMED( "push_int", N, push( si, val ); )
     10        TIMED( "copy_int", ti = si; )
     11        TIMED( "clear_int", clear( si ); )
     12        REPEAT_TIMED( "pop_int", N,
     13                int x = pop( ti ); if ( x > max ) max = x; )
    1914
    20         pair( _Bool, char ) max = { (_Bool)false, '\0' }, val = { (_Bool)true, 'a' };
    21         stack( pair( _Bool, char ) ) s, t;
     15        pair( _Bool, char ) max = { (_Bool)0 /***/, '\0' }, val = { (_Bool)1 /***/, 'a' };
     16        stack( pair( _Bool, char ) ) sp, tp;
    2217
    23         REPEAT_TIMED( "push_pair", N, push( s, val ); )
    24         TIMED( "copy_pair", t = s; )
    25         TIMED( "clear_pair", clear( s ); )
    26         REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) x = pop( t ); max = max( x, max ); )
    27         REPEAT_TIMED( "print_pair", N/2, out | val | ':' | val | endl; )
     18        REPEAT_TIMED( "push_pair", N, push( sp, val ); )
     19        TIMED( "copy_pair", tp = sp; )
     20        TIMED( "clear_pair", clear( sp ); )
     21        REPEAT_TIMED( "pop_pair", N,
     22                pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; )
    2823}
  • doc/papers/general/evaluation/cfa-pair.c

    re5d4e5c r5600747  
    3636}
    3737
    38 forall(otype R, otype S)
    39 forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S );  })
    40 ostype & ?|?( ostype & os, pair(R, S) p ) {
    41         return os | '[' | p.first | ',' | p.second | ']';
    42 } // ?|?
     38// forall(otype R, otype S)
     39// forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S );  })
     40// ostype & ?|?( ostype & os, pair(R, S) p ) {
     41//      return os | '[' | p.first | ',' | p.second | ']';
     42// } // ?|?
  • doc/papers/general/evaluation/cfa-pair.h

    re5d4e5c r5600747  
    3030int ?>=?(pair(R, S) p, pair(R, S) q);
    3131
    32 forall(otype R, otype S)
    33 forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, pair(R, S) ); })
    34 ostype & ?|?( ostype & os, pair(R, S) );
     32// forall(otype R, otype S)
     33// forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S ); })
     34// ostype & ?|?( ostype & os, pair(R, S) );
  • doc/papers/general/evaluation/cfa-stack.c

    re5d4e5c r5600747  
    66        stack_node(T) * next;
    77};
    8 forall(otype T) void ?{}( stack_node(T) & node, T value, stack_node(T) * next ) {
    9     node.value = value;
    10     node.next = next;
    11 }
    128
    139forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
     
    1612        stack_node(T) ** crnt = &s.head;
    1713        for ( stack_node(T) * next = t.head; next; next = next->next ) {
    18                 // *crnt = new( next->value, 0 );
    19                 stack_node(T)* new_node = ((stack_node(T)*)malloc());
    20                 (*new_node){ next->value }; /***/
     14                stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/
     15                (*new_node){ next->value };
    2116                *crnt = new_node;
    22                 stack_node(T) * acrnt = *crnt;
    23                 crnt = &acrnt->next;
     17                crnt = &(*crnt)->next;
    2418        }
    2519        *crnt = 0;
     
    3832
    3933forall(otype T) void push( stack(T) & s, T value ) {
    40         // s.head = new( value, s.head );
    41         stack_node(T)* new_node = ((stack_node(T)*)malloc());
    42         (*new_node){ value, s.head }; /***/
     34        stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/
     35        (*new_node){ value, s.head };
    4336        s.head = new_node;
    4437}
     
    4841        s.head = n->next;
    4942        T v = n->value;
    50         delete( n );
     43        ^(*n){};
     44        free( n );
    5145        return v;
    5246}
     
    5650                stack_node(T) * crnt = next;
    5751                next = crnt->next;
    58                 delete( crnt );
     52                ^(*crnt){};
     53                free(crnt);
    5954        }
    6055        s.head = 0;
  • doc/papers/general/evaluation/cpp-bench.cpp

    re5d4e5c r5600747  
    11#include <algorithm>
    2 #include <fstream>
    32#include "bench.hpp"
    43#include "cpp-stack.hpp"
    54#include "cpp-pair.hpp"
    6 #include "cpp-print.hpp"
    75
    86int main(int argc, char** argv) {
    9         std::ofstream out{"/dev/null"};
    107        int maxi = 0, vali = 42;
    118        stack<int> si, ti;
     
    1512        TIMED( "clear_int", si.clear(); )
    1613        REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop() ); )
    17         REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); )
    1814
    1915        pair<bool, char> maxp = { false, '\0' }, valp = { true, 'a' };
     
    2420        TIMED( "clear_pair", sp.clear(); )
    2521        REPEAT_TIMED( "pop_pair", N, maxp = std::max( maxp, tp.pop() ); )
    26         REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); )
    2722}
  • doc/papers/general/evaluation/cpp-vbench.cpp

    re5d4e5c r5600747  
    11#include <algorithm>
    2 #include <fstream>
    32#include "bench.hpp"
    43#include "cpp-vstack.hpp"
    5 #include "cpp-vprint.hpp"
    64#include "object.hpp"
    75
    86int main(int argc, char** argv) {
    9         std::ofstream out{"/dev/null"};
    107        integer maxi{ 0 }, vali{ 42 };
    118        stack si, ti;
     
    1512        TIMED( "clear_int", si.clear(); )
    1613        REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop()->as<integer>() ); /***/ )
    17         REPEAT_TIMED( "print_int", N/2, print( out, vali, c_string{":"}, vali, c_string{"\n"} ); )
    1814
    1915        ptr<pair> maxp = make<pair>( make<boolean>(false), make<character>('\0') );
     
    2723                ptr<pair> xp = as_ptr<pair>( tp.pop() ); /***/
    2824                if ( *xp > *maxp ) { maxp = std::move(xp); } )
    29         REPEAT_TIMED( "print_pair", N/2, print( out, valp, c_string{":"}, valp, c_string{"\n"} ); )
    3025}
  • doc/papers/general/evaluation/timing.dat

    re5d4e5c r5600747  
    11"400 million repetitions"       "C"     "\\CFA{}"       "\\CC{}"        "\\CC{obj}"
    2 "push\nint"     3002    2459    1520    3305
    3 "copy\nint"     2985    2057    1521    3152
    4 "clear\nint"    1374    827     718     1469
    5 "pop\nint"      1416    1221    717     5467
    6 "print\nint"    5656    6758    3120    3121
    7 "push\npair"    4214    2752    946     6826
    8 "copy\npair"    6127    2105    993     7330
    9 "clear\npair"   2881    885     711     3564
    10 "pop\npair"     3046    5434    783     26538
    11 "print\npair"   7514    10714   8717    16525
     2"push\nint"     2976    2225    1522    3266
     3"copy\nnt"      2932    7072    1526    3110
     4"clear\nint"    1380    731     750     1488
     5"pop\nint"      1444    1196    756     5156
     6"push\npair"    3695    2257    953     6840
     7"copy\npair"    6034    6650    994     7224
     8"clear\npair"   2832    848     742     3297
     9"pop\npair"     3009    5348    797     25235
     10
  • src/GenPoly/Box.cc

    re5d4e5c r5600747  
    163163                        void premutate( DeclStmt *declStmt );
    164164                        Expression *postmutate( MemberExpr *memberExpr );
     165                        void premutate( AddressExpr *addrExpr );
     166                        Expression *postmutate( AddressExpr *addrExpr );
    165167                        Expression *postmutate( SizeofExpr *sizeofExpr );
    166168                        Expression *postmutate( AlignofExpr *alignofExpr );
     
    193195                        ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
    194196                        UniqueName bufNamer;                           ///< Namer for VLA buffers
     197                        Expression * addrMember = nullptr;             ///< AddressExpr argument is MemberExpr?
    195198                };
    196199
     
    11741177                        if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
    11751178                                if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
    1176                                         if ( name->get_name() == "*?" ) {
     1179                                        if ( name->name == "*?" ) {
    11771180                                                Expression *ret = expr->args.front();
    11781181                                                expr->args.clear();
     
    11871190                void Pass1::premutate( AddressExpr * ) { visit_children = false; }
    11881191                Expression * Pass1::postmutate( AddressExpr * addrExpr ) {
    1189                         assert( addrExpr->get_arg()->result && ! addrExpr->get_arg()->get_result()->isVoid() );
     1192                        assert( addrExpr->arg->result && ! addrExpr->arg->result->isVoid() );
    11901193
    11911194                        bool needs = false;
    1192                         if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->get_arg() ) ) {
    1193                                 if ( expr->result && isPolyType( expr->get_result(), scopeTyVars, env ) ) {
    1194                                         if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) {
    1195                                                 if ( name->get_name() == "*?" ) {
    1196                                                         if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->get_args().front() ) ) {
    1197                                                                 assert( appExpr->get_function()->result );
    1198                                                                 FunctionType *function = getFunctionType( appExpr->get_function()->get_result() );
     1195                        if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) {
     1196                                if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
     1197                                        if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
     1198                                                if ( name->name == "*?" ) {
     1199                                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
     1200                                                                assert( appExpr->function->result );
     1201                                                                FunctionType *function = getFunctionType( appExpr->function->result );
    11991202                                                                assert( function );
    12001203                                                                needs = needsAdapter( function, scopeTyVars );
     
    12061209                        // isPolyType check needs to happen before mutating addrExpr arg, so pull it forward
    12071210                        // out of the if condition.
    1208                         addrExpr->arg = addrExpr->get_arg()->acceptMutator( *visitor );
     1211                        addrExpr->arg = addrExpr->arg->acceptMutator( *visitor );
    12091212                        // ... but must happen after mutate, since argument might change (e.g. intrinsic *?, ?[?]) - re-evaluate above comment
    1210                         bool polytype = isPolyType( addrExpr->get_arg()->get_result(), scopeTyVars, env );
     1213                        bool polytype = isPolyType( addrExpr->arg->result, scopeTyVars, env );
    12111214                        if ( polytype || needs ) {
    1212                                 Expression *ret = addrExpr->get_arg();
    1213                                 delete ret->get_result();
    1214                                 ret->set_result( addrExpr->get_result()->clone() );
    1215                                 addrExpr->set_arg( 0 );
     1215                                Expression *ret = addrExpr->arg;
     1216                                delete ret->result;
     1217                                ret->result = addrExpr->result->clone();
     1218                                addrExpr->arg = nullptr;
    12161219                                delete addrExpr;
    12171220                                return ret;
     
    12501253
    12511254                void Pass2::addAdapters( FunctionType *functionType ) {
    1252                         std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
     1255                        std::list< DeclarationWithType *> &paramList = functionType->parameters;
    12531256                        std::list< FunctionType *> functions;
    12541257                        for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
     
    12711274
    12721275                DeclarationWithType * Pass2::postmutate( FunctionDecl *functionDecl ) {
    1273                         FunctionType * ftype = functionDecl->get_functionType();
    1274                         if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) {
    1275                                 if ( ! isPrefix( functionDecl->get_name(), "_thunk" ) && ! isPrefix( functionDecl->get_name(), "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
    1276                                         assert( ftype->get_returnVals().size() == 1 );
    1277                                         DeclarationWithType * retval = ftype->get_returnVals().front();
    1278                                         if ( retval->get_name() == "" ) {
    1279                                                 retval->set_name( "_retval" );
     1276                        FunctionType * ftype = functionDecl->type;
     1277                        if ( ! ftype->returnVals.empty() && functionDecl->statements ) {
     1278                                if ( ! isPrefix( functionDecl->name, "_thunk" ) && ! isPrefix( functionDecl->name, "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
     1279                                        assert( ftype->returnVals.size() == 1 );
     1280                                        DeclarationWithType * retval = ftype->returnVals.front();
     1281                                        if ( retval->name == "" ) {
     1282                                                retval->name = "_retval";
    12801283                                        }
    1281                                         functionDecl->get_statements()->get_kids().push_front( new DeclStmt( retval ) );
     1284                                        functionDecl->statements->kids.push_front( new DeclStmt( retval ) );
    12821285                                        DeclarationWithType * newRet = retval->clone(); // for ownership purposes
    1283                                         ftype->get_returnVals().front() = newRet;
     1286                                        ftype->returnVals.front() = newRet;
    12841287                                }
    12851288                        }
    12861289                        // errors should have been caught by this point, remove initializers from parameters to allow correct codegen of default arguments
    1287                         for ( Declaration * param : functionDecl->get_functionType()->get_parameters() ) {
     1290                        for ( Declaration * param : functionDecl->type->parameters ) {
    12881291                                if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( param ) ) {
    1289                                         delete obj->get_init();
    1290                                         obj->set_init( nullptr );
     1292                                        delete obj->init;
     1293                                        obj->init = nullptr;
    12911294                                }
    12921295                        }
     
    15841587                        assert( newMemberExpr );
    15851588
    1586                         Type *memberType = memberExpr->member->get_type();
     1589                        // Must apply the generic substitution to the member type to handle cases where the member is a generic parameter substituted by a known concrete type, e.g.
     1590                        //   forall(otype T) struct Box { T x; }
     1591                        //   forall(otype T) f() {
     1592                        //     Box(T *) b; b.x;
     1593                        //   }
     1594                        // TODO: memberExpr->result should be exactly memberExpr->member->get_type() after substitution, so it doesn't seem like it should be necessary to apply the substitution manually. For some reason this is not currently the case. This requires more investigation.
     1595                        Type *memberType = memberExpr->member->get_type()->clone();
     1596                        TypeSubstitution sub = objectType->genericSubstitution();
     1597                        sub.apply( memberType );
    15871598                        if ( ! isPolyType( memberType, scopeTyVars ) ) {
    15881599                                // Not all members of a polymorphic type are themselves of polymorphic type; in this case the member expression should be wrapped and dereferenced to form an lvalue
     
    15921603                        }
    15931604
     1605                        delete memberType;
    15941606                        delete memberExpr;
    15951607                        return newMemberExpr;
     1608                }
     1609
     1610                void PolyGenericCalculator::premutate( AddressExpr * addrExpr ) {
     1611                        GuardValue( addrMember );
     1612                        // is the argument a MemberExpr before mutating?
     1613                        addrMember = dynamic_cast< MemberExpr * >( addrExpr->arg );
     1614                }
     1615
     1616                Expression * PolyGenericCalculator::postmutate( AddressExpr * addrExpr ) {
     1617                        if ( addrMember && addrMember != addrExpr->arg ) {
     1618                                // arg was a MemberExpr and has been mutated
     1619                                if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( addrExpr->arg ) ) {
     1620                                        if ( InitTweak::getFunctionName( untyped ) == "?+?" ) {
     1621                                                // MemberExpr was converted to pointer+offset, and it is not valid C to take the address of an addition, so strip the address-of
     1622                                                // TODO: should  addrExpr->arg->result be changed to addrExpr->result?
     1623                                                Expression * ret = addrExpr->arg;
     1624                                                addrExpr->arg = nullptr;
     1625                                                std::swap( addrExpr->env, ret->env );
     1626                                                delete addrExpr;
     1627                                                return ret;
     1628                                        }
     1629                                }
     1630                        }
     1631                        return addrExpr;
    15961632                }
    15971633
  • src/SynTree/Expression.cc

    re5d4e5c r5600747  
    345345}
    346346
    347 namespace {
    348         TypeSubstitution makeSub( Type * t ) {
    349                 if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( t ) ) {
    350                         return makeSub( refType->get_base() );
    351                 } else if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) {
    352                         return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() );
    353                 } else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) {
    354                         return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() );
    355                 } else {
    356                         assertf( false, "makeSub expects struct or union type for aggregate, but got: %s", toString( t ).c_str() );
    357                 }
    358         }
    359 }
    360 
    361 
    362347MemberExpr::MemberExpr( DeclarationWithType *member, Expression *aggregate ) :
    363348                Expression(), member(member), aggregate(aggregate) {
    364349        assert( member );
    365350        assert( aggregate );
    366 
    367         TypeSubstitution sub( makeSub( aggregate->get_result() ) );
     351        assert( aggregate->result );
     352
     353        TypeSubstitution sub = aggregate->result->genericSubstitution();
    368354        Type * res = member->get_type()->clone();
    369355        sub.apply( res );
  • src/SynTree/ReferenceToType.cc

    re5d4e5c r5600747  
    1414//
    1515
    16 #include <cassert>           // for assert
    17 #include <list>              // for list, _List_const_iterator, list<>::cons...
    18 #include <ostream>           // for operator<<, basic_ostream, ostream, endl
    19 #include <string>            // for string, operator<<, char_traits, operator==
    20 
    21 #include "Common/utility.h"  // for printAll, cloneAll, deleteAll
    22 #include "Declaration.h"     // for StructDecl, UnionDecl, EnumDecl, Declara...
    23 #include "Expression.h"      // for Expression
    24 #include "Type.h"            // for TypeInstType, StructInstType, UnionInstType
     16#include <cassert>            // for assert
     17#include <list>               // for list, _List_const_iterator, list<>::cons...
     18#include <ostream>            // for operator<<, basic_ostream, ostream, endl
     19#include <string>             // for string, operator<<, char_traits, operator==
     20
     21#include "Common/utility.h"   // for printAll, cloneAll, deleteAll
     22#include "Declaration.h"      // for StructDecl, UnionDecl, EnumDecl, Declara...
     23#include "Expression.h"       // for Expression
     24#include "Type.h"             // for TypeInstType, StructInstType, UnionInstType
     25#include "TypeSubstitution.h" // for TypeSubstitution
    2526
    2627class Attribute;
     
    6364std::string StructInstType::typeString() const { return "struct"; }
    6465
     66const std::list<TypeDecl*>* StructInstType::get_baseParameters() const {
     67        if ( ! baseStruct ) return nullptr;
     68        return &baseStruct->get_parameters();
     69}
     70
    6571std::list<TypeDecl*>* StructInstType::get_baseParameters() {
    6672        if ( ! baseStruct ) return nullptr;
     
    7177
    7278AggregateDecl * StructInstType::getAggr() { return baseStruct; }
     79
     80TypeSubstitution StructInstType::genericSubstitution() const {
     81        return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() );
     82}
    7383
    7484void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const {
     
    102112}
    103113
     114const std::list< TypeDecl * > * UnionInstType::get_baseParameters() const {
     115        if ( ! baseUnion ) return nullptr;
     116        return &baseUnion->get_parameters();
     117}
     118
    104119bool UnionInstType::isComplete() const { return baseUnion ? baseUnion->has_body() : false; }
    105120
    106121AggregateDecl * UnionInstType::getAggr() { return baseUnion; }
     122
     123TypeSubstitution UnionInstType::genericSubstitution() const {
     124        return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() );
     125}
    107126
    108127void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const {
  • src/SynTree/ReferenceType.cc

    re5d4e5c r5600747  
    1616#include "Type.h"
    1717#include "Expression.h"
     18#include "TypeSubstitution.h"
    1819#include "Common/utility.h"
    1920
     
    3536}
    3637
     38TypeSubstitution ReferenceType::genericSubstitution() const { return base->genericSubstitution(); }
     39
    3740void ReferenceType::print( std::ostream &os, Indenter indent ) const {
    3841        Type::print( os, indent );
  • src/SynTree/Type.cc

    re5d4e5c r5600747  
    1515#include "Type.h"
    1616
    17 #include "Attribute.h"               // for Attribute
    18 #include "Common/utility.h"          // for cloneAll, deleteAll, printAll
    19 #include "InitTweak/InitTweak.h"     // for getPointerBase
    20 #include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
    21 #include "SynTree/Declaration.h"     // for TypeDecl
     17#include "Attribute.h"                // for Attribute
     18#include "Common/utility.h"           // for cloneAll, deleteAll, printAll
     19#include "InitTweak/InitTweak.h"      // for getPointerBase
     20#include "SynTree/BaseSyntaxNode.h"   // for BaseSyntaxNode
     21#include "SynTree/Declaration.h"      // for TypeDecl
     22#include "SynTree/TypeSubstitution.h" // for TypeSubstitution
    2223
    2324using namespace std;
     
    8182int Type::referenceDepth() const { return 0; }
    8283
     84TypeSubstitution Type::genericSubstitution() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
     85
    8386void Type::print( std::ostream &os, Indenter indent ) const {
    8487        if ( ! forall.empty() ) {
  • src/SynTree/Type.h

    re5d4e5c r5600747  
    178178        virtual bool isComplete() const { return true; }
    179179
    180         virtual AggregateDecl * getAggr() {     assertf( false, "Non-aggregate type: %s", toString( this ).c_str() ); }
     180        virtual AggregateDecl * getAggr() { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
     181
     182        virtual TypeSubstitution genericSubstitution() const;
    181183
    182184        virtual Type *clone() const = 0;
     
    329331        virtual unsigned size() const override { return base->size(); }
    330332
     333        virtual TypeSubstitution genericSubstitution() const override;
     334
    331335        virtual ReferenceType *clone() const override { return new ReferenceType( *this ); }
    332336        virtual void accept( Visitor & v ) override { v.visit( this ); }
     
    406410        /// Accesses generic parameters of base struct (NULL if none such)
    407411        std::list<TypeDecl*> * get_baseParameters();
     412        const std::list<TypeDecl*> * get_baseParameters() const;
    408413
    409414        virtual bool isComplete() const override;
    410415
    411416        virtual AggregateDecl * getAggr() override;
     417
     418        virtual TypeSubstitution genericSubstitution() const override;
    412419
    413420        /// Looks up the members of this struct named "name" and places them into "foundDecls".
     
    439446
    440447        /// Accesses generic parameters of base union (NULL if none such)
    441         std::list< TypeDecl * > * get_baseParameters();
     448        std::list<TypeDecl*> * get_baseParameters();
     449        const std::list<TypeDecl*> * get_baseParameters() const;
    442450
    443451        virtual bool isComplete() const override;
    444452
    445453        virtual AggregateDecl * getAggr() override;
     454
     455        virtual TypeSubstitution genericSubstitution() const override;
    446456
    447457        /// looks up the members of this union named "name" and places them into "foundDecls"
  • src/tests/.expect/literals.x86.txt

    re5d4e5c r5600747  
    522522signed int __main__Fi___1(){
    523523    __attribute__ ((unused)) signed int ___retval_main__i_1;
     524    ((void)0b01101011);
     525    ((void)0b01101011u);
     526    ((void)0b01101011l);
     527    ((void)0b01101011ll);
     528    ((void)0b01101011ul);
     529    ((void)0b01101011lu);
     530    ((void)0b01101011ull);
     531    ((void)0b01101011llu);
     532    ((void)(+0b01101011));
     533    ((void)(+0b01101011u));
     534    ((void)(+0b01101011l));
     535    ((void)(+0b01101011ll));
     536    ((void)(+0b01101011ul));
     537    ((void)(+0b01101011lu));
     538    ((void)(+0b01101011ull));
     539    ((void)(+0b01101011llu));
     540    ((void)(-0b01101011));
     541    ((void)(-0b01101011u));
     542    ((void)(-0b01101011l));
     543    ((void)(-0b01101011ll));
     544    ((void)(-0b01101011ul));
     545    ((void)(-0b01101011lu));
     546    ((void)(-0b01101011ull));
     547    ((void)(-0b01101011llu));
    524548    ((void)01234567);
    525549    ((void)01234567u);
     
    10171041    ((void)(-0X0123456789.0123456789P-09F));
    10181042    ((void)(-0X0123456789.0123456789P-09L));
     1043    ((void)((signed char )0b01101011));
     1044    ((void)((signed short int )0b01101011));
     1045    ((void)((signed int )0b01101011));
     1046    ((void)((signed long long int )0b01101011));
     1047    ((void)((__int128 )0b01101011));
     1048    ((void)((unsigned char )0b01101011u));
     1049    ((void)((signed short int )0b01101011u));
     1050    ((void)((unsigned int )0b01101011u));
     1051    ((void)((signed long long int )0b01101011u));
     1052    ((void)((__int128 )0b01101011u));
     1053    ((void)(+((signed int )((signed char )0b01101011))));
     1054    ((void)(+((signed int )((signed short int )0b01101011))));
     1055    ((void)(+((signed int )0b01101011)));
     1056    ((void)(+((signed long long int )0b01101011)));
     1057    ((void)(+((float )((__int128 )0b01101011))));
     1058    ((void)(+((signed int )((unsigned char )0b01101011u))));
     1059    ((void)(+((signed int )((signed short int )0b01101011u))));
     1060    ((void)(+((unsigned int )0b01101011u)));
     1061    ((void)(+((signed long long int )0b01101011u)));
     1062    ((void)(+((float )((__int128 )0b01101011u))));
     1063    ((void)(-((signed int )((signed char )0b01101011))));
     1064    ((void)(-((signed int )((signed short int )0b01101011))));
     1065    ((void)(-((signed int )0b01101011)));
     1066    ((void)(-((signed long long int )0b01101011)));
     1067    ((void)(-((float )((__int128 )0b01101011))));
     1068    ((void)(-((signed int )((unsigned char )0b01101011u))));
     1069    ((void)(-((signed int )((signed short int )0b01101011u))));
     1070    ((void)(-((unsigned int )0b01101011u)));
     1071    ((void)(-((signed long long int )0b01101011u)));
     1072    ((void)(-((float )((__int128 )0b01101011u))));
    10191073    ((void)((signed char )01234567));
    10201074    ((void)((signed short int )01234567));
Note: See TracChangeset for help on using the changeset viewer.