Changeset 8d182b1


Ignore:
Timestamp:
Nov 14, 2023, 12:19:09 PM (23 months ago)
Author:
caparson <caparson@…>
Branches:
master
Children:
1ccae59, 89a8bab
Parents:
df8ba61a (diff), 5625427 (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:
115 deleted
104 edited

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    rdf8ba61a r8d182b1  
    41084108}
    41094109
    4110 @article{Buhr22,
     4110@article{Buhr23,
    41114111    contributer = {pabuhr@plg},
    41124112    author      = {Peter A. Buhr and Colby A. Parsons and Thierry Delisle and He Nan Li},
     
    41144114    journal     = spe,
    41154115    year        = 2023,
    4116     month       = sep,
    4117     note        = {\url{https://onlinelibrary.wiley.com/doi/pdf/10.1002/spe.3262}}
     4116    month       = dec,
     4117    volume      = 53,
     4118    number      = 12,
     4119    pages       = {2463-2500},
     4120    note        = {\url{https://onlinelibrary.wiley.com/doi/10.1002/spe.3262},
    41184121}
    41194122
     
    41334136    journal     = spe,
    41344137    year        = 1983,
     4138    month       = jul,
    41354139    volume      = 13,
    41364140    number      = 7,
    41374141    pages       = {577-596},
    4138     month       = jul
    41394142}
    41404143
  • doc/proposals/enum.tex

    rdf8ba61a r8d182b1  
    1 %%
    2 %% This is file `sample-manuscript.tex',
    3 %% generated with the docstrip utility.
    4 %%
    5 %% The original source files were:
    6 %%
    7 %% samples.dtx  (with options: `manuscript')
    8 %%
    9 %% IMPORTANT NOTICE:
    10 %%
    11 %% For the copyright see the source file.
    12 %%
    13 %% Any modified versions of this file must be renamed
    14 %% with new filenames distinct from sample-manuscript.tex.
    15 %%
    16 %% For distribution of the original source see the terms
    17 %% for copying and modification in the file samples.dtx.
    18 %%
    19 %% This generated file may be distributed as long as the
    20 %% original source files, as listed above, are part of the
    21 %% same distribution. (The sources need not necessarily be
    22 %% in the same archive or directory.)
    23 %%
    24 %% Commands for TeXCount
    25 %TC:macro \cite [option:text,text]
    26 %TC:macro \citep [option:text,text]
    27 %TC:macro \citet [option:text,text]
    28 %TC:envir table 0 1
    29 %TC:envir table* 0 1
    30 %TC:envir tabular [ignore] word
    31 %TC:envir displaymath 0 word
    32 %TC:envir math 0 word
    33 %TC:envir comment 0 0
    34 %%
    35 %%
    36 %% The first command in your LaTeX source must be the \documentclass command.
    37 \documentclass[manuscript,screen,review]{acmart}
     1\documentclass[12pt]{article}
     2\usepackage{fullpage,times}
     3\usepackage{pslatex}                    % reduce size of san serif font
    384\usepackage{xcolor}
    395\usepackage{listings}
    40 \usepackage[ligature, inference]{semantic}
    41 \usepackage{array}
    42 
    43 \definecolor{mGreen}{rgb}{0,0.6,0}
    44 \definecolor{mGray}{rgb}{0.5,0.5,0.5}
    45 \definecolor{mPurple}{rgb}{0.58,0,0.82}
    46 \definecolor{backgroundColour}{rgb}{0.95,0.95,0.92}
     6%\usepackage{array}
     7\usepackage{graphics}
     8\usepackage{xspace}
     9
     10\makeatletter
     11\renewcommand\section{\@startsection{section}{1}{\z@}{-3.0ex \@plus -1ex \@minus -.2ex}{1.5ex \@plus .2ex}{\normalfont\large\bfseries}}
     12\renewcommand\subsection{\@startsection{subsection}{2}{\z@}{-2.75ex \@plus -1ex \@minus -.2ex}{1.25ex \@plus .2ex}{\normalfont\normalsize\bfseries}}
     13\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-2.5ex \@plus -1ex \@minus -.2ex}{1.0ex \@plus .2ex}{\normalfont\normalsize\bfseries}}
     14\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}{-2.0ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries}}
     15\renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
     16\makeatother
     17
     18\usepackage[ignoredisplayed]{enumitem}  % do not affect trivlist
     19\setlist{labelsep=1ex}% global
     20\setlist[itemize]{topsep=0.5ex,parsep=0.25ex,itemsep=0.25ex,listparindent=\parindent,leftmargin=\parindent}% global
     21\setlist[itemize,1]{label=\textbullet}% local
     22%\renewcommand{\labelitemi}{{\raisebox{0.25ex}{\footnotesize$\bullet$}}}
     23\setlist[enumerate]{topsep=0.5ex,parsep=0.25ex,itemsep=0.25ex,listparindent=\parindent}% global
     24\setlist[enumerate,2]{leftmargin=\parindent,labelsep=*,align=parleft,label=\alph*.}% local
     25\setlist[description]{topsep=0.5ex,itemsep=0pt,listparindent=\parindent,leftmargin=\parindent,labelsep=1.5ex}
     26
     27\newenvironment{cquote}{%
     28        \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindent\rightmargin\leftmargin}%
     29        \item\relax
     30}{%
     31        \endlist
     32}% cquote
     33
     34\setlength{\topmargin}{-0.45in}                                                 % move running title into header
     35\setlength{\headsep}{0.25in}
     36\setlength{\textheight}{9.0in}
     37
     38\newcommand{\CFAIcon}{\textsf{C\raisebox{\depth}{\rotatebox{180}A}}} % Cforall icon
     39\newcommand{\CFA}{\protect\CFAIcon\xspace}                              % CFA symbolic name
     40\newcommand{\PAB}[1]{{\color{red}PAB: #1}}
     41
     42% \definecolor{mGreen}{rgb}{0,0.6,0}
     43% \definecolor{mGray}{rgb}{0.5,0.5,0.5}
     44% \definecolor{mPurple}{rgb}{0.58,0,0.82}
     45% \definecolor{backgroundColour}{rgb}{0.95,0.95,0.92}
    4746
    4847\lstdefinestyle{CStyle}{
    49     backgroundcolor=\color{backgroundColour},   
    50     commentstyle=\color{mGreen},
    51     keywordstyle=\color{magenta},
    52     numberstyle=\tiny\color{mGray},
    53     stringstyle=\color{mPurple},
    54     basicstyle=\footnotesize,
     48%    backgroundcolor=\color{backgroundColour},   
     49%    commentstyle=\color{mGreen},
     50%    keywordstyle=\color{magenta},
     51        stringstyle=\small\tt,                                  % use typewriter font
     52%    stringstyle=\color{mPurple},
     53    columns=fullflexible,
     54    basicstyle=\small\linespread{0.9}\sf,       % reduce line spacing and use sanserif font
     55%   basicstyle=\footnotesize,
    5556    breakatwhitespace=false,         
    56     breaklines=true,                 
     57%    breaklines=true,                 
    5758    captionpos=b,                   
    5859    keepspaces=true,                 
    59     numbers=left,                   
    60     numbersep=5pt,                 
    61     showspaces=false,               
     60%    numbers=left,                   
     61%    numbersep=5pt,                 
     62%    numberstyle=\tiny\color{mGray},
     63%    showspaces=false,               
    6264    showstringspaces=false,
    63     showtabs=false,                 
    64     tabsize=2,
    65     language=C
    66 }
    67 
    68 %%
    69 %% \BibTeX command to typeset BibTeX logo in the docs
    70 \AtBeginDocument{%
    71   \providecommand\BibTeX{{%
    72     \normalfont B\kern-0.5em{\scshape i\kern-0.25em b}\kern-0.8em\TeX}}}
    73 
    74 
    75 %%
    76 %% end of the preamble, start of the body of the document source.
     65%    showtabs=false,                 
     66        showlines=true,                                                 % show blank lines at end of code
     67    tabsize=5,
     68    language=C,
     69        aboveskip=4pt,                                                  % spacing above/below code block
     70        belowskip=2pt,
     71        xleftmargin=\parindent,                 % indent code to paragraph indentation
     72}
     73\lstset{style=CStyle,moredelim=**[is][\color{red}]{@}{@}}
     74\lstMakeShortInline@                            % single-character for \lstinline
     75
    7776\begin{document}
    7877
    79 %%
    80 %% The "title" command has an optional parameter,
    81 %% allowing the author to define a "short title" to be used in page headers.
    82 \title{Enumeration in Cforall}
    83 
    84 %%
    85 %% The "author" command and its associated commands are used to define
    86 %% the authors and their affiliations.
    87 %% Of note is the shared affiliation of the first two authors, and the
    88 %% "authornote" and "authornotemark" commands
    89 %% used to denote shared contribution to the research.
     78\title{\vspace*{-0.5in}Enumeration in \CFA}
    9079\author{Jiada Liang}
    9180
    92 
    93 %%
    94 %% The abstract is a short summary of the work to be presented in the
    95 %% article.
     81\maketitle
     82
    9683\begin{abstract}
    97     An enumeration, or enum in short, is a type that defines a list of named constant values in C. C uses integral type as the underlying representation of enum. Cforall extends C enum to allow more types, including custom types, to be used as enumeration inner representation.
     84An enumeration is a type that defines a list of named constant values in C (and other languages).
     85C uses an integral type as the underlying representation of an enumeration.
     86\CFA extends C enumerations to allow all basic and custom types for the inner representation.
    9887\end{abstract}
    9988
    100 %%
    101 %% The code below is generated by the tool at http://dl.acm.org/ccs.cfm.
    102 %% Please copy and paste the code instead of the example below.
    103 %%
    104 
    105 
    106 %%
    107 %% This command processes the author and affiliation and title
    108 %% information and builds the first part of the formatted document.
    109 \maketitle
    110 
    11189\section{C-Style Enum}
    112 \begin{lstlisting}[style=CStyle, label{lst:weekday}]
     90
     91\CFA supports the C-Style enumeration using the same syntax and semantics.
     92\begin{lstlisting}[label=lst:weekday]
    11393enum Weekday { Monday, Tuesday, Wednesday, Thursday=10, Friday, Saturday, Sunday };
    11494\end{lstlisting}
    115 Cforall supports the C-Style enumeration (C-enum for short). It has the same syntax as C and resembles the same language semantics. In code~\ref{lst:weekday} example, the syntax defines an enum class $Weekday$ with enumerators $Monday$, $Tuesday$, $Wednesday$, $Thursday$, $Friday$, $Saturday$ and $Sunday$ in order. The successor of $Tuesday$ is $Monday$ and the predecessor of $Tuesday$ is $Wednesday$. Enumerators have an integral type, either being explicitly initialized by an initializer or being assigned a value by the compiler. For example, $Thursday$ has been assigned with value $10$. If not explicitly initialized, the first value of an enum, $Monday$ in the $Weekday$ example, has the integer value 0. Other uninitialized enum value has a value that is equal to their successor $+ 1$. The enum value $Tuesday$, $Wednesday$, $Friday$, $Saturday$, and $Sunday$ have value 1, 2, 11, 12, and 13 respectively.
    116 
    117 \begin{lstlisting}[label{lst:enum_scope}, style=CStyle]
    118 {
    119     {
    120         enum RGB {R, G, B};
    121         int i = R  // i == 0
    122     }
    123     int j = G; // ERROR! G is not declared in this scope
    124 }
    125 \end{lstlisting}
    126 C-enums are unscoped: enumerators declared inside of an enum are visible in the enclosing scope of the enum class.
    127 
    128 \section{Cforall-Style Enum}
    129 \begin{lstlisting}[style=CStyle, label{lst:color}]
    130 enum Color(char *) { Red="R", Green="G", Blue="B"  };
    131 \end{lstlisting}
    132 A Cforall enumeration is parameterized by a type declared. Cforall allows any oType in the enum declaration, and values assigned to enumerators must be in the declared type.
    133 
    134 \section{Enumerable Type Traits}
    135 A trait is a collection of constraints in Cforall, which can be used to describe types. Cforall standard library defines traits to categorize types that are related enumeration features.
    136 \subsection{Enumerable}
    137 A type is enumerable if it can map an integer to a value.
    138 \begin{lstlisting}[style=CStyle]
    139 forall(T)
    140 trait Enumerable {
    141     T value( *class_name* , int );
    142 };
    143 \end{lstlisting}
    144 The parameter class name stands for the name of an enumeration class, Weekday, for example.
    145 
    146 \subsection{AutoInitializable}
    147 \begin{lstlisting}[style=CStyle]
     95The example defines an @enum@ type @Weekday@ with ordered enumerators @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@.
     96The successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@.
     97A C enumeration has an integral type, with consecutive enumerator values assigned by the compiler starting at zero or explicitly initialized by the programmer.
     98For example, @Monday@ to @Wednesday@ have values 0--2, @Thursday@ is set to @10@, and after it, @Friday@ to @Sunday@ have values 11--13.
     99
     100There are 3 attributes for an enumeration: position, label, and value:
     101\begin{cquote}
     102\small\sf
     103\begin{tabular}{rccccccccccc}
     104enum Weekday \{ & Monday,       & Tuesday,      & Wednesday,    & Thursday=10,  & Friday,       & Saturday,     & Sunday \}; \\
     105position                & 0                     & 1                     & 2                             & 3                             & 4                     & 5                     & 6                     \\
     106label                   & Monday        & Tuesday       & Wednesday             & Thursday              & Friday        & Saturday      & Sunday        \\
     107value                   & 0                     & 1                     & 2                             & 10                    & 11            & 12            & 13
     108\end{tabular}
     109\end{cquote}
     110
     111The enumerators of an enum are unscoped, i.e., enumerators declared inside of an enum are visible in the enclosing scope of the enum class.
     112\begin{lstlisting}[label=lst:enum_scope]
     113{
     114        enum RGB { R, G, B };
     115        int i = R  // i == 0
     116}
     117int j = G; // ERROR! G is not declared in this scope
     118\end{lstlisting}
     119
     120\section{\CFA-Style Enum}
     121
     122A \CFA enumeration is parameterized by a type, which specifies the type for each enumerator.
     123\CFA allows any object type for the enumerators, and values assigned to enumerators must be in the declared type.
     124\begin{lstlisting}[label=lst:color]
     125enum Colour( @char *@ ) { Red = "R", Green = "G", Blue = "B"  };
     126\end{lstlisting}
     127The type of @Colour@ is @char *@ and each enumerator is initialized with a C string.
     128Only types have define an ordering can be automatically initialized (see Section~\ref{s:AutoInitializable}).
     129
     130
     131% An instance of \CFA-enum (denoted as @<enum_instance>@) is a label for the defined enum name.
     132% The label can be retrieved by calling the function @label( <enum_instance> )@.
     133% Similarly, the @value()@ function returns the value used to initialize the \CFA-enum.
     134
     135A \CFA-enum is scoped: enumeration constants are not automatically exposed to the global scope.
     136Enumeration constant can be referenced using qualified expressions like an aggregate that supports qualified references to its fields. The syntax of $qualified\_expression$ for \CFA-enum is the following:
     137$$<qualified\_expression> := <enum\_type>.<enumerator>$$
     138
     139
     140\subsection{enumeration instance}
     141\begin{lstlisting}[label=lst:sample_cforall_enum_usage]
     142Colour green = Colour.Green;
     143\end{lstlisting}
     144The ~\ref{lst:sample_cforall_enum_usage} example declares a $enumeration\ instance$ named @red@ and initializes it with $enumeration\ constant$ @Color.Red@.
     145An enumeration instance is a data structure that captures attributes of an enumeration constant, which can be retrieved by functions $position( enumeration\ instance )$, $value( enumeration\ instance )$, and $label( enumeration\ instance )$.
     146\begin{lstlisting}
     147int green_pos = position( green ); // 1
     148char * green_value = value( green ); // "G"
     149char * green_label = label( green ); // "Green"
     150\end{lstlisting}
     151An enumeration instance can be assigned to a variable or used as its position with type integer, its value with declared type T, or its label with type char *, and the compiler will resolve the usage as a type fits the context.
     152\begin{lstlisting}[label=lst:enum_inst_assign_int]
     153int green_pos = green; // equivalent to position( green );
     154\end{lstlisting}
     155A resolution of an enumeration constant is $unambigious$ if only one of the attributes has the resolvable type.
     156In example~\ref{lst:enum_inst_assign_int}, the right-hand side of the assignment expression expects integer type.
     157The position of an enumeration is @int@, while the other two cannot be resolved as integers.
     158The expression unambiguously returns the position of @green@.
     159\begin{lstlisting}[label=lst:enum_inst_assign_string]
     160char * green_value = green; // equivalent to value( green );
     161\end{lstlisting}
     162On the other hand, the resolution of an enumeration constant is $ambigious$ if multiple attributes have the expected type.
     163In example~\ref{lst:enum_inst_assign_string}, both value and label have the expected type @char *@.
     164When a resolution is ambiguous, a \textit{resolution precedence} applies: $$value > position > label$$
     165\CFA uses resolution distance to describe if one type can be used as another. While \CFA calculates the resolution distance between the expected type and types of all three attributes, it would not choose the attribute with the closest distance. Instead, when resolving an enumeration constant, \CFA always chooses value whenever it is a possible resolution (resolution distance is not infinite), followed by position, then label.
     166\begin{lstlisting}[label=lst:enum_inst_precedence]
     167enum(double) Foo { Bar };
     168int tee = Foo.Bar; // value( Bar );
     169\end{lstlisting}
     170In the example~\ref{lst:enum_inst_precedence}, while $position( Bar )$ has the closest resolution among the three attributes, $Foo.Bar$ is resolved as $value( Bar )$ because of the resolution precedence.
     171
     172Although \CFA enumeration captures three different attributes, an instance of enumeration does not occupy extra memory.
     173The @sizeof@ \CFA enumeration instance is always 4 bytes, the same amount of memory to store a C enumeration instance.
     174It comes from the fact that:
     175\begin{enumerate}
     176\item
     177a \CFA enumeration is always statically typed;
     178\item
     179it is always resolved as one of its attributes in terms of real usage.
     180\end{enumerate}
     181When creating the enumeration instance green and assigns it with the enumeration constant @Color.Green@, the compilers essentially allocate an integer variables and store the position 1.
     182The invocations of $positions()$, $value()$, and $label()$ turn into calls to special functions defined in the prelude:
     183\begin{lstlisting}[label=lst:companion_call]
     184position( green );
     185>>> position( Colour, 1 ) -> int
     186value( green );
     187>>> value( Colour, 1 ) -> T
     188label( green );
     189>>> label( Colour, 1) -> char *
     190\end{lstlisting}
     191@T@ represents the type declared in the \CFA enumeration defined and @char *@ in the example.
     192These generated functions are $Companion Functions$, they take an $companion$ object and the position as parameters.
     193
     194\subsection{Companion Object and Companion Function}
     195
     196\begin{lstlisting}[caption={Enum Type Functions}, label=lst:cforall_enum_functions]
     197forall( T )  {
     198        struct Companion {
     199                const T * const values;
     200                const char** const labels;
     201                        int length;
     202        };
     203}
     204\end{lstlisting}
     205\CFA creates an object of Companion for every \CFA-enumeration. A companion object has the same name as the enumeration is defined for.
     206A companion object stores values and labels of enumeration constants, in the order of the constants defined in the enumeration.
     207
     208\CFA generates the definition of companion functions. Because \CFA implicitly stores enumeration instance as its position, the companion function $position$ does nothing but returns the position it passes it.
     209Companions function $value$ and $label$ return the array item at the given position of $values$ and $labels$, respectively.
     210\begin{lstlisting}[label=lst:companion_definition]
     211int position( Companion o, int pos ) { return pos; }
     212T value( Companion o, int pos ) { return o.values[ pos ]; }
     213char * label( Companion o, int pos ) { return o.labels[ pos ]; }
     214\end{lstlisting}
     215Notably, the Companion structure definition, and all companion objects, are visible to the users.
     216A user can retrieve values and labels defined in an enumeration by accessing the values and labels directly, or indirectly by calling Companion functions $values$ and $labels$
     217\begin{lstlisting}[label=lst:companion_definition_values_labels]
     218Colour.values; // read the Companion's values
     219values( Colour ); // Same as Colour.values
     220\end{lstlisting}
     221
     222\subsection{User Define Enumeration Functions}
     223
     224The Companion objects make extending features for \CFA enumeration easy.
     225
     226\begin{lstlisting}[label=lst:companion_user_definition]
     227char * charastic_string( Companion o, int position ) {
     228        return sprintf("Label: %s; Value: %s", label( o, position ), value( o, position) );
     229}
     230printf( charactic_string ( Color, 1 ) );
     231>>> Label: G; Value: G
     232\end{lstlisting}
     233Defining a function takes a Companion object effectively defines functions for all \CFA enumeration.
     234
     235The \CFA compiler turns a function call that takes an enumeration instance as a parameter into a function call with a companion object plus a position.
     236Therefore, a user can use the syntax with a user-defined enumeration function call:
     237\begin{lstlisting}[label=lst:companion_user_definition]
     238charactic_string ( Color.Green ); // equivalent to charactic_string ( Color, 1 )
     239>>> Label: G; Value: G
     240\end{lstlisting}
     241Similarly, the user can work with the enumeration type itself: (see section ref...)
     242\begin{lstlisting}[ label=lst:companion_user_definition]
     243void print_enumerators ( Companion o ) {
     244        for ( c : Companion o ) {
     245                sout | label (c) | value( c ) ;
     246        }
     247}
     248print_enumerators( Colour );
     249\end{lstlisting}
     250
     251\subsection{Runtime Enumeration}
     252
     253The Companion structure definition is visible to users, and users can create an instance of Companion object themselves, which effectively constructs a \textit{Runtime Enumeration}.
     254\begin{lstlisting}[ label=lst:runtime_enum ]
     255const char values[] = { "Hello", "World" };
     256const char labels[] = { "First", "Second" };
     257Companion (char *) MyEnum = { .values: values, .labels: labels, .length: 2 };
     258\end{lstlisting}
     259A runtime enumeration can be used to call enumeration functions.
     260\begin{lstlisting}[ label=lst:runtime_enum_usage ]
     261sout | charatstic_string( MyEnum, 1 );
     262>>> Label: Second; Value: World
     263\end{lstlisting}
     264However, a runtime enumeration cannot create an enumeration instance, and it does not support enum-qualified syntax.
     265\begin{lstlisting}[ label=lst:runtime_enum_usage ]
     266MyEnum e = MyEnum.First; // Does not work: cannot create an enumeration instance e,
     267                                    // and MyEnum.First is not recognizable
     268\end{lstlisting}
     269During the compilation, \CFA adds enumeration declarations to an enumeration symbol table and creates specialized function definitions for \CFA enumeration. \CFA does not recognize runtime enumeration during compilation and would not add them to the enumeration symbol table, resulting in a lack of supports for runtime enumeration.
     270
     271\section{Enumeration Features}
     272
     273A trait is a collection of constraints in \CFA, which can be used to describe types.
     274The \CFA standard library defines traits to categorize types with related enumeration features.
     275
     276\subsection{Auto Initializable}
     277\label{s:AutoInitializable}
     278
     279TODO: make the initialization rule a separate section.
     280
     281If no explicit initializer is given to an enumeration constant, C initializes the first enumeration constant with value 0, and the other enumeration constant has a value equal to its $predecessor+1$.
     282\CFA enumerations have the same rule in enumeration constant initialization.
     283However, not all types can be automatically initialized by \CFA because the meaning of $zero$, $one$, and addition operator may not be well-defined.
     284
     285A type is auto-Initializable if it has defined @zero_t@, @one_t@, and an addition operator.
     286\begin{lstlisting}
    148287forall(T)
    149288trait AutoInitializable {
    150   void ?()( T & t, zero_t );
    151   void ?()( T & t, one_t );
    152   S& ?+=?( T & t, one_t );
    153   void ?{}( T &, T );
    154   T ?{}( T &, T );
    155 };
    156 \end{lstlisting}
    157 
    158 \subsection{AutoInitializable}
    159 \begin{lstlisting}[style=CStyle]
    160 forall(T)
    161 trait AutoInitializable {
    162   void ?()( T & t, zero_t );
    163   void ?()( T & t, one_t );
    164   S& ?+=?( T & t, one_t );
    165   void ?{}( T &, T );
    166   T ?{}( T &, T );
    167 };
    168 \end{lstlisting}
    169 A type is AutoInitializable if it has defined a zero\_t constructor, a one\_t constructor, an addition assignment operator, a copy constructor, and a copy assignment operator.
    170 
    171 \subsection{Enumerable Type}
    172 \begin{lstlisting}[style=CStyle]
    173 forall(T)
    174 trait enumerable {
    175   void ?()( T & t, zero_t );
    176   void ?()( T & t, one_t );
    177   S& ?+=?( T & t, one_t );
    178   void ?{}( T &, T );
    179   T ?{}( T &, T );
    180 };
    181 \end{lstlisting}
    182 
    183 
    184 
    185 
    186 
    187 (Should change the definition of enumerable to something else. Maybe auto-constructible. If a type is not auto-constructible, all enumeration must be explicitly initialized)
    188 \begin{lstlisting}[caption={An example enumerable type}, label{lst:sample_enumerable}, style=CStyle]
    189 struct Type { int i; };
    190 void ?()( Type & t, zero_t ) { t.i = 0; };
    191 void ?()( Type & t, one_t ) { t.i = 1; };
    192 int ?!=?( Type t, zero_t ) { return t.i != 0; };
    193 S& ?+=?( Type & t, one_t ) { t.i += 1; return t; };
    194 void ?()( Type & t, Type rhs ) { t.i = rhs.i; };
    195 Type ?()( Type & t, Type rhs ) { t.i = rhs.i; return t; };
    196 \end{lstlisting}
    197 
    198 A Cforall-enum is a C-enum parameterized by an enumerable type. For example,  $enum(int)$ turns a C-enum into a Cforall-enum.
    199 \begin{lstlisting}[caption={An example Cforall enum}, label{lst:sample_cforall_enum}, style=CStyle]
    200 enum Color(Type) { Red, Green, Blue };
    201 
    202 > Type Color.values[] = { 0, values[0]++, values[1]++ };
    203 > enum Color.Label { Red_Label, Green_Label, Blue_Label };
    204 \end{lstlisting}
    205 Declaring a Cforall-enum, the compiler defines a C-enum names every element in the Cforall-enum, and an array that stores Cforall enumeration values.
    206 
    207 \subsection{Cforall Enumerations Behaviour}
    208 An instance of Cforall-enum (denoted as $<enum\_instance>$) has a label, the defined enum name. The label can be retrieved by calling the function $label()$ on a $<enum\_instance>$. The $value()$ function on the other hand returns the value used to initialize the Cforall-enum.
    209 
    210 Cforall-enum supports a qualified expression. The syntax of the qualified expression for Cforall-enum is $$<enum\_type\_name>.<enum\_instance\_name>$$. In the $Color$ example, $Color$ is a $<enum\_type\_name>$ and $Red$, $Green$, $Blue$ are $<enum\_instance\_name>$.
    211 
    212 \begin{lstlisting}[caption={An example Cforall enum}, label{lst:sample_cforall_enum_usage}, style=CStyle]
    213 enum Color red = Color.Red;
    214 > enum Color.Label red = = Color.Label.Red_Label;
    215 Type instance = Color.Red;
    216 > Type instance = Color.values[ Color.Label.Red_Label ];
    217 \end{lstlisting}
    218 
    219 The expression $Color.Red$ is overloaded to represent both $value(Color.Red)$ and $label(Color.Red)$. The expression returns the $label(Color.Red)$ by default but returns $value()$ whenever the $value()$ is a closer candidate in the context. [more explanation] In \ref{lst:sample_cforall_enum_usage}, when assigned to an enum variable, $Color.Red$ returns the label. This is to reduce the memory to store a Cforall-enum variable. In an assignment expression when the left-hand-side expects a $Type$, the resolution finds $value(Color.Red)$ is a better candidate than $label(Color.Red)$, and returns the value instead.
    220 
    221 \subsection{Enum Type Functions}
    222 \begin{lstlisting}[caption={Enum Type Functions}, label{lst:cforall_enum_functions}, style=CStyle]
    223 enum Color(string) { // assume String has been defined as an enumerable type
    224     R = "Red", G = "Green", B = "Blue"
    225 };
    226 values( Color );
    227 > [ String("Red"), String("Green"), String("Blue") ];
    228 label_strings( Color );
    229 > [ "R", "G", "B" ];
    230 enum Color green = Color.G;
    231 
    232 label_string( Color, green );
    233 > "G"
    234 label( Color, green );
    235 > 1
    236 value( Color, green ) ;
    237 > "Green"
    238 value( Color, "G" );
    239 > "Green"
    240 label( Color, "G" );
    241 > 1
    242 value( Color, "DNE" );
    243 > (null)
    244 value( Color, 1 ); // "1" is the label "G"
    245 > "Green"
    246 \end{lstlisting}
    247 Names of labels are distinct in an enum declaration. Cforall therefore allows indexing an enum value with its string representation of a label.
     289        void ?()( T & t, zero_t );
     290        void ?()( T & t, one_t );
     291        S ?+?( T & t, one_t );
     292};
     293\end{lstlisting}
     294An example of user-defined @AutoInitializable@ would look like the following:
     295\begin{lstlisting}[label=lst:sample_auto_Initializable]
     296struct Odd { int i; };
     297void ?()( Odd & t, zero_t ) { t.i = 1; };
     298void ?()( Odd & t, one_t ) { t.i = 2; };
     299Odd ?+?( Odd t1, Odd t2 )
     300        { return Odd( t1.i + t2.i); };
     301\end{lstlisting}
     302When an enumeration declares an AutoInitializable as its type, no explicit initialization is necessary.
     303\begin{lstlisting}[label=lst:sample_auto_Initializable_usage]
     304enum AutoInitUsage(Odd) {
     305        A, B, C = 6, D
     306};
     307\end{lstlisting}
     308
     309In the example~\ref{lst:sample_auto_Initializable_usage_gen}, because no initializer is specified for the first enumeration constant @A@, \CFA initializes it with the value of @zero_t@, which is 1.
     310@B@ and @D@ have the values of their $predecessor + one_t$, while @one_t@ has the value 2.
     311Therefore, the enumeration is initialized as the following:
     312\begin{lstlisting}[label=lst:sample_auto_Initializable_usage_gen]
     313enum AutoInitUsage(Odd) {
     314        A=1, B=3, C = 6, D=8
     315};
     316\end{lstlisting}
     317In \CFA, integral types, float types, and imaginary numbers are example types that are AutoInitialiable.
     318\begin{lstlisting}[label=lst:letter]
     319enum Alphabet(int) {
     320        A='A', B, C, D, E, F, G, H, I, J, K, L, M,
     321        N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
     322        a='a', b, c, d, e, f, g, h, i, j, k, l, m,
     323        n, o, p, q, r, s, t, u, v, w, x, y, z
     324};
     325print( "%c, %c, %c", Alphabet.F, Alphabet.o, Alphabet.o );
     326>>> F, o, o
     327\end{lstlisting}
    248328
    249329\subsection{Iteration and Range}
    250 A Cforall enum is iterable and supports range function.
    251 \begin{lstlisting}[caption={Range Functions}, label{lst:range_functions}, style=CStyle]
    252 struct string;
    253 enum(string) Weekday(
    254     Monday = "M", Tuesday = "Tu", ...
    255 };
    256 for ( i; Weekday ) { sout | i; }
    257 >> M Tu W Th F Sat Sun
    258 for ( Monday ~= Tuesday )
    259 >> M Tu
     330
     331It is convenient to iterate over a \CFA enumeration.
     332Here is the basic usage:
     333\begin{lstlisting}[label=lst:range_functions]
     334for ( Alphabet ah; Alphabet; ) {
     335        printf( "%d ", ah );
     336}
     337>>> A B C (...omit the rest)
     338\end{lstlisting}
     339The for-loop uses the enumeration type @Alphabet@ as range.
     340When that happens, \CFA iterates all enumerators in the order they defined in the enumeration.
     341@'ch'@ is the iterating enumerator, and it returns the value of an Alphabet in this context according to the precedence rule.
     342
     343\CFA offers a shorthand for iterating all enumeration constants:
     344\begin{lstlisting}[label=lst:range_functions]
     345for ( Alphabet ch ) {
     346        printf( "%d ", ch );
     347}
     348>>> A B C (...omit the rest)
     349\end{lstlisting}
     350
     351Enumeration supports the \CFA loop control syntax for for-loop.
     352\begin{lstlisting}[label=lst:range_functions]
     353for ( Alphabet.D )
     354for ( ch; Alphabet.g ~ Alphabet.z )
     355for ( Alphabet ch; Alphabet.R ~ Alphabet.X ~ 2 )
     356\end{lstlisting}
     357Notably, the meaning of "step" of iteration has changed for enumeration.
     358Consider the following example:
     359\begin{lstlisting}[label=lst:range_functions]
     360enum(int) Sequence {
     361        A = 10, B = 12, C = 14; 
     362}
     363for ( s; Sequence.A ~ Sequence.C ) {
     364        printf( "%d ", s );
     365}
     366
     367>>> 10 12 14
     368
     369for ( s; Sequence.A ~ Sequence.A ~ 2 ) {
     370        printf( "%d ", s );
     371}
     372>>> 10 14
     373\end{lstlisting}
     374The range iteration of enumeration does not return the @current_value++@ until it reaches the upper bound.
     375The semantics is to return the next enumeration constant.
     376If a stepping is specified, 2 for example, it returns the 2 enumeration constant after the current one, rather than the @current+2@.
     377
     378It is also possible to iterate over an enumeration's labels, implicitly or explicitly:
     379\begin{lstlisting}[label=lst:range_functions_label_implicit]
     380for ( char * ch; Alphabet )
     381\end{lstlisting}
     382This for-loop implicitly iterates every label of the enumeration, because a label is the only valid resolution to the ch with type @char *@ in this case.
     383If the value can also be resolved as the @char *@, you might iterate the labels explicitly with the array iteration.
     384\begin{lstlisting}[label=lst:range_functions_label_implicit]
     385for ( char * ch; labels( Alphabet ) )
    260386\end{lstlisting}
    261387
    262388\section{Implementation}
    263389
    264 \subsection{Companion Object}
    265 The intuition to create a companion object is that functions that support enumeration features need static information of an enumeration class. For example, values() returns an array of values defined for the enumeration. $label( Color, "G" )$ needs information about enum names defined for the enum class $Color$. Theoretically, enum-type functions can be defined as functions that take $TypeName$ expression as the first parameter. An alternative approach is to define that "companion object".
    266 
    267 \begin{lstlisting}[caption={Enum Type Functions}, label{lst:cforall_enum_functions}, style=CStyle]
    268 struct string;
    269 enum Color( string ) {
    270     R = "Red", G = "Green", B = "Blue"
    271 };
    272 
    273 forall( T | enumerable(T) )  {
    274     struct Companion {
    275         T* values;
    276         char** labels;
    277     };
    278 }
    279 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    280 enum Color.Label;
    281 Companion( string ) Color = {
    282     .values = [ "Red", "Green", "Blue" ],
    283     .labels = [ "R", "G", "B" ]
    284 };
    285 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    286 forall( T | enumerable(T) )
    287 T value( Companion companion, int index ) { return companion.values[ index ]; }
    288 T value( Companion, enum Color.Label );
    289 char* label( Companion companion, int index ) { return companion.values[ index ]; }
    290 char* label( Companion, enum Color.Label );
    291 
    292 \end{lstlisting}
    293 
    294 
    295 \subsection{Companion Trait}
    296 Users can define the companion object themselves. A companion object should define an array of any type called values and an array of strings representing a label. Defining a companion object effectively creates a new enumerable type.
    297 
    298 \subsection{Companion Mapping}
    299 
    300 
    301 
    302 \begin{lstlisting}[caption={Enum Type Functions}, label{lst:cforall_enum_functions}, style=CStyle]
    303 
    304 \end{lstlisting}
    305 %%
    306 %% If your work has an appendix, this is the place to put it.
    307 \appendix
    308 
     390\CFA places the definition of Companion structure and non-parameterized Companion functions in the prelude, visible globally.
     391
     392\subsection{Declaration}
     393
     394The qualified enumeration syntax is dedicated to \CFA enumeration.
     395\begin{lstlisting}[label=lst:range_functions]
     396enum (type_declaration) name { enumerator = const_expr, enumerator = const_expr, ... }
     397\end{lstlisting}
     398A compiler stores the name, the underlying type, and all enumerators in an @enumeration table@.
     399During the $Validation$ pass, the compiler links the type declaration to the type's definition.
     400It ensures that the name of an enumerator is unique within the enumeration body, and checks if all values of the enumerator have the declaration type.
     401If the declared type is not @Auto Initializable@, \CFA rejects the enumeration definition.
     402Otherwise, it attempts to initialize enumerators with the enumeration initialization pattern. (a reference to a future initialization pattern section)
     403
     404\begin{lstlisting}[label=lst:init]
     405struct T { ... };
     406void ?{}( T & t, zero_t ) { ... };
     407void ?{}( T & t, one_t ) { ... };
     408T ?+?( T & lhs, T & rhs ) { ... };
     409
     410enum (T) Sample {
     411        Zero: 0 /* zero_t */,
     412        One: Zero + 1 /* ?+?( Zero, one_t ) */ , ...
     413};
     414\end{lstlisting}
     415Challenge: \\
     416The value of an enumerator, or the initializer, requires @const_expr@.
     417While previously getting around the issue by pushing it to the C compiler, it might not work anymore because of the user-defined types, user-defined @zero_t@, @one_t@, and addition operation.
     418Might not be able to implement a \emph{correct} static check.
     419
     420\CFA $autogens$ a Companion object for the declared enumeration.
     421\begin{lstlisting}[label=lst:companion]
     422Companion( T ) Sample {
     423        .values: { 0, 0+1, 0+1+1, 0+1+1+1, ... }, /* 0: zero_t, 1: one_t, +: ?+?{} */
     424        .labels: { "Zero", "One", "Two", "Three", ...},
     425        .length: /* number of enumerators */
     426};
     427\end{lstlisting}
     428\CFA stores values as intermediate expressions because the result of the function call to the function @?+?{}(T&, T&)@ is statically unknown to \CFA.
     429But the result is computed at run time, and the compiler ensures the @values@ are not changed.
     430
     431\subsection{qualified expression}
     432
     433\CFA uses qualified expression to address the scoping of \CFA-enumeration.
     434\begin{lstlisting}[label=lst:qualified_expression]
     435aggregation_name.field;
     436\end{lstlisting}
     437The qualified expression is not dedicated to \CFA enumeration.
     438It is a feature that is supported by other aggregation in \CFA as well, including a C enumeration.
     439When C enumerations are unscoped, the qualified expression syntax still helps to disambiguate names in the context.
     440\CFA recognizes if the expression references a \CFA aggregation by searching the presence of @aggregation_name@ in the \CFA enumeration table.
     441If the @aggregation_name@ is identified as a \CFA enumeration, the compiler checks if @field@ presents in the declared \CFA enumeration.
     442
     443\subsection{\lstinline{with} statement/statement}
     444
     445\emph{Work in Progress}
     446
     447Instead of qualifying an enumeration expression every time, one can use the @with@ to expose enumerators to the current scope so that they are directly accessible.
     448
     449\subsection{Instance Declaration}
     450
     451\emph{Work in Progress}
     452
     453\begin{lstlisting}[label=lst:declaration]
     454enum Sample s1;
     455Sample s2;
     456\end{lstlisting}
     457A declaration of \CFA enumeration instance that has no difference than a C enumeration or other \CFA aggregation.
     458The compiler recognizes the type of a variable declaration by searching the name in all possible types.
     459The @enum@ keyword is not necessary but helps to disambiguate types (questionable).
     460The generated code for a \CFA enumeration declaration is utterly an integer, which is meant to store the position.
     461\begin{lstlisting}[label=lst:declaration]
     462int s1;
     463int s2;
     464\end{lstlisting}
     465
     466\subsection{Compiler Representation}
     467
     468\emph{Work in Progress}
     469
     470The internal representation of an enumeration constant is @EnumInstType@.
     471The minimum information an @EnumInstType@ stores is a reference to the \CFA-enumeration declaration and the position of the enumeration constant.
     472\begin{lstlisting}[label=lst:EnumInstType]
     473class EnumInstType {
     474        EnumDecl enumDecl;
     475        int position;
     476};
     477\end{lstlisting}
     478
     479\subsection{Unification and Resolution }
     480
     481\emph{Work in Progress}
     482
     483\begin{lstlisting}
     484enum Colour( char * ) { Red = "R", Green = "G", Blue = "B"  };
     485\end{lstlisting}
     486The @EnumInstType@ is convertible to other types.
     487A \CFA enumeration expression is implicitly \emph{overloaded} with its three different attributes: value, position, and label.
     488The \CFA compilers need to resolve an @EnumInstType@ as one of its attributes based on the current context.
     489
     490\begin{lstlisting}[caption={Null Context}, label=lst:null_context]
     491{
     492        Colour.Green;
     493}
     494\end{lstlisting}
     495In example~\ref{lst:null_context}, the environment gives no information to help with the resolution of @Colour.Green@.
     496In this case, any of the attributes is resolvable.
     497According to the \textit{precedence rule}, the expression with @EnumInstType@ resolves as @value( Colour.Green )@.
     498The @EnumInstType@ is converted to the type of the value, which is statically known to the compiler as @char *@.
     499When the compilation reaches the code generation, the compiler outputs code for type @char *@ with the value @"G"@.
     500\begin{lstlisting}[caption={Null Context Generated Code}, label=lst:null_context]
     501{
     502        "G";
     503}
     504\end{lstlisting}
     505\begin{lstlisting}[caption={int Context}, label=lst:int_context]
     506{
     507        int g = Colour.Green;
     508}
     509\end{lstlisting}
     510The assignment expression gives a context for the EnumInstType resolution.
     511The EnumInstType is used as an @int@, and \CFA needs to determine which of the attributes can be resolved as an @int@ type.
     512The functions $Unify( T1, T2 ): bool$ take two types as parameters and determine if one type can be used as another.
     513In example~\ref{lst:int_context}, the compiler is trying to unify @int@ and @EnumInstType@ of @Colour@.
     514$$Unification( int, EnumInstType<Colour> )$$ which turns into three Unification call
     515\begin{lstlisting}[label=lst:attr_resolution_1]
     516{
     517        Unify( int, char * ); // unify with the type of value
     518        Unify( int, int ); // unify with the type of position
     519        Unify( int, char * ); // unify with the type of label
     520}
     521\end{lstlisting}
     522\begin{lstlisting}[label=lst:attr_resolution_precedence]
     523{
     524        Unification( T1, EnumInstType<T2> ) {
     525                if ( Unify( T1, T2 ) ) return T2;
     526                if ( Unify( T1, int ) ) return int;
     527                if ( Unify( T1, char * ) ) return char *;
     528                Error: Cannot Unify T1 with EnumInstType<T2>;
     529        }
     530}
     531\end{lstlisting}
     532After the unification, @EnumInstType@ is replaced by its attributes.
     533
     534\begin{lstlisting}[caption={Unification Functions}, label=lst:unification_func_call]
     535{
     536        T2 foo ( T1 ); // function take variable with T1 as a parameter
     537        foo( EnumInstType<T3> ); // Call foo with a variable has type EnumInstType<T3>
     538        >>>> Unification( T1, EnumInstType<T3> )
     539}
     540\end{lstlisting}
     541% The conversion can work backward: in restrictive cases, attributes of can be implicitly converted back to the EnumInstType.
     542Backward conversion:
     543\begin{lstlisting}[caption={Unification Functions}, label=lst:unification_func_call]
     544{
     545        enum Colour colour = 1;
     546}
     547\end{lstlisting}
     548
     549\begin{lstlisting}[caption={Unification Functions}, label=lst:unification_func_call]
     550{
     551   Unification( EnumInstType<Colour>, int ) >>> label
     552}
     553\end{lstlisting}
     554@int@ can be unified with the label of Colour.
     555@5@ is a constant expression $\Rightarrow$ Compiler knows the value during the compilation $\Rightarrow$ turns it into
     556\begin{lstlisting}
     557{
     558   enum Colour colour = Colour.Green;
     559}
     560\end{lstlisting}
     561Steps:
     562\begin{enumerate}
     563\item
     564identify @1@ as a constant expression with type @int@, and the value is statically known as @1@
     565\item
     566@unification( EnumInstType<Colour>, int )@: @position( EnumInstType< Colour > )@
     567\item
     568return the enumeration constant at the position 1
     569\end{enumerate}
     570\begin{lstlisting}
     571{
     572        enum T (int) { ... } // Declaration
     573        enum T t = 1;
     574}
     575\end{lstlisting}
     576Steps:
     577\begin{enumerate}
     578\item
     579identify @1@ as a constant expression with type @int@, and the value is statically known as @1@
     580\item
     581@unification( EnumInstType<Colour>, int )@: @value( EnumInstType< Colour > )@
     582\item
     583return the FIRST enumeration constant that has the value 1, by searching through the values array
     584\end{enumerate}
     585The downside of the precedence rule: @EnumInstType@ $\Rightarrow$ @int ( value )@ $\Rightarrow$ @EnumInstType@ may return a different @EnumInstType@ because the value can be repeated and there is no way to know which one is expected $\Rightarrow$ want uniqueness
    309586
    310587\end{document}
    311 \endinput
    312 %%
    313 %% End of file `sample-manuscript.tex'.
     588
     589% Local Variables: %
     590% tab-width: 4 %
     591% compile-command: "pdflatex enum.tex" %
     592% End: %
  • libcfa/src/iostream.cfa

    rdf8ba61a r8d182b1  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Oct 19 21:10:10 2023
    13 // Update Count     : 1801
     12// Last Modified On : Sat Nov 11 07:06:27 2023
     13// Update Count     : 1803
    1414//
    1515
     
    10011001                                } // if
    10021002                        } // if
     1003                        // FIX ME: CFA strings need to be modified to NOT change the argument for this case, then this can be removed.
     1004                        if ( rwd > 0 && args == 0 ) f.s[0]= '\0';       // read failed => no pattern match => set string to null
    10031005                } else {
    10041006                        if ( f.flags.delimiter ) {                                      // getline
     
    10411043                                } // if
    10421044                        } // if
     1045                        if ( rwd > 0 && args == 0 ) f.s[0]= '\0';       // read failed => no pattern match => set string to null
    10431046                } // if
    10441047                if ( args == 1 && eof( is ) ) {                                 // data but scan ended at EOF
  • src/AST/Decl.cpp

    rdf8ba61a r8d182b1  
    2020#include <unordered_map>
    2121
    22 #include "CodeGen/FixMain.h"   // for FixMain
    2322#include "Common/Eval.h"       // for eval
    2423
     
    7675        }
    7776        this->type = ftype;
    78         // Hack forcing the function "main" to have Cforall linkage to replace
    79         // main even if it is inside an extern "C", and also makes sure the
    80         // replacing function is always a C function.
    81         if ( name == "main" ) {
    82                 this->linkage = CodeGen::FixMain::getMainLinkage();
    83         }
    8477}
    8578
     
    108101        }
    109102        this->type = type;
    110         // See note above about this hack.
    111         if ( name == "main" ) {
    112                 this->linkage = CodeGen::FixMain::getMainLinkage();
    113         }
    114103}
    115104
  • src/AST/SymbolTable.cpp

    rdf8ba61a r8d182b1  
    3939        static inline auto stats() {
    4040                using namespace Stats::Counters;
    41                 static auto group   = build<CounterGroup>("Indexers");
     41                static auto group   = build<CounterGroup>("Symbol Tables");
    4242                static struct {
    4343                        SimpleCounter * count;
  • src/AST/SymbolTable.hpp

    rdf8ba61a r8d182b1  
    8888        using Ptr = std::shared_ptr<const SymbolTable>;
    8989
    90         Ptr prevScope;                 ///< Indexer for parent scope
     90        Ptr prevScope;                 ///< Symbol Table for parent scope
    9191        unsigned long scope;           ///< Scope index of this indexer
    9292        unsigned long repScope;        ///< Scope index of currently represented scope
  • src/AST/Type.hpp

    rdf8ba61a r8d182b1  
    3434
    3535namespace ast {
    36 
    37 template< typename T > class Pass;
    3836
    3937class Type : public Node {
  • src/AST/module.mk

    rdf8ba61a r8d182b1  
    2020        AST/Bitfield.hpp \
    2121        AST/Chain.hpp \
    22         AST/Convert.cpp \
    23         AST/Convert.hpp \
    2422        AST/Copy.cpp \
    2523        AST/Copy.hpp \
  • src/BasicTypes-gen.cc

    rdf8ba61a r8d182b1  
    272272        size_t start, end;
    273273
    274 
    275         #define TypeH TOP_SRCDIR "src/SynTree/Type.h"
    276         resetInput( file, TypeH, buffer, code, str );
    277 
    278         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH );
    279         start += sizeof( STARTMK );                                                     // includes newline
    280         code << str.substr( 0, start );
    281 
    282         code << "\t" << BYMK << endl;
    283         code << "\tenum Kind {" << endl;
    284         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    285                 code << "\t\t" << graph[r].name << "," << endl;
    286         } // for
    287         code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;
    288         code << "\t} kind;" << endl;
    289         code << "\t";                                                                           // indentation for end marker
    290 
    291         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );
    292         code << str.substr( start );
    293 
    294         output( file, TypeH, code );
    295         // cout << code.str();
    296 
    297 
    298         #define TypeC TOP_SRCDIR "src/SynTree/Type.cc"
    299         resetInput( file, TypeC, buffer, code, str );
    300 
    301         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC );
    302         start += sizeof( STARTMK );                                                     // includes newline
    303         code << str.substr( 0, start );
    304 
    305         code << BYMK << endl;
    306         code << "const char * BasicType::typeNames[] = {" << endl;
    307         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    308                 code << "\t\"" << graph[r].type << "\"," << endl;
    309         } // for
    310         code << "};" << endl;
    311 
    312         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC );
    313         code << str.substr( start );
    314 
    315         output( file, TypeC, code );
    316         // cout << code.str();
    317 
    318 
    319         // TEMPORARY DURING CHANGE OVER
    320274        #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp"
    321275        resetInput( file, TypeH_AST, buffer, code, str );
  • src/CodeGen/CodeGeneratorNew.cpp

    rdf8ba61a r8d182b1  
    2424namespace CodeGen {
    2525
    26 int CodeGenerator_new::tabsize = 4;
     26int CodeGenerator::tabsize = 4;
    2727
    2828// The kinds of statements that should be followed by whitespace.
     
    3535}
    3636
    37 void CodeGenerator_new::extension( ast::Expr const * expr ) {
     37void CodeGenerator::extension( ast::Expr const * expr ) {
    3838        if ( expr->extension ) output << "__extension__ ";
    3939}
    4040
    41 void CodeGenerator_new::extension( ast::Decl const * decl ) {
     41void CodeGenerator::extension( ast::Decl const * decl ) {
    4242        if ( decl->extension ) output << "__extension__ ";
    4343}
    4444
    45 void CodeGenerator_new::asmName( ast::DeclWithType const * decl ) {
     45void CodeGenerator::asmName( ast::DeclWithType const * decl ) {
    4646        if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) {
    4747                output << " asm ( " << asmName->rep << " )";
     
    4949}
    5050
    51 CodeGenerator_new::LabelPrinter & CodeGenerator_new::LabelPrinter::operator()(
     51CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()(
    5252                std::vector<ast::Label> const & l ) {
    5353        labels = &l;
     
    5555}
    5656
    57 std::ostream & CodeGenerator_new::LabelPrinter::operator()( std::ostream & output ) const {
     57std::ostream & CodeGenerator::LabelPrinter::operator()( std::ostream & output ) const {
    5858        const std::vector<ast::Label> & labels = *this->labels;
    5959        for ( const ast::Label & label : labels ) {
     
    6666// Using updateLocation at the beginning of a node and endl within a node
    6767// should become the method of formating.
    68 void CodeGenerator_new::updateLocation( CodeLocation const & to ) {
     68void CodeGenerator::updateLocation( CodeLocation const & to ) {
    6969        // Skip if linemarks shouldn't appear or if location is unset.
    7070        if ( !options.lineMarks || to.isUnset() ) return;
     
    8686}
    8787
    88 void CodeGenerator_new::updateLocation( ast::ParseNode const * to ) {
     88void CodeGenerator::updateLocation( ast::ParseNode const * to ) {
    8989        updateLocation( to->location );
    9090}
    9191
    92 std::ostream & CodeGenerator_new::LineEnder::operator()( std::ostream & os ) const {
     92std::ostream & CodeGenerator::LineEnder::operator()( std::ostream & os ) const {
    9393        os << "\n" << std::flush;
    9494        cg.currentLocation.first_line++;
     
    9696}
    9797
    98 CodeGenerator_new::CodeGenerator_new( std::ostream & os, const Options & options ) :
    99                 indent( 0, CodeGenerator_new::tabsize ), output( os ),
     98CodeGenerator::CodeGenerator( std::ostream & os, const Options & options ) :
     99                indent( 0, CodeGenerator::tabsize ), output( os ),
    100100                options( options ), printLabels( *this ), endl( *this )
    101101{}
    102102
    103 std::string CodeGenerator_new::mangleName( ast::DeclWithType const * decl ) {
     103std::string CodeGenerator::mangleName( ast::DeclWithType const * decl ) {
    104104        // GCC builtins should always be printed unmangled.
    105105        if ( options.pretty || decl->linkage.is_gcc_builtin ) {
     
    112112}
    113113
    114 void CodeGenerator_new::genAttributes(
     114void CodeGenerator::genAttributes(
    115115                const std::vector<ast::ptr<ast::Attribute>> & attributes ) {
    116116        if ( attributes.empty() ) return;
     
    129129}
    130130
    131 void CodeGenerator_new::previsit( ast::Node const * ) {
     131void CodeGenerator::previsit( ast::Node const * ) {
    132132        // All traversal is manual.
    133133        // TODO: Which means the ast::Pass is just providing a default no visit?
     
    135135}
    136136
    137 void CodeGenerator_new::previsit( ast::ParseNode const * node ) {
     137void CodeGenerator::previsit( ast::ParseNode const * node ) {
    138138        previsit( (ast::Node const *)node );
    139139        updateLocation( node );
    140140}
    141141
    142 void CodeGenerator_new::postvisit( ast::Node const * node ) {
     142void CodeGenerator::postvisit( ast::Node const * node ) {
    143143        std::stringstream ss;
    144144        ast::print( ss, node );
     
    146146}
    147147
    148 void CodeGenerator_new::previsit( ast::Expr const * expr ) {
     148void CodeGenerator::previsit( ast::Expr const * expr ) {
    149149        previsit( (ast::ParseNode const *)expr );
    150150        GuardAction( [this, expr](){
     
    155155}
    156156
    157 void CodeGenerator_new::postvisit( ast::FunctionDecl const * decl ) {
     157void CodeGenerator::postvisit( ast::FunctionDecl const * decl ) {
    158158        // Deleted decls should never be used, so don't print them in C.
    159159        if ( decl->isDeleted && options.genC ) return;
     
    168168
    169169        std::ostringstream acc;
    170         ast::Pass<CodeGenerator_new> subCG( acc, subOptions );
     170        ast::Pass<CodeGenerator> subCG( acc, subOptions );
    171171        // Add the forall clause.
    172172        // TODO: These probably should be removed by now and the assert used.
     
    213213}
    214214
    215 //void CodeGenerator_new::postvisit( ast::ObjectDecl const * decl_ ) {
    216 ast::ObjectDecl const * CodeGenerator_new::postvisit(
     215ast::ObjectDecl const * CodeGenerator::postvisit(
    217216                ast::ObjectDecl const * decl ) {
    218217        // Deleted decls should never be used, so don't print them in C.
     
    262261}
    263262
    264 void CodeGenerator_new::handleStorageClass( ast::DeclWithType const * decl ) {
     263void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) {
    265264        if ( decl->storage.any() ) {
    266265                ast::print( output, decl->storage );
     
    268267}
    269268
    270 void CodeGenerator_new::handleAggregate(
     269void CodeGenerator::handleAggregate(
    271270                ast::AggregateDecl const * decl, std::string const & kind ) {
    272271        if ( !decl->params.empty() && !options.genC ) {
     
    296295}
    297296
    298 void CodeGenerator_new::postvisit( ast::StructDecl const * decl ) {
     297void CodeGenerator::postvisit( ast::StructDecl const * decl ) {
    299298        extension( decl );
    300299        handleAggregate( decl, "struct " );
    301300}
    302301
    303 void CodeGenerator_new::postvisit( ast::UnionDecl const * decl ) {
     302void CodeGenerator::postvisit( ast::UnionDecl const * decl ) {
    304303        extension( decl );
    305304        handleAggregate( decl, "union " );
     
    332331}
    333332
    334 void CodeGenerator_new::postvisit( ast::EnumDecl const * decl ) {
     333void CodeGenerator::postvisit( ast::EnumDecl const * decl ) {
    335334        extension( decl );
    336335        auto members = decl->members;
     
    370369}
    371370
    372 void CodeGenerator_new::postvisit( ast::TraitDecl const * decl ) {
     371void CodeGenerator::postvisit( ast::TraitDecl const * decl ) {
    373372        assertf( !options.genC, "TraitDecls should not reach code generation." );
    374373        extension( decl );
     
    376375}
    377376
    378 void CodeGenerator_new::postvisit( ast::TypedefDecl const * decl ) {
     377void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) {
    379378        assertf( !options.genC, "Typedefs should not reach code generation." );
    380379        output << "typedef " << genType( decl->base, decl->name, options ) << endl;
    381380}
    382381
    383 void CodeGenerator_new::postvisit( ast::TypeDecl const * decl ) {
     382void CodeGenerator::postvisit( ast::TypeDecl const * decl ) {
    384383        assertf( !options.genC, "TypeDecls should not reach code generation." );
    385384        output << decl->genTypeString() << " " << decl->name;
     
    397396}
    398397
    399 void CodeGenerator_new::postvisit( ast::StaticAssertDecl const * decl ) {
     398void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) {
    400399        output << "_Static_assert(";
    401400        decl->cond->accept( *visitor );
     
    405404}
    406405
    407 void CodeGenerator_new::postvisit( ast::Designation const * designation ) {
     406void CodeGenerator::postvisit( ast::Designation const * designation ) {
    408407        auto designators = designation->designators;
    409408        if ( 0 == designators.size() ) return;
     
    423422}
    424423
    425 void CodeGenerator_new::postvisit( ast::SingleInit const * init ) {
     424void CodeGenerator::postvisit( ast::SingleInit const * init ) {
    426425        init->value->accept( *visitor );
    427426}
    428427
    429 void CodeGenerator_new::postvisit( ast::ListInit const * init ) {
     428void CodeGenerator::postvisit( ast::ListInit const * init ) {
    430429        auto initBegin = init->initializers.begin();
    431430        auto initEnd = init->initializers.end();
     
    446445}
    447446
    448 void CodeGenerator_new::postvisit( ast::ConstructorInit const * init ) {
     447void CodeGenerator::postvisit( ast::ConstructorInit const * init ) {
    449448        assertf( !options.genC, "ConstructorInit nodes should not reach code generation." );
    450449        // This isn't actual code, but labels the constructor/destructor pairs.
     
    456455}
    457456
    458 void CodeGenerator_new::postvisit( ast::ApplicationExpr const * expr ) {
     457void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) {
    459458        extension( expr );
    460459        if ( auto var = expr->func.as<ast::VariableExpr>() ) {
     
    550549}
    551550
    552 void CodeGenerator_new::postvisit( ast::UntypedExpr const * expr ) {
     551void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) {
    553552        extension( expr );
    554553        if ( auto name = expr->func.as<ast::NameExpr>() ) {
     
    638637}
    639638
    640 void CodeGenerator_new::postvisit( ast::RangeExpr const * expr ) {
     639void CodeGenerator::postvisit( ast::RangeExpr const * expr ) {
    641640        expr->low->accept( *visitor );
    642641        output << " ... ";
     
    644643}
    645644
    646 void CodeGenerator_new::postvisit( ast::NameExpr const * expr ) {
     645void CodeGenerator::postvisit( ast::NameExpr const * expr ) {
    647646        extension( expr );
    648647        if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) {
     
    657656}
    658657
    659 void CodeGenerator_new::postvisit( ast::DimensionExpr const * expr ) {
     658void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) {
    660659        extension( expr );
    661660        output << "/*non-type*/" << expr->name;
    662661}
    663662
    664 void CodeGenerator_new::postvisit( ast::AddressExpr const * expr ) {
     663void CodeGenerator::postvisit( ast::AddressExpr const * expr ) {
    665664        extension( expr );
    666665        output << "(&";
     
    669668}
    670669
    671 void CodeGenerator_new::postvisit( ast::LabelAddressExpr const * expr ) {
     670void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) {
    672671        extension( expr );
    673672        output << "(&&" << expr->arg << ")";
    674673}
    675674
    676 void CodeGenerator_new::postvisit( ast::CastExpr const * expr ) {
     675void CodeGenerator::postvisit( ast::CastExpr const * expr ) {
    677676        extension( expr );
    678677        output << "(";
     
    688687}
    689688
    690 void CodeGenerator_new::postvisit( ast::KeywordCastExpr const * expr ) {
     689void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) {
    691690        assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
    692691        extension( expr );
     
    696695}
    697696
    698 void CodeGenerator_new::postvisit( ast::VirtualCastExpr const * expr ) {
     697void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) {
    699698        assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
    700699        extension( expr );
     
    705704}
    706705
    707 void CodeGenerator_new::postvisit( ast::UntypedMemberExpr const * expr ) {
     706void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) {
    708707        assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
    709708        extension( expr );
     
    713712}
    714713
    715 void CodeGenerator_new::postvisit( ast::MemberExpr const * expr ) {
     714void CodeGenerator::postvisit( ast::MemberExpr const * expr ) {
    716715        extension( expr );
    717716        expr->aggregate->accept( *visitor );
     
    719718}
    720719
    721 void CodeGenerator_new::postvisit( ast::VariableExpr const * expr ) {
     720void CodeGenerator::postvisit( ast::VariableExpr const * expr ) {
    722721        extension( expr );
    723722        const OperatorInfo * opInfo;
     
    733732}
    734733
    735 void CodeGenerator_new::postvisit( ast::ConstantExpr const * expr ) {
     734void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) {
    736735        extension( expr );
    737736        output << expr->rep;
    738737}
    739738
    740 void CodeGenerator_new::postvisit( ast::SizeofExpr const * expr ) {
     739void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) {
    741740        extension( expr );
    742741        output << "sizeof(";
     
    749748}
    750749
    751 void CodeGenerator_new::postvisit( ast::AlignofExpr const * expr ) {
     750void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) {
    752751        // Using the GCC extension to avoid changing the std to C11.
    753752        extension( expr );
     
    761760}
    762761
    763 void CodeGenerator_new::postvisit( ast::UntypedOffsetofExpr const * expr ) {
     762void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) {
    764763        assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
    765764        output << "offsetof(";
     
    769768}
    770769
    771 void CodeGenerator_new::postvisit( ast::OffsetofExpr const * expr ) {
     770void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) {
    772771        // Use GCC builtin
    773772        output << "__builtin_offsetof(";
     
    777776}
    778777
    779 void CodeGenerator_new::postvisit( ast::OffsetPackExpr const * expr ) {
     778void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) {
    780779        assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
    781780        output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
    782781}
    783782
    784 void CodeGenerator_new::postvisit( ast::LogicalExpr const * expr ) {
     783void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) {
    785784        extension( expr );
    786785        output << "(";
     
    791790}
    792791
    793 void CodeGenerator_new::postvisit( ast::ConditionalExpr const * expr ) {
     792void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) {
    794793        extension( expr );
    795794        output << "(";
     
    802801}
    803802
    804 void CodeGenerator_new::postvisit( ast::CommaExpr const * expr ) {
     803void CodeGenerator::postvisit( ast::CommaExpr const * expr ) {
    805804        extension( expr );
    806805        output << "(";
     
    818817}
    819818
    820 void CodeGenerator_new::postvisit( ast::TupleAssignExpr const * expr ) {
     819void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) {
    821820        assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
    822821        expr->stmtExpr->accept( *visitor );
    823822}
    824823
    825 void CodeGenerator_new::postvisit( ast::UntypedTupleExpr const * expr ) {
     824void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) {
    826825        assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
    827826        extension( expr );
     
    831830}
    832831
    833 void CodeGenerator_new::postvisit( ast::TupleExpr const * expr ) {
     832void CodeGenerator::postvisit( ast::TupleExpr const * expr ) {
    834833        assertf( !options.genC, "TupleExpr should not reach code generation." );
    835834        extension( expr );
     
    839838}
    840839
    841 void CodeGenerator_new::postvisit( ast::TupleIndexExpr const * expr ) {
     840void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) {
    842841        assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
    843842        extension( expr );
     
    846845}
    847846
    848 void CodeGenerator_new::postvisit( ast::TypeExpr const * expr ) {
     847void CodeGenerator::postvisit( ast::TypeExpr const * expr ) {
    849848        // TODO: Should there be an assertion there?
    850849        if ( !options.genC ) {
     
    853852}
    854853
    855 void CodeGenerator_new::postvisit( ast::AsmExpr const * expr ) {
     854void CodeGenerator::postvisit( ast::AsmExpr const * expr ) {
    856855        if ( !expr->inout.empty() ) {
    857856                output << "[ " << expr->inout << " ] ";
     
    863862}
    864863
    865 void CodeGenerator_new::postvisit( ast::CompoundLiteralExpr const * expr ) {
     864void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) {
    866865        //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
    867866        assert( expr->result && expr->init.as<ast::ListInit>() );
     
    870869}
    871870
    872 void CodeGenerator_new::postvisit( ast::UniqueExpr const * expr ) {
     871void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) {
    873872        assertf( !options.genC, "UniqueExpr should not reach code generation." );
    874873        output << "unq<" << expr->id << ">{ ";
     
    877876}
    878877
    879 void CodeGenerator_new::postvisit( ast::StmtExpr const * expr ) {
     878void CodeGenerator::postvisit( ast::StmtExpr const * expr ) {
    880879        auto stmts = expr->stmts->kids;
    881880        output << "({" << endl;
     
    905904}
    906905
    907 void CodeGenerator_new::postvisit( ast::ConstructorExpr const * expr ) {
     906void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) {
    908907        assertf( !options.genC, "ConstructorExpr should not reach code generation." );
    909908        expr->callExpr->accept( *visitor );
    910909}
    911910
    912 void CodeGenerator_new::postvisit( ast::DeletedExpr const * expr ) {
     911void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) {
    913912        assertf( !options.genC, "DeletedExpr should not reach code generation." );
    914913        expr->expr->accept( *visitor );
    915914}
    916915
    917 void CodeGenerator_new::postvisit( ast::DefaultArgExpr const * expr ) {
     916void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) {
    918917        assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
    919918        expr->expr->accept( *visitor );
    920919}
    921920
    922 void CodeGenerator_new::postvisit( ast::GenericExpr const * expr ) {
     921void CodeGenerator::postvisit( ast::GenericExpr const * expr ) {
    923922        assertf( !options.genC, "GenericExpr should not reach code generation." );
    924923        output << "_Generic(";
     
    940939}
    941940
    942 void CodeGenerator_new::postvisit( ast::CompoundStmt const * stmt ) {
     941void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) {
    943942        output << "{" << endl;
    944943
     
    955954}
    956955
    957 void CodeGenerator_new::postvisit( ast::ExprStmt const * stmt ) {
     956void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) {
    958957        assert( stmt );
    959958        // Cast the top-level expression to void to reduce gcc warnings.
     
    967966}
    968967
    969 void CodeGenerator_new::postvisit( ast::AsmStmt const * stmt ) {
     968void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) {
    970969        output << "asm ";
    971970        if ( stmt->isVolatile ) output << "volatile ";
     
    991990}
    992991
    993 void CodeGenerator_new::postvisit( ast::AsmDecl const * decl ) {
     992void CodeGenerator::postvisit( ast::AsmDecl const * decl ) {
    994993        output << "asm ";
    995994        ast::AsmStmt const * stmt = decl->stmt;
     
    999998}
    1000999
    1001 void CodeGenerator_new::postvisit( ast::DirectiveDecl const * decl ) {
     1000void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) {
    10021001        // endl prevents spaces before the directive.
    10031002        output << endl << decl->stmt->directive;
    10041003}
    10051004
    1006 void CodeGenerator_new::postvisit( ast::DirectiveStmt const * stmt ) {
     1005void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) {
    10071006        // endl prevents spaces before the directive.
    10081007        output << endl << stmt->directive;
    10091008}
    10101009
    1011 void CodeGenerator_new::postvisit( ast::IfStmt const * stmt ) {
     1010void CodeGenerator::postvisit( ast::IfStmt const * stmt ) {
    10121011        output << "if ( ";
    10131012        stmt->cond->accept( *visitor );
     
    10221021}
    10231022
    1024 void CodeGenerator_new::postvisit( ast::SwitchStmt const * stmt ) {
     1023void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) {
    10251024        output << "switch ( ";
    10261025        stmt->cond->accept( *visitor );
     
    10361035}
    10371036
    1038 void CodeGenerator_new::postvisit( ast::CaseClause const * clause ) {
     1037void CodeGenerator::postvisit( ast::CaseClause const * clause ) {
    10391038        updateLocation( clause );
    10401039        output << indent;
     
    10561055}
    10571056
    1058 void CodeGenerator_new::postvisit( ast::BranchStmt const * stmt ) {
     1057void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) {
    10591058        switch ( stmt->kind ) {
    10601059        case ast::BranchStmt::Goto:
     
    10911090}
    10921091
    1093 void CodeGenerator_new::postvisit( ast::ReturnStmt const * stmt ) {
     1092void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) {
    10941093        output << "return ";
    10951094        if ( stmt->expr ) stmt->expr->accept( *visitor );
     
    10971096}
    10981097
    1099 void CodeGenerator_new::postvisit( ast::ThrowStmt const * stmt ) {
     1098void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) {
    11001099        assertf( !options.genC, "ThrowStmt should not reach code generation." );
    11011100
     
    11121111}
    11131112
    1114 void CodeGenerator_new::postvisit( ast::CatchClause const * stmt ) {
     1113void CodeGenerator::postvisit( ast::CatchClause const * stmt ) {
    11151114        assertf( !options.genC, "CatchClause should not reach code generation." );
    11161115
     
    11261125}
    11271126
    1128 void CodeGenerator_new::postvisit( ast::WaitForStmt const * stmt ) {
     1127void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) {
    11291128        assertf( !options.genC, "WaitforStmt should not reach code generation." );
    11301129
     
    11721171}
    11731172
    1174 void CodeGenerator_new::postvisit( ast::WithStmt const * stmt ) {
     1173void CodeGenerator::postvisit( ast::WithStmt const * stmt ) {
    11751174        assertf( !options.genC, "WithStmt should not reach code generation." );
    11761175
     
    11811180}
    11821181
    1183 void CodeGenerator_new::postvisit( ast::WhileDoStmt const * stmt ) {
     1182void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) {
    11841183        if ( stmt->isDoWhile ) {
    11851184                output << "do";
     
    11911190        output << " ";
    11921191
    1193         output << CodeGenerator_new::printLabels( stmt->body->labels );
     1192        output << CodeGenerator::printLabels( stmt->body->labels );
    11941193        stmt->body->accept( *visitor );
    11951194
     
    12031202}
    12041203
    1205 void CodeGenerator_new::postvisit( ast::ForStmt const * stmt ) {
     1204void CodeGenerator::postvisit( ast::ForStmt const * stmt ) {
    12061205        // Initializer is always hoised so don't generate it.
    12071206        // TODO: Do an assertion check?
     
    12261225}
    12271226
    1228 void CodeGenerator_new::postvisit( ast::NullStmt const * ) {
     1227void CodeGenerator::postvisit( ast::NullStmt const * ) {
    12291228        output << "/* null statement */ ;";
    12301229}
    12311230
    1232 void CodeGenerator_new::postvisit( ast::DeclStmt const * stmt ) {
     1231void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) {
    12331232        stmt->decl->accept( *visitor );
    12341233
     
    12361235}
    12371236
    1238 void CodeGenerator_new::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
     1237void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
    12391238        assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
    12401239        stmt->callStmt->accept( *visitor );
    12411240}
    12421241
    1243 void CodeGenerator_new::postvisit( ast::MutexStmt const * stmt ) {
     1242void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) {
    12441243        assertf( !options.genC, "MutexStmt should not reach code generation." );
    12451244        // TODO: But this isn't what a mutex statement looks like.
  • src/CodeGen/CodeGeneratorNew.hpp

    rdf8ba61a r8d182b1  
    2525namespace CodeGen {
    2626
    27 #warning Remove the _new when old version is removed.
    28 struct CodeGenerator_new :
     27struct CodeGenerator final :
    2928                public ast::WithGuards,
    3029                public ast::WithShortCircuiting,
    31                 public ast::WithVisitorRef<CodeGenerator_new> {
    32         CodeGenerator_new( std::ostream & out, Options const & options );
     30                public ast::WithVisitorRef<CodeGenerator> {
     31        CodeGenerator( std::ostream & out, Options const & options );
    3332
    3433        // Turn off visit_children for all nodes.
     
    119118        /// Custom local implementation of endl that updates print location.
    120119        struct LineEnder {
    121                 CodeGenerator_new & cg;
    122                 LineEnder( CodeGenerator_new & cg ) : cg( cg ) {}
     120                CodeGenerator & cg;
     121                LineEnder( CodeGenerator & cg ) : cg( cg ) {}
    123122                std::ostream & operator()( std::ostream & ) const;
    124123        };
     
    129128        /// Wrapper class to help print vectors of Labels.
    130129        struct LabelPrinter {
    131                 LabelPrinter( CodeGenerator_new & cg ) : cg( cg ), labels( nullptr ) {}
     130                LabelPrinter( CodeGenerator & cg ) : cg( cg ), labels( nullptr ) {}
    132131                LabelPrinter & operator()( std::vector<ast::Label> const & l );
    133132                std::ostream & operator()( std::ostream & ) const;
    134                 CodeGenerator_new & cg;
     133                CodeGenerator & cg;
    135134                std::vector<ast::Label> const * labels;
    136135        };
  • src/CodeGen/FixMain.cc

    rdf8ba61a r8d182b1  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.cc --
     7// FixMain.cc -- Tools to change a Cforall main into a C main.
    88//
    99// Author           : Thierry Delisle
     
    2525#include "AST/Type.hpp"
    2626#include "AST/Vector.hpp"
    27 #include "Common/PassVisitor.h"
    2827#include "Common/SemanticError.h"  // for SemanticError
    2928#include "CodeGen/GenType.h"       // for GenType
    30 #include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
    31 #include "SynTree/Type.h"          // for FunctionType
    3229#include "SymTab/Mangler.h"
    3330
     
    3633namespace {
    3734
    38 struct FindMainCore {
    39         FunctionDecl * main_signature = nullptr;
    40 
    41         void previsit( FunctionDecl * decl ) {
    42                 if ( FixMain::isMain( decl ) ) {
    43                         if ( main_signature ) {
    44                                 SemanticError( decl, "Multiple definition of main routine\n" );
    45                         }
    46                         main_signature = decl;
    47                 }
    48         }
    49 };
    50 
    51 struct FindMainCore_new {
     35struct FindMainCore final {
    5236        ast::FunctionDecl const * main_declaration = nullptr;
    5337
    5438        void previsit( ast::FunctionDecl const * decl ) {
    55                 if ( FixMain::isMain( decl ) ) {
     39                if ( isMain( decl ) ) {
    5640                        if ( main_declaration ) {
    5741                                SemanticError( decl, "Multiple definition of main routine\n" );
     
    6549        return genType( types[at], "", Options( false, false, false, false ) );
    6650}
    67 
    68 }
    69 
    70         template<typename container>
    71         std::string genTypeAt(const container& p, size_t idx) {
    72                 return genType((*std::next(p.begin(), idx))->get_type(), "");
    73         }
    74 
    75         void FixMain::fix( std::list< Declaration * > & translationUnit,
    76                         std::ostream &os, const char* bootloader_filename ) {
    77                 PassVisitor< FindMainCore > main_finder;
    78                 acceptAll( translationUnit, main_finder );
    79                 FunctionDecl * main_signature = main_finder.pass.main_signature;
    80 
    81                 if( main_signature ) {
    82                         os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
    83                         main_signature->mangleName = SymTab::Mangler::mangle(main_signature);
    84 
    85                         os << main_signature->get_scopedMangleName() << "(";
    86                         const auto& params = main_signature->get_functionType()->get_parameters();
    87                         switch(params.size()) {
    88                                 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
    89                                 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
    90                                 case 0: break;
    91                                 default : assert(false);
    92                         }
    93                         os << "); }\n";
    94 
    95                         std::ifstream bootloader(bootloader_filename, std::ios::in);
    96                         assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
    97                         os << bootloader.rdbuf();
    98                 }
    99         }
    100 
    101 namespace {
    10251
    10352ast::ObjectDecl * makeIntObj(){
     
    157106}
    158107
     108struct FixLinkageCore final {
     109        ast::Linkage::Spec const spec;
     110        FixLinkageCore( ast::Linkage::Spec spec ) : spec( spec ) {}
     111
     112        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ) {
     113                if ( decl->name != "main" ) return decl;
     114                return ast::mutate_field( decl, &ast::FunctionDecl::linkage, spec );
     115        }
     116};
     117
    159118} // namespace
    160119
    161 bool FixMain::isMain( FunctionDecl * decl ) {
    162         if ( std::string("main") != decl->name ) {
    163                 return false;
    164         }
    165         return is_main( SymTab::Mangler::mangle( decl, true, true ) );
    166 }
    167 
    168 bool FixMain::isMain( const ast::FunctionDecl * decl ) {
     120bool isMain( const ast::FunctionDecl * decl ) {
    169121        if ( std::string("main") != decl->name ) {
    170122                return false;
     
    173125}
    174126
    175 void FixMain::fix( ast::TranslationUnit & translationUnit,
     127void fixMainLinkage( ast::TranslationUnit & translationUnit,
     128                bool replace_main ) {
     129        ast::Linkage::Spec const spec =
     130                ( replace_main ) ? ast::Linkage::Cforall : ast::Linkage::C;
     131        ast::Pass<FixLinkageCore>::run( translationUnit, spec );
     132}
     133
     134void fixMainInvoke( ast::TranslationUnit & translationUnit,
    176135                std::ostream &os, const char * bootloader_filename ) {
    177136
    178         ast::Pass<FindMainCore_new> main_finder;
     137        ast::Pass<FindMainCore> main_finder;
    179138        ast::accept_all( translationUnit, main_finder );
    180139        if ( nullptr == main_finder.core.main_declaration ) return;
  • src/CodeGen/FixMain.h

    rdf8ba61a r8d182b1  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.h --
     7// FixMain.h -- Tools to change a Cforall main into a C main.
    88//
    99// Author           : Thierry Delisle
     
    1717
    1818#include <iosfwd>
    19 #include <memory>
    20 #include <list>
    2119
    22 #include "AST/LinkageSpec.hpp"
    23 #include "SynTree/LinkageSpec.h"
    24 
    25 class Declaration;
    26 class FunctionDecl;
    2720namespace ast {
    2821        class FunctionDecl;
     
    3225namespace CodeGen {
    3326
    34 class FixMain {
    35 public :
    36         static inline LinkageSpec::Spec mainLinkage() {
    37                 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
    38         }
    39         static inline ast::Linkage::Spec getMainLinkage() {
    40                 return replace_main ? ast::Linkage::Cforall : ast::Linkage::C;
    41         }
     27/// Is this function a program main function?
     28bool isMain( const ast::FunctionDecl * decl );
    4229
    43         static inline void setReplaceMain(bool val) {
    44                 replace_main = val;
    45         }
     30/// Adjust the linkage of main functions.
     31void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain );
    4632
    47         static bool isMain(FunctionDecl* decl);
    48         static bool isMain(const ast::FunctionDecl * decl);
    49 
    50         static void fix( std::list< Declaration * > & decls,
    51                         std::ostream &os, const char* bootloader_filename );
    52         static void fix( ast::TranslationUnit & translationUnit,
    53                         std::ostream &os, const char * bootloader_filename );
    54 
    55 private:
    56         static bool replace_main;
    57 };
     33/// Add a wrapper around to run the Cforall main.
     34void fixMainInvoke( ast::TranslationUnit & transUnit,
     35                std::ostream & os, const char * bootloaderFilename );
    5836
    5937} // namespace CodeGen
  • src/CodeGen/FixNames.cc

    rdf8ba61a r8d182b1  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
    24 #include "Common/PassVisitor.h"
    2524#include "Common/SemanticError.h"  // for SemanticError
    2625#include "FixMain.h"               // for FixMain
    2726#include "SymTab/Mangler.h"        // for Mangler
    28 #include "SynTree/LinkageSpec.h"   // for Cforall, isMangled
    29 #include "SynTree/Constant.h"      // for Constant
    30 #include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declarat...
    31 #include "SynTree/Expression.h"    // for ConstantExpr
    32 #include "SynTree/Label.h"         // for Label, noLabels
    33 #include "SynTree/Statement.h"     // for ReturnStmt, CompoundStmt
    34 #include "SynTree/Type.h"          // for Type, BasicType, Type::Qualifiers
    35 #include "SynTree/Visitor.h"       // for Visitor, acceptAll
    3627#include "CompilationState.h"
    3728
    3829namespace CodeGen {
    39         class FixNames : public WithGuards {
    40           public:
    41                 void postvisit( ObjectDecl *objectDecl );
    42                 void postvisit( FunctionDecl *functionDecl );
    4330
    44                 void previsit( CompoundStmt *compoundStmt );
    45           private:
    46                 int scopeLevel = 1;
    47 
    48                 void fixDWT( DeclarationWithType *dwt );
    49         };
    50 
    51         void fixNames( std::list< Declaration* > & translationUnit ) {
    52                 PassVisitor<FixNames> fixer;
    53                 acceptAll( translationUnit, fixer );
    54         }
    55 
    56         void FixNames::fixDWT( DeclarationWithType * dwt ) {
    57                 if ( dwt->get_name() != "" ) {
    58                         if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) {
    59                                 if (!useNewAST) {
    60                                         dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
    61                                 }
    62                                 dwt->set_scopeLevel( scopeLevel );
    63                         } // if
    64                 } // if
    65         }
    66 
    67         void FixNames::postvisit( ObjectDecl * objectDecl ) {
    68                 fixDWT( objectDecl );
    69         }
    70 
    71         void FixNames::postvisit( FunctionDecl * functionDecl ) {
    72                 fixDWT( functionDecl );
    73 
    74                 if ( FixMain::isMain( functionDecl ) ) {
    75                         int nargs = functionDecl->get_functionType()->get_parameters().size();
    76                         if( !(nargs == 0 || nargs == 2 || nargs == 3) ) {
    77                                 SemanticError(functionDecl, "Main expected to have 0, 2 or 3 arguments\n");
    78                         }
    79                         functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    80                 }
    81         }
    82 
    83         void FixNames::previsit( CompoundStmt * ) {
    84                 scopeLevel++;
    85                 GuardAction( [this](){ scopeLevel--; } );
    86         }
     31namespace {
    8732
    8833/// Does work with the main function and scopeLevels.
    89 class FixNames_new final {
     34class FixNames final {
    9035        int scopeLevel = 1;
    9136
     
    10348
    10449        const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) {
    105                 if ( FixMain::isMain( functionDecl ) ) {
     50                if ( isMain( functionDecl ) ) {
    10651                        auto mutDecl = ast::mutate( functionDecl );
    10752
     
    13883};
    13984
     85} // namespace
     86
    14087void fixNames( ast::TranslationUnit & translationUnit ) {
    141         ast::Pass<FixNames_new>::run( translationUnit );
     88        ast::Pass<FixNames>::run( translationUnit );
    14289}
    14390
  • src/CodeGen/FixNames.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 #include <list>  // for list
    19 
    20 class Declaration;
    2118namespace ast {
    2219        class TranslationUnit;
     
    2421
    2522namespace CodeGen {
    26         /// mangles object and function names
    27         void fixNames( std::list< Declaration* > & translationUnit );
     23
    2824/// Sets scope levels and fills in main's default return.
    2925void fixNames( ast::TranslationUnit & translationUnit );
     26
    3027} // namespace CodeGen
    3128
  • src/CodeGen/GenType.cc

    rdf8ba61a r8d182b1  
    2121#include "AST/Print.hpp"          // for print
    2222#include "AST/Vector.hpp"         // for vector
    23 #include "CodeGenerator.h"        // for CodeGenerator
    24 #include "CodeGeneratorNew.hpp"   // for CodeGenerator_new
    25 #include "SynTree/Declaration.h"  // for DeclarationWithType
    26 #include "SynTree/Expression.h"   // for Expression
    27 #include "SynTree/Type.h"         // for PointerType, Type, FunctionType
    28 #include "SynTree/Visitor.h"      // for Visitor
     23#include "CodeGeneratorNew.hpp"   // for CodeGenerator
     24#include "Common/UniqueName.h"    // for UniqueName
    2925
    3026namespace CodeGen {
    31         struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    32                 std::string typeString;
    33                 GenType( const std::string &typeString, const Options &options );
    34 
    35                 void previsit( BaseSyntaxNode * );
    36                 void postvisit( BaseSyntaxNode * );
    37 
    38                 void postvisit( FunctionType * funcType );
    39                 void postvisit( VoidType * voidType );
    40                 void postvisit( BasicType * basicType );
    41                 void postvisit( PointerType * pointerType );
    42                 void postvisit( ArrayType * arrayType );
    43                 void postvisit( ReferenceType * refType );
    44                 void postvisit( StructInstType * structInst );
    45                 void postvisit( UnionInstType * unionInst );
    46                 void postvisit( EnumInstType * enumInst );
    47                 void postvisit( TypeInstType * typeInst );
    48                 void postvisit( TupleType  * tupleType );
    49                 void postvisit( VarArgsType * varArgsType );
    50                 void postvisit( ZeroType * zeroType );
    51                 void postvisit( OneType * oneType );
    52                 void postvisit( GlobalScopeType * globalType );
    53                 void postvisit( TraitInstType * inst );
    54                 void postvisit( TypeofType * typeof );
    55                 void postvisit( VTableType * vtable );
    56                 void postvisit( QualifiedType * qualType );
    57 
    58           private:
    59                 void handleQualifiers( Type *type );
    60                 std::string handleGeneric( ReferenceToType * refType );
    61                 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    62 
    63                 Options options;
    64         };
    65 
    66         std::string genType( Type *type, const std::string &baseString, const Options &options ) {
    67                 PassVisitor<GenType> gt( baseString, options );
    68                 std::ostringstream os;
    69 
    70                 if ( ! type->get_attributes().empty() ) {
    71                         PassVisitor<CodeGenerator> cg( os, options );
    72                         cg.pass.genAttributes( type->get_attributes() );
    73                 } // if
    74 
    75                 type->accept( gt );
    76                 return os.str() + gt.pass.typeString;
    77         }
    78 
    79         std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
    80                 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );
    81         }
    82 
    83         std::string genPrettyType( Type * type, const std::string & baseString ) {
    84                 return genType( type, baseString, true, false );
    85         }
    86 
    87         GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}
    88 
    89         // *** BaseSyntaxNode
    90         void GenType::previsit( BaseSyntaxNode * ) {
    91                 // turn off automatic recursion for all nodes, to allow each visitor to
    92                 // precisely control the order in which its children are visited.
    93                 visit_children = false;
    94         }
    95 
    96         void GenType::postvisit( BaseSyntaxNode * node ) {
    97                 std::stringstream ss;
    98                 node->print( ss );
    99                 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
    100         }
    101 
    102         void GenType::postvisit( VoidType * voidType ) {
    103                 typeString = "void " + typeString;
    104                 handleQualifiers( voidType );
    105         }
    106 
    107         void GenType::postvisit( BasicType * basicType ) {
    108                 BasicType::Kind kind = basicType->kind;
    109                 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
    110                 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
    111                 handleQualifiers( basicType );
    112         }
    113 
    114         void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {
    115                 std::ostringstream os;
    116                 if ( typeString != "" ) {
    117                         if ( typeString[ 0 ] == '*' ) {
    118                                 os << "(" << typeString << ")";
    119                         } else {
    120                                 os << typeString;
    121                         } // if
    122                 } // if
    123                 os << "[";
    124 
    125                 if ( isStatic ) {
    126                         os << "static ";
    127                 } // if
    128                 if ( qualifiers.is_const ) {
    129                         os << "const ";
    130                 } // if
    131                 if ( qualifiers.is_volatile ) {
    132                         os << "volatile ";
    133                 } // if
    134                 if ( qualifiers.is_restrict ) {
    135                         os << "__restrict ";
    136                 } // if
    137                 if ( qualifiers.is_atomic ) {
    138                         os << "_Atomic ";
    139                 } // if
    140                 if ( dimension != 0 ) {
    141                         PassVisitor<CodeGenerator> cg( os, options );
    142                         dimension->accept( cg );
    143                 } else if ( isVarLen ) {
    144                         // no dimension expression on a VLA means it came in with the * token
    145                         os << "*";
    146                 } // if
    147                 os << "]";
    148 
    149                 typeString = os.str();
    150 
    151                 base->accept( *visitor );
    152         }
    153 
    154         void GenType::postvisit( PointerType * pointerType ) {
    155                 assert( pointerType->base != 0);
    156                 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
    157                         genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
    158                 } else {
    159                         handleQualifiers( pointerType );
    160                         if ( typeString[ 0 ] == '?' ) {
    161                                 typeString = "* " + typeString;
    162                         } else {
    163                                 typeString = "*" + typeString;
    164                         } // if
    165                         pointerType->base->accept( *visitor );
    166                 } // if
    167         }
    168 
    169         void GenType::postvisit( ArrayType * arrayType ) {
    170                 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
    171         }
    172 
    173         void GenType::postvisit( ReferenceType * refType ) {
    174                 assert( 0 != refType->base );
    175                 assertf( ! options.genC, "Reference types should not reach code generation." );
    176                 handleQualifiers( refType );
    177                 typeString = "&" + typeString;
    178                 refType->base->accept( *visitor );
    179         }
    180 
    181         void GenType::postvisit( FunctionType * funcType ) {
    182                 std::ostringstream os;
    183 
    184                 if ( typeString != "" ) {
    185                         if ( typeString[ 0 ] == '*' ) {
    186                                 os << "(" << typeString << ")";
    187                         } else {
    188                                 os << typeString;
    189                         } // if
    190                 } // if
    191 
    192                 /************* parameters ***************/
    193 
    194                 const std::list<DeclarationWithType *> &pars = funcType->parameters;
    195 
    196                 if ( pars.empty() ) {
    197                         if ( funcType->get_isVarArgs() ) {
    198                                 os << "()";
    199                         } else {
    200                                 os << "(void)";
    201                         } // if
    202                 } else {
    203                         PassVisitor<CodeGenerator> cg( os, options );
    204                         os << "(" ;
    205 
    206                         cg.pass.genCommaList( pars.begin(), pars.end() );
    207 
    208                         if ( funcType->get_isVarArgs() ) {
    209                                 os << ", ...";
    210                         } // if
    211                         os << ")";
    212                 } // if
    213 
    214                 typeString = os.str();
    215 
    216                 if ( funcType->returnVals.size() == 0 ) {
    217                         typeString = "void " + typeString;
    218                 } else {
    219                         funcType->returnVals.front()->get_type()->accept( *visitor );
    220                 } // if
    221 
    222                 // add forall
    223                 if( ! funcType->forall.empty() && ! options.genC ) {
    224                         // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    225                         std::ostringstream os;
    226                         PassVisitor<CodeGenerator> cg( os, options );
    227                         os << "forall(";
    228                         cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
    229                         os << ")" << std::endl;
    230                         typeString = os.str() + typeString;
    231                 }
    232         }
    233 
    234         std::string GenType::handleGeneric( ReferenceToType * refType ) {
    235                 if ( ! refType->parameters.empty() ) {
    236                         std::ostringstream os;
    237                         PassVisitor<CodeGenerator> cg( os, options );
    238                         os << "(";
    239                         cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
    240                         os << ") ";
    241                         return os.str();
    242                 }
    243                 return "";
    244         }
    245 
    246         void GenType::postvisit( StructInstType * structInst )  {
    247                 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
    248                 if ( options.genC ) typeString = "struct " + typeString;
    249                 handleQualifiers( structInst );
    250         }
    251 
    252         void GenType::postvisit( UnionInstType * unionInst ) {
    253                 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    254                 if ( options.genC ) typeString = "union " + typeString;
    255                 handleQualifiers( unionInst );
    256         }
    257 
    258         void GenType::postvisit( EnumInstType * enumInst ) {
    259                 if ( enumInst->baseEnum && enumInst->baseEnum->base ) {
    260                         typeString = genType(enumInst->baseEnum->base, typeString, options);
    261                 } else {
    262                         typeString = enumInst->name + " " + typeString;
    263                         if ( options.genC ) {
    264                                 typeString = "enum " + typeString;
    265                         }
    266                 }
    267                 handleQualifiers( enumInst );
    268         }
    269 
    270         void GenType::postvisit( TypeInstType * typeInst ) {
    271                 assertf( ! options.genC, "Type instance types should not reach code generation." );
    272                 typeString = typeInst->name + " " + typeString;
    273                 handleQualifiers( typeInst );
    274         }
    275 
    276         void GenType::postvisit( TupleType * tupleType ) {
    277                 assertf( ! options.genC, "Tuple types should not reach code generation." );
    278                 unsigned int i = 0;
    279                 std::ostringstream os;
    280                 os << "[";
    281                 for ( Type * t : *tupleType ) {
    282                         i++;
    283                         os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");
    284                 }
    285                 os << "] ";
    286                 typeString = os.str() + typeString;
    287         }
    288 
    289         void GenType::postvisit( VarArgsType * varArgsType ) {
    290                 typeString = "__builtin_va_list " + typeString;
    291                 handleQualifiers( varArgsType );
    292         }
    293 
    294         void GenType::postvisit( ZeroType * zeroType ) {
    295                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    296                 typeString = (options.pretty ? "zero_t " : "long int ") + typeString;
    297                 handleQualifiers( zeroType );
    298         }
    299 
    300         void GenType::postvisit( OneType * oneType ) {
    301                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    302                 typeString = (options.pretty ? "one_t " : "long int ") + typeString;
    303                 handleQualifiers( oneType );
    304         }
    305 
    306         void GenType::postvisit( GlobalScopeType * globalType ) {
    307                 assertf( ! options.genC, "Global scope type should not reach code generation." );
    308                 handleQualifiers( globalType );
    309         }
    310 
    311         void GenType::postvisit( TraitInstType * inst ) {
    312                 assertf( ! options.genC, "Trait types should not reach code generation." );
    313                 typeString = inst->name + " " + typeString;
    314                 handleQualifiers( inst );
    315         }
    316 
    317         void GenType::postvisit( TypeofType * typeof ) {
    318                 std::ostringstream os;
    319                 PassVisitor<CodeGenerator> cg( os, options );
    320                 os << "typeof(";
    321                 typeof->expr->accept( cg );
    322                 os << ") " << typeString;
    323                 typeString = os.str();
    324                 handleQualifiers( typeof );
    325         }
    326 
    327         void GenType::postvisit( VTableType * vtable ) {
    328                 assertf( ! options.genC, "Virtual table types should not reach code generation." );
    329                 std::ostringstream os;
    330                 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;
    331                 typeString = os.str();
    332                 handleQualifiers( vtable );
    333         }
    334 
    335         void GenType::postvisit( QualifiedType * qualType ) {
    336                 assertf( ! options.genC, "Qualified types should not reach code generation." );
    337                 std::ostringstream os;
    338                 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;
    339                 typeString = os.str();
    340                 handleQualifiers( qualType );
    341         }
    342 
    343         void GenType::handleQualifiers( Type * type ) {
    344                 if ( type->get_const() ) {
    345                         typeString = "const " + typeString;
    346                 } // if
    347                 if ( type->get_volatile() ) {
    348                         typeString = "volatile " + typeString;
    349                 } // if
    350                 if ( type->get_restrict() ) {
    351                         typeString = "__restrict " + typeString;
    352                 } // if
    353                 if ( type->get_atomic() ) {
    354                         typeString = "_Atomic " + typeString;
    355                 } // if
    356         }
    35727
    35828namespace {
    35929
    360 #warning Remove the _new when old version is removed.
    361 struct GenType_new :
     30struct GenType final :
    36231                public ast::WithShortCircuiting,
    363                 public ast::WithVisitorRef<GenType_new> {
     32                public ast::WithVisitorRef<GenType> {
    36433        std::string result;
    365         GenType_new( const std::string &typeString, const Options &options );
     34        GenType( const std::string &typeString, const Options &options );
    36635
    36736        void previsit( ast::Node const * );
     
    39766};
    39867
    399 GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
    400 
    401 void GenType_new::previsit( ast::Node const * ) {
     68GenType::GenType( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
     69
     70void GenType::previsit( ast::Node const * ) {
    40271        // Turn off automatic recursion for all nodes, to allow each visitor to
    40372        // precisely control the order in which its children are visited.
     
    40574}
    40675
    407 void GenType_new::postvisit( ast::Node const * node ) {
     76void GenType::postvisit( ast::Node const * node ) {
    40877        std::stringstream ss;
    40978        ast::print( ss, node );
     
    41180}
    41281
    413 void GenType_new::postvisit( ast::VoidType const * type ) {
     82void GenType::postvisit( ast::VoidType const * type ) {
    41483        result = "void " + result;
    41584        handleQualifiers( type );
    41685}
    41786
    418 void GenType_new::postvisit( ast::BasicType const * type ) {
     87void GenType::postvisit( ast::BasicType const * type ) {
    41988        ast::BasicType::Kind kind = type->kind;
    42089        assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES );
     
    42392}
    42493
    425 void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {
     94void GenType::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {
    42695        std::ostringstream os;
    42796        if ( result != "" ) {
     
    449118        }
    450119        if ( dimension != 0 ) {
    451                 ast::Pass<CodeGenerator_new>::read( dimension, os, options );
     120                ast::Pass<CodeGenerator>::read( dimension, os, options );
    452121        } else if ( isVarLen ) {
    453122                // no dimension expression on a VLA means it came in with the * token
     
    461130}
    462131
    463 void GenType_new::postvisit( ast::PointerType const * type ) {
     132void GenType::postvisit( ast::PointerType const * type ) {
    464133        if ( type->isStatic || type->isVarLen || type->dimension ) {
    465134                genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
     
    475144}
    476145
    477 void GenType_new::postvisit( ast::ArrayType const * type ) {
     146void GenType::postvisit( ast::ArrayType const * type ) {
    478147        genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
    479148}
    480149
    481 void GenType_new::postvisit( ast::ReferenceType const * type ) {
     150void GenType::postvisit( ast::ReferenceType const * type ) {
    482151        assertf( !options.genC, "Reference types should not reach code generation." );
    483152        handleQualifiers( type );
     
    486155}
    487156
    488 void GenType_new::postvisit( ast::FunctionType const * type ) {
     157void GenType::postvisit( ast::FunctionType const * type ) {
    489158        std::ostringstream os;
    490159
     
    526195                //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." );
    527196                std::ostringstream os;
    528                 ast::Pass<CodeGenerator_new> cg( os, options );
     197                ast::Pass<CodeGenerator> cg( os, options );
    529198                os << "forall(";
    530199                cg.core.genCommaList( type->forall );
     
    534203}
    535204
    536 std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) {
     205std::string GenType::handleGeneric( ast::BaseInstType const * type ) {
    537206        if ( !type->params.empty() ) {
    538207                std::ostringstream os;
    539                 ast::Pass<CodeGenerator_new> cg( os, options );
     208                ast::Pass<CodeGenerator> cg( os, options );
    540209                os << "(";
    541210                cg.core.genCommaList( type->params );
     
    546215}
    547216
    548 void GenType_new::postvisit( ast::StructInstType const * type )  {
     217void GenType::postvisit( ast::StructInstType const * type )  {
    549218        result = type->name + handleGeneric( type ) + " " + result;
    550219        if ( options.genC ) result = "struct " + result;
     
    552221}
    553222
    554 void GenType_new::postvisit( ast::UnionInstType const * type ) {
     223void GenType::postvisit( ast::UnionInstType const * type ) {
    555224        result = type->name + handleGeneric( type ) + " " + result;
    556225        if ( options.genC ) result = "union " + result;
     
    558227}
    559228
    560 void GenType_new::postvisit( ast::EnumInstType const * type ) {
     229void GenType::postvisit( ast::EnumInstType const * type ) {
    561230        if ( type->base && type->base->base ) {
    562231                result = genType( type->base->base, result, options );
     
    570239}
    571240
    572 void GenType_new::postvisit( ast::TypeInstType const * type ) {
     241void GenType::postvisit( ast::TypeInstType const * type ) {
    573242        assertf( !options.genC, "TypeInstType should not reach code generation." );
    574243        result = type->name + " " + result;
     
    576245}
    577246
    578 void GenType_new::postvisit( ast::TupleType const * type ) {
     247void GenType::postvisit( ast::TupleType const * type ) {
    579248        assertf( !options.genC, "TupleType should not reach code generation." );
    580249        unsigned int i = 0;
     
    589258}
    590259
    591 void GenType_new::postvisit( ast::VarArgsType const * type ) {
     260void GenType::postvisit( ast::VarArgsType const * type ) {
    592261        result = "__builtin_va_list " + result;
    593262        handleQualifiers( type );
    594263}
    595264
    596 void GenType_new::postvisit( ast::ZeroType const * type ) {
     265void GenType::postvisit( ast::ZeroType const * type ) {
    597266        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
    598267        result = (options.pretty ? "zero_t " : "long int ") + result;
     
    600269}
    601270
    602 void GenType_new::postvisit( ast::OneType const * type ) {
     271void GenType::postvisit( ast::OneType const * type ) {
    603272        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
    604273        result = (options.pretty ? "one_t " : "long int ") + result;
     
    606275}
    607276
    608 void GenType_new::postvisit( ast::GlobalScopeType const * type ) {
     277void GenType::postvisit( ast::GlobalScopeType const * type ) {
    609278        assertf( !options.genC, "GlobalScopeType should not reach code generation." );
    610279        handleQualifiers( type );
    611280}
    612281
    613 void GenType_new::postvisit( ast::TraitInstType const * type ) {
     282void GenType::postvisit( ast::TraitInstType const * type ) {
    614283        assertf( !options.genC, "TraitInstType should not reach code generation." );
    615284        result = type->name + " " + result;
     
    617286}
    618287
    619 void GenType_new::postvisit( ast::TypeofType const * type ) {
     288void GenType::postvisit( ast::TypeofType const * type ) {
    620289        std::ostringstream os;
    621290        os << "typeof(";
    622         ast::Pass<CodeGenerator_new>::read( type, os, options );
     291        ast::Pass<CodeGenerator>::read( type, os, options );
    623292        os << ") " << result;
    624293        result = os.str();
     
    626295}
    627296
    628 void GenType_new::postvisit( ast::VTableType const * type ) {
     297void GenType::postvisit( ast::VTableType const * type ) {
    629298        assertf( !options.genC, "Virtual table types should not reach code generation." );
    630299        std::ostringstream os;
     
    634303}
    635304
    636 void GenType_new::postvisit( ast::QualifiedType const * type ) {
     305void GenType::postvisit( ast::QualifiedType const * type ) {
    637306        assertf( !options.genC, "QualifiedType should not reach code generation." );
    638307        std::ostringstream os;
     
    642311}
    643312
    644 void GenType_new::handleQualifiers( ast::Type const * type ) {
     313void GenType::handleQualifiers( ast::Type const * type ) {
    645314        if ( type->is_const() ) {
    646315                result = "const " + result;
     
    657326}
    658327
    659 std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) {
     328std::string GenType::genParamList( const ast::vector<ast::Type> & range ) {
    660329        auto cur = range.begin();
    661330        auto end = range.end();
    662331        if ( cur == end ) return "";
    663332        std::ostringstream oss;
    664         for ( unsigned int i = 0 ; ; ++i ) {
    665                 oss << genType( *cur++, "__param_" + std::to_string(i), options );
     333        UniqueName param( "__param_" );
     334        while ( true ) {
     335                oss << genType( *cur++, options.genC ? param.newName() : "", options );
    666336                if ( cur == end ) break;
    667337                oss << ", ";
     
    675345        std::ostringstream os;
    676346        if ( !type->attributes.empty() ) {
    677                 ast::Pass<CodeGenerator_new> cg( os, options );
     347                ast::Pass<CodeGenerator> cg( os, options );
    678348                cg.core.genAttributes( type->attributes );
    679349        }
    680350
    681         return os.str() + ast::Pass<GenType_new>::read( type, base, options );
     351        return os.str() + ast::Pass<GenType>::read( type, base, options );
    682352}
    683353
    684354std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) {
    685         return ast::Pass<GenType_new>::read( type, base, options );
     355        return ast::Pass<GenType>::read( type, base, options );
    686356}
    687357
  • src/CodeGen/Generate.cc

    rdf8ba61a r8d182b1  
    1919#include <string>                    // for operator<<
    2020
    21 #include "CodeGeneratorNew.hpp"      // for CodeGenerator_new, doSemicolon, ...
    22 #include "CodeGenerator.h"           // for CodeGenerator, doSemicolon, oper...
     21#include "CodeGeneratorNew.hpp"      // for CodeGenerator, doSemicolon, ...
    2322#include "GenType.h"                 // for genPrettyType
    24 #include "Common/PassVisitor.h"      // for PassVisitor
    25 #include "SynTree/LinkageSpec.h"     // for isBuiltin, isGeneratable
    26 #include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
    27 #include "SynTree/Declaration.h"     // for Declaration
    28 #include "SynTree/Type.h"            // for Type
    2923
    3024using namespace std;
    3125
    3226namespace CodeGen {
    33         namespace {
    34                 /// Removes misc. nodes that should not exist in CodeGen
    35                 struct TreeCleaner {
    36                         void premutate( CompoundStmt * stmt );
    37                         Statement * postmutate( ImplicitCtorDtorStmt * stmt );
    38 
    39                         static bool shouldClean( Declaration * );
    40                 };
    41 
    42                 void cleanTree( std::list< Declaration * > & translationUnit ) {
    43                         PassVisitor<TreeCleaner> cleaner;
    44                         filter( translationUnit, [](Declaration * decl) { return TreeCleaner::shouldClean(decl); }, false );
    45                         mutateAll( translationUnit, cleaner );
    46                 } // cleanTree
    47         } // namespace
    48 
    49         void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
    50                 cleanTree( translationUnit );
    51 
    52                 PassVisitor<CodeGenerator> cgv( os, pretty, generateC, lineMarks, printExprTypes );
    53                 for ( auto & dcl : translationUnit ) {
    54                         if ( LinkageSpec::isGeneratable( dcl->get_linkage() ) && (doIntrinsics || ! LinkageSpec::isBuiltin( dcl->get_linkage() ) ) ) {
    55                                 cgv.pass.updateLocation( dcl );
    56                                 dcl->accept(cgv);
    57                                 if ( doSemicolon( dcl ) ) {
    58                                         os << ";";
    59                                 } // if
    60                                 os << cgv.pass.endl;
    61                         } // if
    62                 } // for
    63         }
    64 
    65         void generate( BaseSyntaxNode * node, std::ostream & os ) {
    66                 if ( Type * type = dynamic_cast< Type * >( node ) ) {
    67                         os << genPrettyType( type, "" );
    68                 } else {
    69                         PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
    70                         node->accept( cgv );
    71                 }
    72                 os << std::endl;
    73         }
    74 
    75         namespace {
    76                 void TreeCleaner::premutate( CompoundStmt * cstmt ) {
    77                         filter( cstmt->kids, [](Statement * stmt) {
    78                                 if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( stmt ) ) {
    79                                         return shouldClean( declStmt->decl );
    80                                 }
    81                                 return false;
    82                         }, false );
    83                 }
    84 
    85                 Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) {
    86                         Statement * callStmt = nullptr;
    87                         std::swap( stmt->callStmt, callStmt );
    88                         delete stmt;
    89                         return callStmt;
    90                 }
    91 
    92                 bool TreeCleaner::shouldClean( Declaration * decl ) {
    93                         return dynamic_cast< TraitDecl * >( decl );
    94                 }
    95         } // namespace
    9627
    9728namespace {
     
    10132
    10233        /// Removes various nodes that should not exist in CodeGen.
    103         struct TreeCleaner_new {
     34        struct TreeCleaner final {
    10435                ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) {
    10536                        auto mutStmt = ast::mutate( stmt );
     
    12051                bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
    12152        erase_if( translationUnit.decls, shouldClean );
    122         ast::Pass<TreeCleaner_new>::run( translationUnit );
     53        ast::Pass<TreeCleaner>::run( translationUnit );
    12354
    124         ast::Pass<CodeGenerator_new> cgv( os,
     55        ast::Pass<CodeGenerator> cgv( os,
    12556                        Options( pretty, generateC, lineMarks, printExprTypes ) );
    12657        for ( auto & decl : translationUnit.decls ) {
  • src/CodeGen/Generate.h

    rdf8ba61a r8d182b1  
    1717
    1818#include <iostream>  // for ostream
    19 #include <list>      // for list
    20 
    21 class BaseSyntaxNode;
    22 class Declaration;
    2319
    2420namespace ast {
     
    2723
    2824namespace CodeGen {
    29         /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.)
    30         void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false , bool lineMarks = false, bool printTypeExpr = false );
    31 
    32         /// Generate code for a single node -- helpful for debugging in gdb
    33         void generate( BaseSyntaxNode * node, std::ostream & os );
    3425
    3526/// Generates all code in transUnit and writing it to the os.
  • src/CodeGen/LinkOnce.cc

    rdf8ba61a r8d182b1  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
    24 #include "Common/PassVisitor.h"       // for PassVisitor, WithShortCircuiting
    2524
    2625namespace CodeGen {
    2726
    2827namespace {
    29 
    30 bool is_cfa_linkonce_old( Attribute const * attr ) {
    31         return std::string("cfa_linkonce") == attr->name;
    32 }
    33 
    34 bool is_section_attribute_old( Attribute const * attr ) {
    35         return std::string("section") == attr->name;
    36 }
    37 
    38 class LinkOnceVisitorCore : public WithShortCircuiting {
    39 public:
    40         void previsit( Declaration * ) {
    41                 visit_children = false;
    42         }
    43 
    44         void previsit( DeclarationWithType * decl ) {
    45                 std::list< Attribute * > & attributes = decl->attributes;
    46                 // See if we can find the element:
    47                 auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old );
    48                 if ( attributes.end() != found ) {
    49                         // Remove any other sections:
    50                         attributes.remove_if( is_section_attribute_old );
    51                         // Iterator to the cfa_linkonce attribute should still be valid.
    52                         Attribute * attribute = *found;
    53                         assert( attribute->parameters.empty() );
    54                         assert( !decl->mangleName.empty() );
    55                         // Overwrite the attribute in place.
    56                         const std::string section_name = ".gnu.linkonce." + decl->mangleName;
    57                         attribute->name = "section";
    58                         attribute->parameters.push_back(
    59                                 new ConstantExpr( Constant::from_string( section_name ) )
    60                         );
    61 
    62                         // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce
    63                         // visibility is a mess otherwise
    64                         attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));
    65 
    66                 }
    67                 visit_children = false;
    68         }
    69 };
    7028
    7129bool is_cfa_linkonce( ast::Attribute const * attr ) {
     
    12280} // namespace
    12381
    124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {
    125         PassVisitor<LinkOnceVisitorCore> translator;
    126         acceptAll( translationUnit, translator );
    127 }
    128 
    12982void translateLinkOnce( ast::TranslationUnit & translationUnit ) {
    13083        ast::Pass<LinkOnceCore>::run( translationUnit );
  • src/CodeGen/LinkOnce.h

    rdf8ba61a r8d182b1  
    2020// for now its almost the only attribute we handle.
    2121
    22 #include <list>  // for list
    2322
    24 class Declaration;
    2523namespace ast {
    2624        class TranslationUnit;
     
    2927namespace CodeGen {
    3028
    31 void translateLinkOnce( std::list< Declaration *> & translationUnit );
    3229void translateLinkOnce( ast::TranslationUnit & translationUnit );
    3330/* Convert the cfa_linkonce attribute on top level declaration into
  • src/CodeGen/module.mk

    rdf8ba61a r8d182b1  
    1616
    1717SRC_CODEGEN = \
    18         CodeGen/FixMain2.cc \
    19         CodeGen/FixMain.h \
     18        CodeGen/CodeGeneratorNew.cpp \
     19        CodeGen/CodeGeneratorNew.hpp \
     20        CodeGen/GenType.cc \
     21        CodeGen/GenType.h \
    2022        CodeGen/OperatorTable.cc \
    2123        CodeGen/OperatorTable.h
    2224
    2325SRC += $(SRC_CODEGEN) \
    24         CodeGen/CodeGenerator.cc \
    25         CodeGen/CodeGenerator.h \
    26         CodeGen/CodeGeneratorNew.cpp \
    27         CodeGen/CodeGeneratorNew.hpp \
    2826        CodeGen/Generate.cc \
    2927        CodeGen/Generate.h \
    3028        CodeGen/FixMain.cc \
     29        CodeGen/FixMain.h \
    3130        CodeGen/FixNames.cc \
    3231        CodeGen/FixNames.h \
    33         CodeGen/GenType.cc \
    34         CodeGen/GenType.h \
    3532        CodeGen/LinkOnce.cc \
    3633        CodeGen/LinkOnce.h \
  • src/Common/Eval.cc

    rdf8ba61a r8d182b1  
    1919
    2020#include "AST/Inspect.hpp"
    21 #include "Common/PassVisitor.h"
    2221#include "CodeGen/OperatorTable.h"                                              // access: OperatorInfo
    2322#include "AST/Pass.hpp"
    2423#include "InitTweak/InitTweak.h"
    25 #include "SynTree/Expression.h"
    26 
    27 //-------------------------------------------------------------
    28 // Old AST
    29 struct EvalOld : public WithShortCircuiting {
    30         long long int value = 0;                                                        // compose the result of the constant expression
    31         bool valid = true;                                                                      // true => constant expression and value is the result
    32                                                                                                                 // false => not constant expression, e.g., ++i
    33         bool cfavalid = true;                                                           // true => constant expression and value computable
    34                                                                                                                 // false => constant expression but value not computable, e.g., sizeof(int)
    35 
    36         void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    37         void postvisit( const BaseSyntaxNode * ) { valid = false; }
    38 
    39         void postvisit( const SizeofExpr * ) {
    40         }
    41 
    42         void postvisit( const ConstantExpr * expr ) {
    43                 value = expr->intValue();
    44         }
    45 
    46         void postvisit( const CastExpr * expr ) {
    47                 auto arg = eval(expr->arg);
    48                 valid = arg.second;
    49                 value = arg.first;
    50                 // TODO: perform type conversion on value if valid
    51         }
    52 
    53         void postvisit( const VariableExpr * const expr ) {
    54                 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) {
    55                         if ( EnumDecl * decl = inst->baseEnum ) {
    56                                 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
    57                                         return;
    58                                 }
    59                         }
    60                 }
    61                 valid = false;
    62         }
    63 
    64         void postvisit( const ApplicationExpr * expr ) {
    65                 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr));
    66                 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; }
    67                 const std::string & fname = function->name;
    68                 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
    69                 std::pair<long long int, bool> arg1, arg2;
    70                 arg1 = eval(expr->args.front());
    71                 valid = valid && arg1.second;
    72                 if ( ! valid ) return;
    73                 if ( expr->args.size() == 2 ) {
    74                         arg2 = eval(expr->args.back());
    75                         valid = valid && arg2.second;
    76                         if ( ! valid ) return;
    77                 }
    78                 if (fname == "?+?") {
    79                         value = arg1.first + arg2.first;
    80                 } else if (fname == "?-?") {
    81                         value = arg1.first - arg2.first;
    82                 } else if (fname == "?*?") {
    83                         value = arg1.first * arg2.first;
    84                 } else if (fname == "?/?") {
    85                         value = arg1.first / arg2.first;
    86                 } else if (fname == "?%?") {
    87                         value = arg1.first % arg2.first;
    88                 } else {
    89                         valid = false;
    90                 }
    91                 // TODO: implement other intrinsic functions
    92         }
    93 };
    94 
    95 //-------------------------------------------------------------
    96 // New AST
     24
    9725struct EvalNew : public ast::WithShortCircuiting {
    9826        Evaluation result = { 0, true, true };
     
    270198};
    271199
    272 std::pair<long long int, bool> eval( const Expression * expr ) {
    273         PassVisitor<EvalOld> ev;
    274         if ( expr ) {
    275                 expr->accept( ev );
    276                 return std::make_pair( ev.pass.value, ev.pass.valid );
    277         } else {
    278                 return std::make_pair( 0, false );
    279         }
    280 }
    281 
    282200Evaluation eval( const ast::Expr * expr ) {
    283201        if ( expr ) {
  • src/Common/Eval.h

    rdf8ba61a r8d182b1  
    3030
    3131/// Evaluates expr as a long long int.
    32 /// If second is false, expr could not be evaluated.
    33 std::pair<long long int, bool> eval(const Expression * expr);
    3432Evaluation eval(const ast::Expr * expr);
    3533
  • src/Common/Examine.cc

    rdf8ba61a r8d182b1  
    1919#include "CodeGen/OperatorTable.h"
    2020#include "InitTweak/InitTweak.h"
    21 
    22 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {
    23         if (func->name != "main") return nullptr;
    24         if (func->type->parameters.size() != 1) return nullptr;
    25 
    26         auto param = func->type->parameters.front();
    27 
    28         auto type = dynamic_cast<ReferenceType * >(param->get_type());
    29         if (!type) return nullptr;
    30 
    31         auto obj = dynamic_cast<StructInstType *>(type->base);
    32         if (!obj) return nullptr;
    33 
    34         if (kind != obj->baseStruct->kind) return nullptr;
    35 
    36         return param;
    37 }
    3821
    3922namespace {
     
    6952
    7053namespace {
    71         Type * getDestructorParam( FunctionDecl * func ) {
    72                 if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
    73 
    74                 auto params = func->type->parameters;
    75                 if ( 1 != params.size() ) return nullptr;
    76 
    77                 auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() );
    78                 if ( ref ) {
    79                         return ref->base;
    80                 }
    81                 return nullptr;
    82         }
    8354
    8455const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
     
    8859}
    8960
    90 }
    91 
    92 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) {
    93         if ( Type * type = getDestructorParam( func ) ) {
    94                 auto stype = dynamic_cast<StructInstType *>( type );
    95                 return stype && stype->baseStruct == type_decl;
    96         }
    97         return false;
    9861}
    9962
  • src/Common/Examine.h

    rdf8ba61a r8d182b1  
    1515
    1616#include "AST/Decl.hpp"
    17 #include "SynTree/Declaration.h"
    1817
    1918/// Check if this is a main function for a type of an aggregate kind.
    20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );
    2119const ast::DeclWithType * isMainFor(
    2220        const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
     
    2422
    2523/// Check if this function is a destructor for the given structure.
    26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );
    2724bool isDestructorFor(
    2825        const ast::FunctionDecl * func, const ast::StructDecl * type );
  • src/Common/UniqueName.cc

    rdf8ba61a r8d182b1  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // UniqueName.cc --
     7// UniqueName.cc -- Create a unique variants of a base name with a counter.
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jun  8 14:47:49 2015
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Nov  7 15:04:00 2023
     13// Update Count     : 4
    1414//
    1515
    16 #include <string>
    17 #include <sstream>
     16#include "UniqueName.h"
    1817
    19 #include "UniqueName.h"
     18#include "Common/ToString.hpp"
    2019
    2120UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) {
     
    2322
    2423std::string UniqueName::newName( const std::string &additional ) {
    25         std::ostringstream os;
    26         os << base << additional << count++;
    27         return os.str();
     24        return toString( base, additional, count++ );
    2825}
    2926
  • src/Common/UniqueName.h

    rdf8ba61a r8d182b1  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // UniqueName.h --
     7// UniqueName.h -- Create a unique variants of a base name with a counter.
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 22:18:45 2017
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Nov  7 15:00:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    1919
    2020class UniqueName {
    21   public:
    22         UniqueName( const std::string &base = "" );
     21public:
     22        UniqueName( const std::string &base );
    2323        std::string newName( const std::string &additional = "" );
    24   private:
     24private:
    2525        std::string base;
    2626        int count;
  • src/Common/module.mk

    rdf8ba61a r8d182b1  
    3131        Common/Indenter.cc \
    3232        Common/Iterate.hpp \
    33         Common/PassVisitor.cc \
    34         Common/PassVisitor.h \
    35         Common/PassVisitor.impl.h \
    36         Common/PassVisitor.proto.h \
    3733        Common/PersistentMap.h \
    3834        Common/ResolvProtoDump.hpp \
  • src/Concurrency/module.mk

    rdf8ba61a r8d182b1  
    2121        Concurrency/Corun.hpp \
    2222        Concurrency/KeywordsNew.cpp \
    23         Concurrency/Keywords.cc \
    2423        Concurrency/Keywords.h \
    2524        Concurrency/WaitforNew.cpp \
    26         Concurrency/Waitfor.cc \
    2725        Concurrency/Waitfor.h \
    2826        Concurrency/Waituntil.cpp \
  • src/ControlStruct/module.mk

    rdf8ba61a r8d182b1  
    1616
    1717SRC += \
    18         ControlStruct/ExceptDecl.cc \
    1918        ControlStruct/ExceptDeclNew.cpp \
    2019        ControlStruct/ExceptDecl.h \
    2120        ControlStruct/ExceptTranslateNew.cpp \
    22         ControlStruct/ExceptTranslate.cc \
    2321        ControlStruct/ExceptTranslate.h \
    2422        ControlStruct/FixLabels.cpp \
    2523        ControlStruct/FixLabels.hpp \
    26         ControlStruct/ForExprMutator.cc \
    27         ControlStruct/ForExprMutator.h \
    2824        ControlStruct/HoistControlDecls.cpp \
    2925        ControlStruct/HoistControlDecls.hpp \
    30         ControlStruct/LabelFixer.cc \
    31         ControlStruct/LabelFixer.h \
    32         ControlStruct/LabelGenerator.cc \
    33         ControlStruct/LabelGenerator.h \
    3426        ControlStruct/LabelGeneratorNew.cpp \
    3527        ControlStruct/LabelGeneratorNew.hpp \
    36         ControlStruct/MLEMutator.cc \
    37         ControlStruct/MLEMutator.h \
    3828        ControlStruct/MultiLevelExit.cpp \
    39         ControlStruct/MultiLevelExit.hpp \
    40         ControlStruct/Mutate.cc \
    41         ControlStruct/Mutate.h
     29        ControlStruct/MultiLevelExit.hpp
    4230
  • src/GenPoly/FindFunction.cc

    rdf8ba61a r8d182b1  
    2020#include "AST/Pass.hpp"                 // for Pass
    2121#include "AST/Type.hpp"
    22 #include "Common/PassVisitor.h"         // for PassVisitor
    2322#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::iterator
    2423#include "GenPoly/GenPoly.h"            // for TyVarMap
    2524#include "ScrubTyVars.h"                // for ScrubTyVars
    26 #include "SynTree/Declaration.h"        // for DeclarationWithType, TypeDecl
    27 #include "SynTree/Mutator.h"            // for Mutator, mutateAll
    28 #include "SynTree/Type.h"               // for FunctionType, Type, Type::For...
    2925
    3026namespace GenPoly {
    31         class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {
    32           public:
    33                 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
    34 
    35                 void premutate( FunctionType * functionType );
    36                 Type * postmutate( FunctionType * functionType );
    37                 void premutate( PointerType * pointerType );
    38           private:
    39                 void handleForall( const Type::ForallList &forall );
    40 
    41                 std::list< FunctionType const * > & functions;
    42                 TyVarMap tyVars;
    43                 bool replaceMode;
    44                 FindFunctionPredicate predicate;
    45         };
    46 
    47         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    48                 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );
    49                 type->acceptMutator( finder );
    50         }
    51 
    52         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    53                 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );
    54                 type = type->acceptMutator( finder );
    55         }
    56 
    57         FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
    58                 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {
    59         }
    60 
    61         void FindFunction::handleForall( const Type::ForallList &forall ) {
    62                 for ( const Declaration * td : forall ) {
    63                         TyVarMap::iterator var = tyVars.find( td->name );
    64                         if ( var != tyVars.end() ) {
    65                                 tyVars.erase( var->first );
    66                         } // if
    67                 } // for
    68         }
    69 
    70         void FindFunction::premutate( FunctionType * functionType ) {
    71                 visit_children = false;
    72                 GuardScope( tyVars );
    73                 handleForall( functionType->get_forall() );
    74                 mutateAll( functionType->get_returnVals(), *visitor );
    75         }
    76 
    77         Type * FindFunction::postmutate( FunctionType * functionType ) {
    78                 Type *ret = functionType;
    79                 if ( predicate( functionType, tyVars ) ) {
    80                         functions.push_back( functionType );
    81                         if ( replaceMode ) {
    82                                 // replace type parameters in function type with void*
    83                                 ret = ScrubTyVars::scrub( functionType->clone(), tyVars );
    84                         } // if
    85                 } // if
    86                 return ret;
    87         }
    88 
    89         void FindFunction::premutate( PointerType * pointerType ) {
    90                 GuardScope( tyVars );
    91                 handleForall( pointerType->get_forall() );
    92         }
    9327
    9428namespace {
     
    15488void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) {
    15589        GuardScope( typeVars );
    156         //handleForall( type->forall );
    15790}
    15891
     
    16497        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false );
    16598        type->accept( pass );
    166         //(void)type;
    167         //(void)functions;
    168         //(void)typeVars;
    169         //(void)predicate;
    17099}
    171100
     
    175104        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true );
    176105        return type->accept( pass );
    177         //(void)functions;
    178         //(void)typeVars;
    179         //(void)predicate;
    180         //return type;
    181106}
    182107
  • src/GenPoly/FindFunction.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 #include <list>       // for list
    19 
    2018#include "GenPoly.h"  // for TyVarMap
    2119
    22 class FunctionType;
    23 class Type;
    24 
    2520namespace GenPoly {
    26         typedef bool (*FindFunctionPredicate)( FunctionType*, const TyVarMap& );
    27 
    28         /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`
    29         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    30         /// like `findFunction`, but also replaces the function type with void ()(void)
    31         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3221
    3322typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & );
  • src/GenPoly/GenPoly.cc

    rdf8ba61a r8d182b1  
    2929#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
    3030#include "ResolvExpr/typeops.h"         // for flatten
    31 #include "SynTree/Constant.h"           // for Constant
    32 #include "SynTree/Expression.h"         // for Expression, TypeExpr, Constan...
    33 #include "SynTree/Type.h"               // for Type, StructInstType, UnionIn...
    34 #include "SynTree/TypeSubstitution.h"   // for TypeSubstitution
    3531
    3632using namespace std;
     
    3935        namespace {
    4036                /// Checks a parameter list for polymorphic parameters; will substitute according to env if present
    41                 bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
    42                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    43                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    44                                 assertf(paramType, "Aggregate parameters should be type expressions");
    45                                 if ( isPolyType( paramType->get_type(), env ) ) return true;
    46                         }
    47                         return false;
    48                 }
    49 
    5037                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) {
    5138                        for ( auto &param : params ) {
     
    5845
    5946                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    60                 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    61                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    62                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    63                                 assertf(paramType, "Aggregate parameters should be type expressions");
    64                                 if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true;
    65                         }
    66                         return false;
    67                 }
    68 
    6947                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) {
    7048                        for ( auto & param : params ) {
     
    7755
    7856                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    79                 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    80                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    81                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    82                                 assertf(paramType, "Aggregate parameters should be type expressions");
    83                                 if ( isDynType( paramType->get_type(), tyVars, env ) ) return true;
    84                         }
    85                         return false;
    86                 }
    87 
    8857                bool hasDynParams(
    8958                                const std::vector<ast::ptr<ast::Expr>> & params,
     
    9968                        return false;
    10069                }
    101 
    102                 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present
    103                 bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
    104                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    105                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    106                                 assertf(paramType, "Aggregate parameters should be type expressions");
    107                                 if ( includesPolyType( paramType->get_type(), env ) ) return true;
    108                         }
    109                         return false;
    110                 }
    111 
    112                 /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present
    113                 bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    114                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    115                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    116                                 assertf(paramType, "Aggregate parameters should be type expressions");
    117                                 if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true;
    118                         }
    119                         return false;
    120                 }
    121         }
    122 
    123         Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) {
    124                 if ( ! env ) return type;
    125                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
    126                         Type *newType = env->lookup( typeInst->get_name() );
    127                         if ( newType ) return newType;
    128                 }
    129                 return type;
    130         }
    131 
    132         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {
    133                 if ( ! env ) return type;
    134                 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {
    135                         Type *newType = env->lookup( typeInst->get_name() );
    136                         if ( newType ) return newType;
    137                 }
    138                 return type;
    13970        }
    14071
     
    14677                }
    14778                return type;
    148         }
    149 
    150         Type *isPolyType( Type *type, const TypeSubstitution *env ) {
    151                 type = replaceTypeInst( type, env );
    152 
    153                 if ( dynamic_cast< TypeInstType * >( type ) ) {
    154                         return type;
    155                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    156                         return isPolyType( arrayType->base, env );
    157                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    158                         if ( hasPolyParams( structType->get_parameters(), env ) ) return type;
    159                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    160                         if ( hasPolyParams( unionType->get_parameters(), env ) ) return type;
    161                 }
    162                 return 0;
    16379        }
    16480
     
    17894        }
    17995
    180         Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    181                 type = replaceTypeInst( type, env );
    182 
    183                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    184                         if ( tyVars.contains( typeInst->get_name() ) ) {
    185                                 return type;
    186                         }
    187                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    188                         return isPolyType( arrayType->base, tyVars, env );
    189                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    190                         if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type;
    191                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    192                         if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type;
    193                 }
    194                 return 0;
    195         }
    196 
    19796const ast::Type * isPolyType( const ast::Type * type,
    19897                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    211110}
    212111
    213         ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    214                 type = replaceTypeInst( type, env );
    215 
    216                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    217                         auto var = tyVars.find( typeInst->get_name() );
    218                         if ( var != tyVars.end() && var->second.isComplete ) {
    219                                 return typeInst;
    220                         }
    221                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    222                         if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType;
    223                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    224                         if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType;
    225                 }
    226                 return 0;
    227         }
    228 
    229112const ast::BaseInstType * isDynType(
    230113                const ast::Type * type, const TypeVarMap & typeVars,
     
    249132}
    250133
    251         ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {
    252                 if ( function->get_returnVals().empty() ) return 0;
    253 
    254                 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    255         }
    256 
    257134const ast::BaseInstType *isDynRet(
    258135                const ast::FunctionType * type, const TypeVarMap & typeVars ) {
     
    262139}
    263140
    264         ReferenceToType *isDynRet( FunctionType *function ) {
    265                 if ( function->get_returnVals().empty() ) return 0;
    266 
    267                 TyVarMap forallTypes( TypeDecl::Data{} );
    268                 makeTyVarMap( function, forallTypes );
    269                 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    270         }
    271 
    272141const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) {
    273142        if ( func->returns.empty() ) return nullptr;
     
    278147}
    279148
    280         bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {
    281 //              if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
    282 //                      return true;
    283 //              } // if
    284                 if ( isDynRet( adaptee, tyVars ) ) return true;
    285 
    286                 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) {
    287 //                      if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) {
    288                         if ( isDynType( (*innerArg)->get_type(), tyVars ) ) {
    289                                 return true;
    290                         } // if
    291                 } // for
    292                 return false;
    293         }
    294 
    295149bool needsAdapter(
    296150                ast::FunctionType const * adaptee, const TypeVarMap & typeVars ) {
     
    304158        return false;
    305159}
    306 
    307         Type *isPolyPtr( Type *type, const TypeSubstitution *env ) {
    308                 type = replaceTypeInst( type, env );
    309 
    310                 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    311                         return isPolyType( ptr->get_base(), env );
    312                 }
    313                 return 0;
    314         }
    315 
    316         Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    317                 type = replaceTypeInst( type, env );
    318 
    319                 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    320                         return isPolyType( ptr->get_base(), tyVars, env );
    321                 }
    322                 return 0;
    323         }
    324160
    325161const ast::Type * isPolyPtr(
     
    333169        return nullptr;
    334170}
    335 
    336         Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
    337                 int dummy;
    338                 if ( ! levels ) { levels = &dummy; }
    339                 *levels = 0;
    340 
    341                 while ( true ) {
    342                         type = replaceTypeInst( type, env );
    343 
    344                         if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    345                                 type = ptr->get_base();
    346                                 ++(*levels);
    347                         } else break;
    348                 }
    349 
    350                 return isPolyType( type, env );
    351         }
    352 
    353         Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) {
    354                 int dummy;
    355                 if ( ! levels ) { levels = &dummy; }
    356                 *levels = 0;
    357 
    358                 while ( true ) {
    359                         type = replaceTypeInst( type, env );
    360 
    361                         if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    362                                 type = ptr->get_base();
    363                                 ++(*levels);
    364                         } else break;
    365                 }
    366 
    367                 return isPolyType( type, tyVars, env );
    368         }
    369171
    370172ast::Type const * hasPolyBase(
     
    388190}
    389191
    390         bool includesPolyType( Type *type, const TypeSubstitution *env ) {
    391                 type = replaceTypeInst( type, env );
    392 
    393                 if ( dynamic_cast< TypeInstType * >( type ) ) {
    394                         return true;
    395                 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {
    396                         if ( includesPolyType( pointerType->get_base(), env ) ) return true;
    397                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    398                         if ( includesPolyParams( structType->get_parameters(), env ) ) return true;
    399                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    400                         if ( includesPolyParams( unionType->get_parameters(), env ) ) return true;
    401                 }
    402                 return false;
    403         }
    404 
    405         bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    406                 type = replaceTypeInst( type, env );
    407 
    408                 if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) {
    409                         if ( tyVars.contains( typeInstType->get_name() ) ) {
    410                                 return true;
    411                         }
    412                 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {
    413                         if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true;
    414                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    415                         if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true;
    416                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    417                         if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true;
    418                 }
    419                 return false;
    420         }
    421 
    422         FunctionType * getFunctionType( Type *ty ) {
    423                 PointerType *ptrType;
    424                 if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {
    425                         return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise
    426                 } else {
    427                         return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise
    428                 }
    429         }
    430 
    431192        const ast::FunctionType * getFunctionType( const ast::Type * ty ) {
    432193                if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) {
     
    437198        }
    438199
    439         VariableExpr * getBaseVar( Expression *expr, int *levels ) {
    440                 int dummy;
    441                 if ( ! levels ) { levels = &dummy; }
    442                 *levels = 0;
    443 
    444                 while ( true ) {
    445                         if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {
    446                                 return varExpr;
    447                         } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) {
    448                                 expr = memberExpr->get_aggregate();
    449                         } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) {
    450                                 expr = addressExpr->get_arg();
    451                         } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {
    452                                 // look for compiler-inserted dereference operator
    453                                 NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );
    454                                 if ( ! fn || fn->get_name() != std::string("*?") ) return 0;
    455                                 expr = *untypedExpr->begin_args();
    456                         } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) {
    457                                 // copy constructors insert comma exprs, look at second argument which contains the variable
    458                                 expr = commaExpr->get_arg2();
    459                                 continue;
    460                         } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) {
    461                                 int lvl1;
    462                                 int lvl2;
    463                                 VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 );
    464                                 VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 );
    465                                 if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) {
    466                                         *levels = lvl1;
    467                                         return var1;
    468                                 }
    469                                 break;
    470                         } else break;
    471 
    472                         ++(*levels);
    473                 }
    474 
    475                 return 0;
    476         }
    477 
    478200        namespace {
    479201                /// Checks if is a pointer to D
     
    488210                inline D const * as( B const * p ) {
    489211                        return reinterpret_cast<D const *>( p );
    490                 }
    491 
    492                 /// Flattens a declaration list
    493                 template<typename Output>
    494                 void flattenList( list< DeclarationWithType* > src, Output out ) {
    495                         for ( DeclarationWithType* decl : src ) {
    496                                 ResolvExpr::flatten( decl->get_type(), out );
    497                         }
    498                 }
    499 
    500                 /// Flattens a list of types
    501                 template<typename Output>
    502                 void flattenList( list< Type* > src, Output out ) {
    503                         for ( Type* ty : src ) {
    504                                 ResolvExpr::flatten( ty, out );
    505                         }
    506212                }
    507213
     
    515221                }
    516222
    517                 /// Checks if two lists of parameters are equal up to polymorphic substitution.
    518                 bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) {
    519                         if ( aparams.size() != bparams.size() ) return false;
    520 
    521                         for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin();
    522                                         at != aparams.end(); ++at, ++bt ) {
    523                                 TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at);
    524                                 assertf(aparam, "Aggregate parameters should be type expressions");
    525                                 TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt);
    526                                 assertf(bparam, "Aggregate parameters should be type expressions");
    527 
    528                                 // xxx - might need to let VoidType be a wildcard here too; could have some voids
    529                                 // stuffed in for dtype-statics.
    530                                 // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue;
    531                                 if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false;
    532                         }
    533 
    534                         return true;
    535                 }
    536 
    537223                bool paramListsPolyCompatible(
    538224                                std::vector<ast::ptr<ast::Expr>> const & lparams,
     
    559245                        return true;
    560246                }
    561         }
    562 
    563         bool typesPolyCompatible( Type *a, Type *b ) {
    564                 type_index aid{ typeid(*a) };
    565                 // polymorphic types always match
    566                 if ( aid == type_index{typeid(TypeInstType)} ) return true;
    567 
    568                 type_index bid{ typeid(*b) };
    569                 // polymorphic types always match
    570                 if ( bid == type_index{typeid(TypeInstType)} ) return true;
    571 
    572                 // can't match otherwise if different types
    573                 if ( aid != bid ) return false;
    574 
    575                 // recurse through type structure (conditions borrowed from Unify.cc)
    576                 if ( aid == type_index{typeid(BasicType)} ) {
    577                         return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind();
    578                 } else if ( aid == type_index{typeid(PointerType)} ) {
    579                         PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b);
    580 
    581                         // void pointers should match any other pointer type
    582                         return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    583                                 || typesPolyCompatible( ap->get_base(), bp->get_base() );
    584                 } else if ( aid == type_index{typeid(ReferenceType)} ) {
    585                         ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b);
    586                         return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    587                                 || typesPolyCompatible( ap->get_base(), bp->get_base() );
    588                 } else if ( aid == type_index{typeid(ArrayType)} ) {
    589                         ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b);
    590 
    591                         if ( aa->get_isVarLen() ) {
    592                                 if ( ! ba->get_isVarLen() ) return false;
    593                         } else {
    594                                 if ( ba->get_isVarLen() ) return false;
    595 
    596                                 ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() );
    597                                 ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() );
    598                                 if ( ad && bd
    599                                                 && ad->get_constant()->get_value() != bd->get_constant()->get_value() )
    600                                         return false;
    601                         }
    602 
    603                         return typesPolyCompatible( aa->get_base(), ba->get_base() );
    604                 } else if ( aid == type_index{typeid(FunctionType)} ) {
    605                         FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b);
    606 
    607                         vector<Type*> aparams, bparams;
    608                         flattenList( af->get_parameters(), back_inserter( aparams ) );
    609                         flattenList( bf->get_parameters(), back_inserter( bparams ) );
    610                         if ( aparams.size() != bparams.size() ) return false;
    611 
    612                         vector<Type*> areturns, breturns;
    613                         flattenList( af->get_returnVals(), back_inserter( areturns ) );
    614                         flattenList( bf->get_returnVals(), back_inserter( breturns ) );
    615                         if ( areturns.size() != breturns.size() ) return false;
    616 
    617                         for ( unsigned i = 0; i < aparams.size(); ++i ) {
    618                                 if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false;
    619                         }
    620                         for ( unsigned i = 0; i < areturns.size(); ++i ) {
    621                                 if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false;
    622                         }
    623                         return true;
    624                 } else if ( aid == type_index{typeid(StructInstType)} ) {
    625                         StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b);
    626 
    627                         if ( aa->get_name() != ba->get_name() ) return false;
    628                         return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );
    629                 } else if ( aid == type_index{typeid(UnionInstType)} ) {
    630                         UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b);
    631 
    632                         if ( aa->get_name() != ba->get_name() ) return false;
    633                         return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );
    634                 } else if ( aid == type_index{typeid(EnumInstType)} ) {
    635                         return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name();
    636                 } else if ( aid == type_index{typeid(TraitInstType)} ) {
    637                         return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name();
    638                 } else if ( aid == type_index{typeid(TupleType)} ) {
    639                         TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b);
    640 
    641                         vector<Type*> atypes, btypes;
    642                         flattenList( at->get_types(), back_inserter( atypes ) );
    643                         flattenList( bt->get_types(), back_inserter( btypes ) );
    644                         if ( atypes.size() != btypes.size() ) return false;
    645 
    646                         for ( unsigned i = 0; i < atypes.size(); ++i ) {
    647                                 if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false;
    648                         }
    649                         return true;
    650                 } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type
    651247        }
    652248
     
    763359}
    764360
    765         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    766                 // is parameter is not polymorphic, don't need to box
    767                 if ( ! isPolyType( param, exprTyVars ) ) return false;
    768                 Type * newType = arg->clone();
    769                 if ( env ) env->apply( newType );
    770                 std::unique_ptr<Type> manager( newType );
    771                 // if the argument's type is polymorphic, we don't need to box again!
    772                 return ! isPolyType( newType );
    773         }
    774 
    775361bool needsBoxing( const ast::Type * param, const ast::Type * arg,
    776362                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    786372        return !isPolyType( newType );
    787373}
    788 
    789         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    790                 FunctionType * function = getFunctionType( appExpr->function->result );
    791                 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
    792                 TyVarMap exprTyVars( TypeDecl::Data{} );
    793                 makeTyVarMap( function, exprTyVars );
    794                 return needsBoxing( param, arg, exprTyVars, env );
    795         }
    796374
    797375bool needsBoxing(
     
    806384}
    807385
    808         void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    809                 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
    810         }
    811 
    812386void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
    813387        typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
     
    817391        typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
    818392}
    819 
    820         void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
    821                 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
    822                         assert( *tyVar );
    823                         addToTyVarMap( *tyVar, tyVarMap );
    824                 }
    825                 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    826                         makeTyVarMap( pointer->get_base(), tyVarMap );
    827                 }
    828         }
    829393
    830394void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) {
     
    846410}
    847411
    848         void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
    849                 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
    850                         os << i->first << " (" << i->second << ") ";
    851                 } // for
    852                 os << std::endl;
    853         }
    854 
    855412} // namespace GenPoly
    856413
  • src/GenPoly/GenPoly.h

    rdf8ba61a r8d182b1  
    2323#include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
    2424#include "SymTab/Mangler.h"       // for Mangler
    25 #include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
    26 #include "SynTree/SynTree.h"      // for Visitor Nodes
    2725
    2826namespace ast {
     
    3230namespace GenPoly {
    3331
    34         typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    3532        struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> {
    3633                TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {}
     
    3835
    3936        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    40         Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
    41         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );
    4237        const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
    4338
    4439        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
    45         Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
    4640        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    4741
    4842        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    49         Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    5043        const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr );
    5144
    5245        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
    53         ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    5446        const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 );
    5547
    5648        /// true iff function has dynamic-layout return type under the given type variable map
    57         ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );
    5849        const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars );
    5950
    6051        /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
    61         ReferenceToType *isDynRet( FunctionType *function );
    6252        const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
    6353
    6454        /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
    65         bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr );
    6655        bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars );
    6756
    68         /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided
    69         Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );
    70 
    7157        /// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    72         Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    7358        const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 );
    74 
    75         /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;
    76         /// N will be stored in levels, if provided, will look up substitution in env if provided
    77         Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );
    7859
    7960        /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise;
    8061        /// N will be stored in levels, if provided, will look up substitution in env if provided
    81         Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );
    8262        const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 );
    8363
    84         /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one
    85         /// polymorphic parameter; will look up substitution in env if provided.
    86         bool includesPolyType( Type *type, const TypeSubstitution *env = 0 );
    87 
    88         /// true iff this type or some base of this type after dereferencing pointers is either polymorphic in tyVars, or a generic type with
    89         /// at least one polymorphic parameter in tyVars; will look up substitution in env if provided.
    90         bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    91 
    9264        /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
    93         FunctionType *getFunctionType( Type *ty );
    9465        const ast::FunctionType * getFunctionType( const ast::Type * ty );
    9566
    96         /// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise;
    97         /// N will be stored in levels, if provided
    98         VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );
    99 
    10067        /// true iff types are structurally identical, where TypeInstType's match any type.
    101         bool typesPolyCompatible( Type *aty, Type *bty );
    10268        bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
    10369
    10470        /// true if arg requires boxing given exprTyVars
    105         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
    10671        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst );
    10772
    10873        /// true if arg requires boxing in the call to appExpr
    109         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
    11074        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst );
    11175
    11276        /// Adds the type variable `tyVar` to `tyVarMap`
    113         void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
    11477        void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
    11578        void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars );
    11679
    11780        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    118         void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    11981        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
    12082        void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars );
    121 
    122         /// Prints type variable map
    123         void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
    124 
    125         /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
    126         inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
    12783
    12884        /// Gets the name of the sizeof parameter for the type, given its mangled name
     
    13692
    13793        /// Gets the name of the layout function for a given aggregate type, given its declaration
    138         inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
    13994        inline std::string layoutofName( ast::AggregateDecl const * decl ) {
    14095                return std::string( "_layoutof_" ) + decl->name;
  • src/GenPoly/ScrubTyVars.cc

    rdf8ba61a r8d182b1  
    2121#include "ScrubTyVars.h"
    2222#include "SymTab/Mangler.h"             // for mangleType
    23 #include "SynTree/Declaration.h"        // for TypeDecl, TypeDecl::Data, Typ...
    24 #include "SynTree/Expression.h"         // for Expression (ptr only), NameExpr
    25 #include "SynTree/Mutator.h"            // for Mutator
    26 #include "SynTree/Type.h"               // for PointerType, TypeInstType, Type
    2723
    2824namespace GenPoly {
    29         Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) {
    30                 if ( ! tyVars ) {
    31                         if ( typeInst->get_isFtype() ) {
    32                                 delete typeInst;
    33                                 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    34                         } else {
    35                                 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
    36                                 delete typeInst;
    37                                 return ret;
    38                         }
    39                 }
    40 
    41                 TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name );
    42                 if ( tyVar != tyVars->end() ) {
    43                         switch ( tyVar->second.kind ) {
    44                           case TypeDecl::Dtype:
    45                           case TypeDecl::Ttype:
    46                                 {
    47                                         PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
    48                                         delete typeInst;
    49                                         return ret;
    50                                 }
    51                           case TypeDecl::Ftype:
    52                                 delete typeInst;
    53                                 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    54                           default:
    55                                 assertf(false, "Unhandled tyvar kind: %d", tyVar->second.kind);
    56                         } // switch
    57                 } // if
    58                 return typeInst;
    59         }
    60 
    61         Type * ScrubTyVars::mutateAggregateType( Type * ty ) {
    62                 if ( shouldScrub( ty ) ) {
    63                         PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
    64                         delete ty;
    65                         return ret;
    66                 }
    67                 return ty;
    68         }
    69 
    70         Type * ScrubTyVars::postmutate( StructInstType * structInst ) {
    71                 return mutateAggregateType( structInst );
    72         }
    73 
    74         Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) {
    75                 return mutateAggregateType( unionInst );
    76         }
    77 
    78         void ScrubTyVars::primeBaseScrub( Type * type ) {
    79                 // need to determine whether type needs to be scrubbed to determine whether
    80                 // automatic recursion is necessary
    81                 if ( Type * t = shouldScrub( type ) ) {
    82                         visit_children = false;
    83                         GuardValue( dynType );
    84                         dynType = t;
    85                 }
    86         }
    87 
    88         Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) {
    89                 // sizeof( T ) => _sizeof_T parameter, which is the size of T
    90                 if ( dynType ) {
    91                         Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );
    92                         return expr;
    93                 } // if
    94                 return szeof;
    95         }
    96 
    97         Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {
    98                 // alignof( T ) => _alignof_T parameter, which is the alignment of T
    99                 if ( dynType ) {
    100                         Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );
    101                         return expr;
    102                 } // if
    103                 return algnof;
    104         }
    105 
    106         Type * ScrubTyVars::postmutate( PointerType * pointer ) {
    107                 if ( dynType ) {
    108                         Type * ret = dynType->acceptMutator( *visitor );
    109                         ret->get_qualifiers() |= pointer->get_qualifiers();
    110                         pointer->base = nullptr;
    111                         delete pointer;
    112                         return ret;
    113                 }
    114                 return pointer;
    115         }
    11625
    11726namespace {
  • src/GenPoly/ScrubTyVars.h

    rdf8ba61a r8d182b1  
    1919
    2020#include "AST/Fwd.hpp"        // for Node
    21 #include "Common/PassVisitor.h"
    2221#include "GenPoly.h"          // for TyVarMap, isPolyType, isDynType
    23 #include "SynTree/Mutator.h"  // for Mutator
    24 #include "SynTree/Type.h"     // for Type (ptr only), PointerType (ptr only)
    25 
    26 class AlignofExpr;
    27 class Expression;
    28 class SizeofExpr;
    2922
    3023namespace GenPoly {
    31         struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards {
    32                 /// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables
    33                 enum ScrubMode { FromMap, DynamicFromMap, All };
    34 
    35                 ScrubTyVars() : tyVars(nullptr), mode( All ) {}
    36 
    37                 ScrubTyVars( const TyVarMap &tyVars, ScrubMode mode = FromMap ): tyVars( &tyVars ), mode( mode ) {}
    38 
    39         public:
    40                 /// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
    41                 /// and sizeof/alignof expressions with the proper variable
    42                 template< typename SynTreeClass >
    43                 static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars );
    44 
    45                 /// For all dynamic-layout types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
    46                 /// and sizeof/alignof expressions with the proper variable
    47                 template< typename SynTreeClass >
    48                 static SynTreeClass *scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars );
    49 
    50                 /// For all polymorphic types, replaces generic types, dtypes, and ftypes with the appropriate void type,
    51                 /// and sizeof/alignof expressions with the proper variable
    52                 template< typename SynTreeClass >
    53                 static SynTreeClass *scrubAll( SynTreeClass *target );
    54 
    55                 /// determine if children should be visited based on whether base type should be scrubbed.
    56                 void primeBaseScrub( Type * );
    57 
    58                 void premutate( TypeInstType * ) { visit_children = false; }
    59                 void premutate( StructInstType * ) { visit_children = false; }
    60                 void premutate( UnionInstType * ) { visit_children = false; }
    61                 void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); }
    62                 void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); }
    63                 void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); }
    64 
    65                 Type * postmutate( TypeInstType * typeInst );
    66                 Type * postmutate( StructInstType * structInst );
    67                 Type * postmutate( UnionInstType * unionInst );
    68                 Expression * postmutate( SizeofExpr * szeof );
    69                 Expression * postmutate( AlignofExpr * algnof );
    70                 Type * postmutate( PointerType * pointer );
    71 
    72           private:
    73                 /// Returns the type if it should be scrubbed, NULL otherwise.
    74                 Type* shouldScrub( Type *ty ) {
    75                         switch ( mode ) {
    76                         case FromMap: return isPolyType( ty, *tyVars );
    77                         case DynamicFromMap: return isDynType( ty, *tyVars );
    78                         case All: return isPolyType( ty );
    79                         }
    80                         assert(false); return nullptr; // unreachable
    81                         // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars );
    82                 }
    83 
    84                 /// Mutates (possibly generic) aggregate types appropriately
    85                 Type* mutateAggregateType( Type *ty );
    86 
    87                 const TyVarMap *tyVars;  ///< Type variables to scrub
    88                 ScrubMode mode;          ///< which type variables to scrub? [FromMap]
    89 
    90                 Type * dynType = nullptr; ///< result of shouldScrub
    91         };
    92 
    93         template< typename SynTreeClass >
    94         SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {
    95                 PassVisitor<ScrubTyVars> scrubber( tyVars );
    96                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    97         }
    98 
    99         template< typename SynTreeClass >
    100         SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) {
    101                 PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap );
    102                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    103         }
    104 
    105         template< typename SynTreeClass >
    106         SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) {
    107                 PassVisitor<ScrubTyVars> scrubber;
    108                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    109         }
    11024
    11125// ScrubMode and scrubTypeVarsBase are internal.
  • src/GenPoly/SpecializeNew.cpp

    rdf8ba61a r8d182b1  
    2323#include "GenPoly/GenPoly.h"             // for getFunctionType
    2424#include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
    25 #include "ResolvExpr/TypeEnvironment.h"  // for FirstOpen, FirstClosed
    2625
    2726namespace GenPoly {
  • src/GenPoly/module.mk

    rdf8ba61a r8d182b1  
    2323SRC += $(SRC_GENPOLY) \
    2424        GenPoly/BoxNew.cpp \
    25         GenPoly/Box.cc \
    2625        GenPoly/Box.h \
    2726        GenPoly/ErasableScopedMap.h \
     
    2928        GenPoly/FindFunction.h \
    3029        GenPoly/InstantiateGenericNew.cpp \
    31         GenPoly/InstantiateGeneric.cc \
    3230        GenPoly/InstantiateGeneric.h \
    3331        GenPoly/LvalueNew.cpp \
    34         GenPoly/Lvalue.cc \
    3532        GenPoly/ScopedSet.h \
    3633        GenPoly/ScrubTyVars.cc \
    3734        GenPoly/ScrubTyVars.h \
    38         GenPoly/Specialize.cc \
    3935        GenPoly/SpecializeNew.cpp \
    4036        GenPoly/Specialize.h
  • src/InitTweak/FixGlobalInit.cc

    rdf8ba61a r8d182b1  
    2020#include <algorithm>               // for replace_if
    2121
    22 #include "Common/PassVisitor.h"
    23 #include "Common/UniqueName.h"     // for UniqueName
    24 #include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    25 #include "SynTree/LinkageSpec.h"   // for C
    26 #include "SynTree/Attribute.h"     // for Attribute
    27 #include "SynTree/Constant.h"      // for Constant
    28 #include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declaration
    29 #include "SynTree/Expression.h"    // for ConstantExpr, Expression (ptr only)
    30 #include "SynTree/Initializer.h"   // for ConstructorInit, Initializer
    31 #include "SynTree/Label.h"         // for Label
    32 #include "SynTree/Statement.h"     // for CompoundStmt, Statement (ptr only)
    33 #include "SynTree/Type.h"          // for Type, Type::StorageClasses, Functi...
    34 #include "SynTree/Visitor.h"       // for acceptAll, Visitor
    35 
    3622#include "AST/Expr.hpp"
    3723#include "AST/Node.hpp"
    3824#include "AST/Pass.hpp"
     25#include "Common/UniqueName.h"     // for UniqueName
     26#include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    3927
    4028namespace InitTweak {
    41         class GlobalFixer : public WithShortCircuiting {
    42           public:
    43                 GlobalFixer( bool inLibrary );
    44 
    45                 void previsit( ObjectDecl *objDecl );
    46                 void previsit( FunctionDecl *functionDecl );
    47                 void previsit( StructDecl *aggregateDecl );
    48                 void previsit( UnionDecl *aggregateDecl );
    49                 void previsit( EnumDecl *aggregateDecl );
    50                 void previsit( TraitDecl *aggregateDecl );
    51                 void previsit( TypeDecl *typeDecl );
    52 
    53                 UniqueName tempNamer;
    54                 FunctionDecl * initFunction;
    55                 FunctionDecl * destroyFunction;
    56         };
    57 
    58         class GlobalFixer_new : public ast::WithShortCircuiting {
     29        class GlobalFixer : public ast::WithShortCircuiting {
    5930        public:
    6031                void previsit (const ast::ObjectDecl *);
     
    7041        };
    7142
    72         void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ) {
    73                 PassVisitor<GlobalFixer> visitor( inLibrary );
    74                 acceptAll( translationUnit, visitor );
    75                 GlobalFixer & fixer = visitor.pass;
    76                 // don't need to include function if it's empty
    77                 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {
    78                         delete fixer.initFunction;
    79                 } else {
    80                         translationUnit.push_back( fixer.initFunction );
    81                 } // if
    82 
    83                 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {
    84                         delete fixer.destroyFunction;
    85                 } else {
    86                         translationUnit.push_back( fixer.destroyFunction );
    87                 } // if
    88         }
    89 
    90         GlobalFixer::GlobalFixer( bool inLibrary ) : tempNamer( "_global_init" ) {
    91                 std::list< Expression * > ctorParameters;
    92                 std::list< Expression * > dtorParameters;
    93                 if ( inLibrary ) {
    94                         // Constructor/destructor attributes take a single parameter which
    95                         // is the priority, with lower numbers meaning higher priority.
    96                         // Functions specified with priority are guaranteed to run before
    97                         // functions without a priority. To ensure that constructors and destructors
    98                         // for library code are run before constructors and destructors for user code,
    99                         // specify a priority when building the library. Priorities 0-100 are reserved by gcc.
    100                         // Priorities 101-200 are reserved by cfa, so use priority 200 for CFA library globals,
    101                         // allowing room for overriding with a higher priority.
    102                         ctorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );
    103                         dtorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );
    104                 }
    105                 initFunction = new FunctionDecl( "__global_init__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
    106                 initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) );
    107                 destroyFunction = new FunctionDecl( "__global_destroy__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
    108                 destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) );
    109         }
    110 
    11143        void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
    112                 ast::Pass<GlobalFixer_new> fixer;
     44                ast::Pass<GlobalFixer> fixer;
    11345                accept_all(translationUnit, fixer);
    11446
     
    14173        }
    14274
    143         void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    144                 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
    145                 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();
    146 
    147                 // C allows you to initialize objects with constant expressions
    148                 // xxx - this is an optimization. Need to first resolve constructors before we decide
    149                 // to keep C-style initializer.
    150                 // if ( isConstExpr( objDecl->get_init() ) ) return;
    151 
    152                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
    153                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    154                         assert( ! ctorInit->ctor || ! ctorInit->init );
    155 
    156                         Statement * dtor = ctorInit->dtor;
    157                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    158                                 // don't need to call intrinsic dtor, because it does nothing, but
    159                                 // non-intrinsic dtors must be called
    160                                 destroyStatements.push_front( dtor );
    161                                 ctorInit->dtor = nullptr;
    162                         } // if
    163                         if ( Statement * ctor = ctorInit->ctor ) {
    164                                 addDataSectionAttribute( objDecl );
    165                                 initStatements.push_back( ctor );
    166                                 objDecl->init = nullptr;
    167                                 ctorInit->ctor = nullptr;
    168                         } else if ( Initializer * init = ctorInit->init ) {
    169                                 objDecl->init = init;
    170                                 ctorInit->init = nullptr;
    171                         } else {
    172                                 // no constructor and no initializer, which is okay
    173                                 objDecl->init = nullptr;
    174                         } // if
    175                         delete ctorInit;
    176                 } // if
    177         }
    178 
    179         void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) {
     75        void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) {
    18076                auto mutDecl = mutate(objDecl);
    18177                assertf(mutDecl == objDecl, "Global object decl must be unique");
     
    207103        }
    208104
    209         // only modify global variables
    210         void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }
    211         void GlobalFixer::previsit( StructDecl * ) { visit_children = false; }
    212         void GlobalFixer::previsit( UnionDecl * ) { visit_children = false; }
    213         void GlobalFixer::previsit( EnumDecl * ) { visit_children = false; }
    214         void GlobalFixer::previsit( TraitDecl * ) { visit_children = false; }
    215         void GlobalFixer::previsit( TypeDecl * ) { visit_children = false; }
    216 
    217105} // namespace InitTweak
    218106
  • src/InitTweak/FixInitNew.cpp

    rdf8ba61a r8d182b1  
    178178/// (currently by FixInit)
    179179struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> {
    180         typedef std::list< ObjectDecl * > OrderedDecls;
    181         typedef std::list< OrderedDecls > OrderedDeclsStack;
    182 
    183180        InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {}
    184181
     
    194191        ast::Pass<LabelFinder> & finder;
    195192        LabelFinder::LabelMap & labelVars;
    196         OrderedDeclsStack reverseDeclOrder;
    197193};
    198194
     
    921917                                        // static variables with the same name in different functions.
    922918                                        // Note: it isn't sufficient to modify only the mangleName, because
    923                                         // then subsequent Indexer passes can choke on seeing the object's name
     919                                        // then subsequent SymbolTable passes can choke on seeing the object's name
    924920                                        // if another object has the same name and type. An unfortunate side-effect
    925921                                        // of renaming the object is that subsequent NameExprs may fail to resolve,
     
    11731169                                arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );
    11741170                        }
    1175                         InitExpander_new srcParam( arg2 );
     1171                        InitExpander srcParam( arg2 );
    11761172                        // cast away reference type and construct field.
    11771173                        ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences());
  • src/InitTweak/GenInit.cc

    rdf8ba61a r8d182b1  
    2929#include "CompilationState.h"
    3030#include "CodeGen/OperatorTable.h"
    31 #include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
    3231#include "Common/SemanticError.h"      // for SemanticError
    3332#include "Common/ToString.hpp"         // for toCString
     
    3837#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
    3938#include "ResolvExpr/Resolver.h"
    40 #include "SymTab/Autogen.h"            // for genImplicitCall
    4139#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4240#include "SymTab/Mangler.h"            // for Mangler
    43 #include "SynTree/LinkageSpec.h"       // for isOverridable, C
    44 #include "SynTree/Declaration.h"       // for ObjectDecl, DeclarationWithType
    45 #include "SynTree/Expression.h"        // for VariableExpr, UntypedExpr, Address...
    46 #include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit, Initi...
    47 #include "SynTree/Label.h"             // for Label
    48 #include "SynTree/Mutator.h"           // for mutateAll
    49 #include "SynTree/Statement.h"         // for CompoundStmt, ImplicitCtorDtorStmt
    50 #include "SynTree/Type.h"              // for Type, ArrayType, Type::Qualifiers
    51 #include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5241#include "Tuples/Tuples.h"             // for maybeImpure
    5342#include "Validate/FindSpecialDecls.h" // for SizeType
    5443
    5544namespace InitTweak {
    56         namespace {
    57                 const std::list<Label> noLabels;
    58                 const std::list<Expression *> noDesignators;
    59         }
    60 
    61         struct ReturnFixer : public WithStmtsToAdd, public WithGuards {
    62                 /// consistently allocates a temporary variable for the return value
    63                 /// of a function so that anything which the resolver decides can be constructed
    64                 /// into the return type of a function can be returned.
    65                 static void makeReturnTemp( std::list< Declaration * > &translationUnit );
    66 
    67                 void premutate( FunctionDecl *functionDecl );
    68                 void premutate( ReturnStmt * returnStmt );
    69 
    70           protected:
    71                 FunctionType * ftype = nullptr;
    72                 std::string funcName;
    73         };
    74 
    75         struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor>  {
    76                 /// create constructor and destructor statements for object declarations.
    77                 /// the actual call statements will be added in after the resolver has run
    78                 /// so that the initializer expression is only removed if a constructor is found
    79                 /// and the same destructor call is inserted in all of the appropriate locations.
    80                 static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    81 
    82                 void previsit( ObjectDecl * );
    83                 void previsit( FunctionDecl *functionDecl );
    84 
    85                 // should not traverse into any of these declarations to find objects
    86                 // that need to be constructed or destructed
    87                 void previsit( StructDecl *aggregateDecl );
    88                 void previsit( AggregateDecl * ) { visit_children = false; }
    89                 void previsit( NamedTypeDecl * ) { visit_children = false; }
    90                 void previsit( FunctionType * ) { visit_children = false; }
    91 
    92                 void previsit( CompoundStmt * compoundStmt );
    93 
    94           private:
    95                 // set of mangled type names for which a constructor or destructor exists in the current scope.
    96                 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus
    97                 // should not have a ConstructorInit generated.
    98 
    99                 ManagedTypes managedTypes;
    100                 bool inFunction = false;
    101         };
    102 
    103         struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {
    104                 /// hoist dimension from array types in object declaration so that it uses a single
    105                 /// const variable of type size_t, so that side effecting array dimensions are only
    106                 /// computed once.
    107                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    108 
    109                 void premutate( ObjectDecl * objectDecl );
    110                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    111                 void premutate( FunctionDecl *functionDecl );
    112                 // should not traverse into any of these declarations to find objects
    113                 // that need to be constructed or destructed
    114                 void premutate( AggregateDecl * ) { visit_children = false; }
    115                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    116                 void premutate( FunctionType * ) { visit_children = false; }
    117 
    118                 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)
    119                 void premutate( EnumDecl * ) {}
    120 
    121                 void hoist( Type * type );
    122 
    123                 Type::StorageClasses storageClasses;
    124                 bool inFunction = false;
    125         };
    126 
    127         struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
    128                 /// hoist dimension from array types in object declaration so that it uses a single
    129                 /// const variable of type size_t, so that side effecting array dimensions are only
    130                 /// computed once.
    131                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    132 
    133                 void premutate( ObjectDecl * objectDecl );
    134                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    135                 void premutate( FunctionDecl *functionDecl );
    136                 // should not traverse into any of these declarations to find objects
    137                 // that need to be constructed or destructed
    138                 void premutate( AggregateDecl * ) { visit_children = false; }
    139                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    140                 void premutate( FunctionType * ) { visit_children = false; }
    141 
    142                 void hoist( Type * type );
    143 
    144                 Type::StorageClasses storageClasses;
    145                 bool inFunction = false;
    146         };
    147 
    148         void genInit( std::list< Declaration * > & translationUnit ) {
    149                 if (!useNewAST) {
    150                         HoistArrayDimension::hoistArrayDimension( translationUnit );
    151                 }
    152                 else {
    153                         HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
    154                 }
    155                 fixReturnStatements( translationUnit );
    156 
    157                 if (!useNewAST) {
    158                         CtorDtor::generateCtorDtor( translationUnit );
    159                 }
    160         }
    161 
    162         void fixReturnStatements( std::list< Declaration * > & translationUnit ) {
    163                 PassVisitor<ReturnFixer> fixer;
    164                 mutateAll( translationUnit, fixer );
    165         }
    166 
    167         void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
    168                 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    169                 assert( returnVals.size() == 0 || returnVals.size() == 1 );
    170                 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address
    171                 // is being returned
    172                 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {
    173                         // explicitly construct the return value using the return expression and the retVal object
    174                         assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );
    175 
    176                         ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );
    177                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {
    178                                 // return statement has already been mutated - don't need to do it again
    179                                 if ( varExpr->var == retVal ) return;
    180                         }
    181                         Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );
    182                         assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );
    183                         stmtsToAddBefore.push_back( stmt );
    184 
    185                         // return the retVal object
    186                         returnStmt->expr = new VariableExpr( returnVals.front() );
    187                 } // if
    188         }
    189 
    190         void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
    191                 GuardValue( ftype );
    192                 GuardValue( funcName );
    193 
    194                 ftype = functionDecl->type;
    195                 funcName = functionDecl->name;
    196         }
    197 
    198         // precompute array dimension expression, because constructor generation may duplicate it,
    199         // which would be incorrect if it is a side-effecting computation.
    200         void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    201                 PassVisitor<HoistArrayDimension> hoister;
    202                 mutateAll( translationUnit, hoister );
    203         }
    204 
    205         void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {
    206                 GuardValue( storageClasses );
    207                 storageClasses = objectDecl->get_storageClasses();
    208         }
    209 
    210         DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {
    211                 hoist( objectDecl->get_type() );
    212                 return objectDecl;
    213         }
    214 
    215         void HoistArrayDimension::hoist( Type * type ) {
    216                 // if in function, generate const size_t var
    217                 static UniqueName dimensionName( "_array_dim" );
    218 
    219                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    220                 if ( ! inFunction ) return;
    221                 if ( storageClasses.is_static ) return;
    222 
    223                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    224                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    225 
    226                         // need to resolve array dimensions in order to accurately determine if constexpr
    227                         ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
    228                         // array is variable-length when the dimension is not constexpr
    229                         arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    230                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    231                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    232                         // still try to detect constant expressions
    233                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    234 
    235                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    236                         arrayDimension->get_type()->set_const( true );
    237 
    238                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    239                         declsToAddBefore.push_back( arrayDimension );
    240 
    241                         hoist( arrayType->get_base() );
    242                         return;
    243                 }
    244         }
    245 
    246         void HoistArrayDimension::premutate( FunctionDecl * ) {
    247                 GuardValue( inFunction );
    248                 inFunction = true;
    249         }
    250 
    251         // precompute array dimension expression, because constructor generation may duplicate it,
    252         // which would be incorrect if it is a side-effecting computation.
    253         void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    254                 PassVisitor<HoistArrayDimension_NoResolve> hoister;
    255                 mutateAll( translationUnit, hoister );
    256         }
    257 
    258         void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
    259                 GuardValue( storageClasses );
    260                 storageClasses = objectDecl->get_storageClasses();
    261         }
    262 
    263         DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
    264                 hoist( objectDecl->get_type() );
    265                 return objectDecl;
    266         }
    267 
    268         void HoistArrayDimension_NoResolve::hoist( Type * type ) {
    269                 // if in function, generate const size_t var
    270                 static UniqueName dimensionName( "_array_dim" );
    271 
    272                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    273                 if ( ! inFunction ) return;
    274                 if ( storageClasses.is_static ) return;
    275 
    276                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    277                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    278                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    279                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    280                         // still try to detect constant expressions
    281                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    282 
    283                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    284                         arrayDimension->get_type()->set_const( true );
    285 
    286                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    287                         declsToAddBefore.push_back( arrayDimension );
    288 
    289                         hoist( arrayType->get_base() );
    290                         return;
    291                 }
    292         }
    293 
    294         void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
    295                 GuardValue( inFunction );
    296                 inFunction = true;
    297         }
    29845
    29946namespace {
    30047
    301 #       warning Remove the _New suffix after the conversion is complete.
    302 
    30348        // Outer pass finds declarations, for their type could wrap a type that needs hoisting
    304         struct HoistArrayDimension_NoResolve_New final :
     49        struct HoistArrayDimension_NoResolve final :
    30550                        public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
    30651                        public ast::WithGuards, public ast::WithConstTranslationUnit,
    307                         public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New>,
     52                        public ast::WithVisitorRef<HoistArrayDimension_NoResolve>,
    30853                        public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> {
    30954
     
    31257                                public ast::WithShortCircuiting, public ast::WithGuards {
    31358
    314                         HoistArrayDimension_NoResolve_New * outer;
    315                         HoistDimsFromTypes( HoistArrayDimension_NoResolve_New * outer ) : outer(outer) {}
     59                        HoistArrayDimension_NoResolve * outer;
     60                        HoistDimsFromTypes( HoistArrayDimension_NoResolve * outer ) : outer(outer) {}
    31661
    31762                        // Only intended for visiting through types.
     
    464209
    465210
    466         struct ReturnFixer_New final :
     211        struct ReturnFixer final :
    467212                        public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
    468213                void previsit( const ast::FunctionDecl * decl );
     
    472217        };
    473218
    474         void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) {
     219        void ReturnFixer::previsit( const ast::FunctionDecl * decl ) {
    475220                if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false;
    476221                GuardValue( funcDecl ) = decl;
    477222        }
    478223
    479         const ast::ReturnStmt * ReturnFixer_New::previsit(
     224        const ast::ReturnStmt * ReturnFixer::previsit(
    480225                        const ast::ReturnStmt * stmt ) {
    481226                auto & returns = funcDecl->returns;
     
    518263
    519264        void genInit( ast::TranslationUnit & transUnit ) {
    520                 ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit );
    521                 ast::Pass<ReturnFixer_New>::run( transUnit );
     265                ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit );
     266                ast::Pass<ReturnFixer>::run( transUnit );
    522267        }
    523268
    524269        void fixReturnStatements( ast::TranslationUnit & transUnit ) {
    525                 ast::Pass<ReturnFixer_New>::run( transUnit );
    526         }
    527 
    528         void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    529                 PassVisitor<CtorDtor> ctordtor;
    530                 acceptAll( translationUnit, ctordtor );
    531         }
    532 
    533         bool ManagedTypes::isManaged( Type * type ) const {
    534                 // references are never constructed
    535                 if ( dynamic_cast< ReferenceType * >( type ) ) return false;
    536                 // need to clear and reset qualifiers when determining if a type is managed
    537                 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
    538                 type->get_qualifiers() = Type::Qualifiers();
    539                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
    540                         // tuple is also managed if any of its components are managed
    541                         if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) {
    542                                 return true;
    543                         }
    544                 }
    545                 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
    546                 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
    547         }
    548 
    549         bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const {
    550                 Type * type = objDecl->get_type();
    551                 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    552                         // must always construct VLAs with an initializer, since this is an error in C
    553                         if ( at->isVarLen && objDecl->init ) return true;
    554                         type = at->get_base();
    555                 }
    556                 return isManaged( type );
    557         }
    558 
    559         // why is this not just on FunctionDecl?
    560         void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
    561                 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
    562                 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) {
    563                         std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters();
    564                         assert( ! params.empty() );
    565                         Type * type = InitTweak::getPointerBase( params.front()->get_type() );
    566                         assert( type );
    567                         managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) );
    568                 }
    569         }
    570 
    571         void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) {
    572                 // don't construct members, but need to take note if there is a managed member,
    573                 // because that means that this type is also managed
    574                 for ( Declaration * member : aggregateDecl->get_members() ) {
    575                         if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
    576                                 if ( isManaged( field ) ) {
    577                                         // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
    578                                         // polymorphic constructors make generic types managed types
    579                                         StructInstType inst( Type::Qualifiers(), aggregateDecl );
    580                                         managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) );
    581                                         break;
    582                                 }
    583                         }
    584                 }
    585         }
    586 
    587         void ManagedTypes::beginScope() { managedTypes.beginScope(); }
    588         void ManagedTypes::endScope() { managedTypes.endScope(); }
    589 
    590         bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
     270                ast::Pass<ReturnFixer>::run( transUnit );
     271        }
     272
     273        bool ManagedTypes::isManaged( const ast::Type * type ) const {
    591274                // references are never constructed
    592275                if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
     
    607290        }
    608291
    609         bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const {
     292        bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const {
    610293                const ast::Type * type = objDecl->type;
    611294                while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
     
    617300        }
    618301
    619         void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) {
     302        void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) {
    620303                // if this function is a user-defined constructor or destructor, mark down the type as "managed"
    621304                if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
     
    628311        }
    629312
    630         void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) {
     313        void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) {
    631314                // don't construct members, but need to take note if there is a managed member,
    632315                // because that means that this type is also managed
     
    644327        }
    645328
    646         void ManagedTypes_new::beginScope() { managedTypes.beginScope(); }
    647         void ManagedTypes_new::endScope() { managedTypes.endScope(); }
    648 
    649         ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
    650                 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    651                 assertf( objDecl, "genCtorDtor passed null objDecl" );
    652                 std::list< Statement * > stmts;
    653                 InitExpander_old srcParam( maybeClone( arg ) );
    654                 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
    655                 assert( stmts.size() <= 1 );
    656                 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
    657 
    658         }
     329        void ManagedTypes::beginScope() { managedTypes.beginScope(); }
     330        void ManagedTypes::endScope() { managedTypes.endScope(); }
    659331
    660332        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
    661333                assertf(objDecl, "genCtorDtor passed null objDecl");
    662                 InitExpander_new srcParam(arg);
     334                InitExpander srcParam(arg);
    663335                return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    664         }
    665 
    666         ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
    667                 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    668                 // for each constructable object
    669                 std::list< Statement * > ctor;
    670                 std::list< Statement * > dtor;
    671 
    672                 InitExpander_old srcParam( objDecl->get_init() );
    673                 InitExpander_old nullParam( (Initializer *)NULL );
    674                 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    675                 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    676 
    677                 // Currently genImplicitCall produces a single Statement - a CompoundStmt
    678                 // which  wraps everything that needs to happen. As such, it's technically
    679                 // possible to use a Statement ** in the above calls, but this is inherently
    680                 // unsafe, so instead we take the slightly less efficient route, but will be
    681                 // immediately informed if somehow the above assumption is broken. In this case,
    682                 // we could always wrap the list of statements at this point with a CompoundStmt,
    683                 // but it seems reasonable at the moment for this to be done by genImplicitCall
    684                 // itself. It is possible that genImplicitCall produces no statements (e.g. if
    685                 // an array type does not have a dimension). In this case, it's fine to ignore
    686                 // the object for the purposes of construction.
    687                 assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    688                 if ( ctor.size() == 1 ) {
    689                         // need to remember init expression, in case no ctors exist
    690                         // if ctor does exist, want to use ctor expression instead of init
    691                         // push this decision to the resolver
    692                         assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    693                         return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
    694                 }
    695                 return nullptr;
    696         }
    697 
    698         void CtorDtor::previsit( ObjectDecl * objDecl ) {
    699                 managedTypes.handleDWT( objDecl );
    700                 // hands off if @=, extern, builtin, etc.
    701                 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C
    702                 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {
    703                         // constructed objects cannot be designated
    704                         if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
    705                         // constructed objects should not have initializers nested too deeply
    706                         if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );
    707 
    708                         objDecl->set_init( genCtorInit( objDecl ) );
    709                 }
    710         }
    711 
    712         void CtorDtor::previsit( FunctionDecl *functionDecl ) {
    713                 visit_children = false;  // do not try and construct parameters or forall parameters
    714                 GuardValue( inFunction );
    715                 inFunction = true;
    716 
    717                 managedTypes.handleDWT( functionDecl );
    718 
    719                 GuardScope( managedTypes );
    720                 // go through assertions and recursively add seen ctor/dtors
    721                 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
    722                         for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
    723                                 managedTypes.handleDWT( assertion );
    724                         }
    725                 }
    726 
    727                 maybeAccept( functionDecl->get_statements(), *visitor );
    728         }
    729 
    730         void CtorDtor::previsit( StructDecl *aggregateDecl ) {
    731                 visit_children = false; // do not try to construct and destruct aggregate members
    732 
    733                 managedTypes.handleStruct( aggregateDecl );
    734         }
    735 
    736         void CtorDtor::previsit( CompoundStmt * ) {
    737                 GuardScope( managedTypes );
    738336        }
    739337
     
    741339        // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
    742340        // constructable object
    743         InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
     341        InitExpander srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
    744342        ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
    745343
  • src/InitTweak/GenInit.h

    rdf8ba61a r8d182b1  
    2222#include "Common/CodeLocation.h"
    2323#include "GenPoly/ScopedSet.h" // for ScopedSet
    24 #include "SynTree/SynTree.h"   // for Visitor Nodes
    2524
    2625namespace InitTweak {
    2726        /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
    28         void genInit( std::list< Declaration * > & translationUnit );
    2927        void genInit( ast::TranslationUnit & translationUnit );
    3028
    3129        /// Converts return statements into copy constructor calls on the hidden return variable.
    3230        /// This pass must happen before auto-gen.
    33         void fixReturnStatements( std::list< Declaration * > & translationUnit );
    3431        void fixReturnStatements( ast::TranslationUnit & translationUnit );
    3532
    3633        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    37         ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );
    3834        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3935
    4036        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
    41         ConstructorInit * genCtorInit( ObjectDecl * objDecl );
    4237        ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
    4338
    44         class ManagedTypes {
    45         public:
    46                 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed
    47                 bool isManaged( Type * type ) const; // determine if type is managed
    48 
    49                 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor
    50                 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed
    51 
    52                 void beginScope();
    53                 void endScope();
    54         private:
    55                 GenPoly::ScopedSet< std::string > managedTypes;
    56         };
    57 
    58         class ManagedTypes_new {
     39        class ManagedTypes final {
    5940        public:
    6041                bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
  • src/InitTweak/InitTweak.cc

    rdf8ba61a r8d182b1  
    2929#include "AST/Type.hpp"
    3030#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
    31 #include "Common/PassVisitor.h"
    3231#include "Common/SemanticError.h"  // for SemanticError
    3332#include "Common/UniqueName.h"     // for UniqueName
     
    3635#include "InitTweak.h"
    3736#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
    38 #include "SymTab/Autogen.h"
    39 #include "SymTab/Indexer.h"        // for Indexer
    40 #include "SynTree/LinkageSpec.h"   // for Spec, isBuiltin, Intrinsic
    41 #include "SynTree/Attribute.h"     // for Attribute
    42 #include "SynTree/Constant.h"      // for Constant
    43 #include "SynTree/Declaration.h"   // for ObjectDecl, DeclarationWithType
    44 #include "SynTree/Expression.h"    // for Expression, UntypedExpr, Applicati...
    45 #include "SynTree/Initializer.h"   // for Initializer, ListInit, Designation
    46 #include "SynTree/Label.h"         // for Label
    47 #include "SynTree/Statement.h"     // for CompoundStmt, ExprStmt, BranchStmt
    48 #include "SynTree/Type.h"          // for FunctionType, ArrayType, PointerType
    49 #include "SynTree/Visitor.h"       // for Visitor, maybeAccept
    5037#include "Tuples/Tuples.h"         // for Tuples::isTtype
    5138
    5239namespace InitTweak {
    5340        namespace {
    54                 struct HasDesignations : public WithShortCircuiting {
    55                         bool hasDesignations = false;
    56 
    57                         void previsit( BaseSyntaxNode * ) {
    58                                 // short circuit if we already know there are designations
    59                                 if ( hasDesignations ) visit_children = false;
    60                         }
    61 
    62                         void previsit( Designation * des ) {
    63                                 // short circuit if we already know there are designations
    64                                 if ( hasDesignations ) visit_children = false;
    65                                 else if ( ! des->get_designators().empty() ) {
    66                                         hasDesignations = true;
    67                                         visit_children = false;
    68                                 }
    69                         }
    70                 };
    71 
    72                 struct InitDepthChecker : public WithGuards {
    73                         bool depthOkay = true;
    74                         Type * type;
    75                         int curDepth = 0, maxDepth = 0;
    76                         InitDepthChecker( Type * type ) : type( type ) {
    77                                 Type * t = type;
    78                                 while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) {
    79                                         maxDepth++;
    80                                         t = at->get_base();
    81                                 }
    82                                 maxDepth++;
    83                         }
    84                         void previsit( ListInit * ) {
    85                                 curDepth++;
    86                                 GuardAction( [this]() { curDepth--; } );
    87                                 if ( curDepth > maxDepth ) depthOkay = false;
    88                         }
    89                 };
    90 
    91                 struct HasDesignations_new : public ast::WithShortCircuiting {
     41                struct HasDesignations : public ast::WithShortCircuiting {
    9242                        bool result = false;
    9343
     
    10757                };
    10858
    109                 struct InitDepthChecker_new {
     59                struct InitDepthChecker {
    11060                        bool result = true;
    11161                        const ast::Type * type;
    11262                        int curDepth = 0, maxDepth = 0;
    113                         InitDepthChecker_new( const ast::Type * type ) : type( type ) {
     63                        InitDepthChecker( const ast::Type * type ) : type( type ) {
    11464                                const ast::Type * t = type;
    11565                                while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
     
    12878                };
    12979
    130                 struct InitFlattener_old : public WithShortCircuiting {
    131                         void previsit( SingleInit * singleInit ) {
    132                                 visit_children = false;
    133                                 argList.push_back( singleInit->value->clone() );
    134                         }
    135                         std::list< Expression * > argList;
    136                 };
    137 
    138                 struct InitFlattener_new : public ast::WithShortCircuiting {
     80                struct InitFlattener : public ast::WithShortCircuiting {
    13981                        std::vector< ast::ptr< ast::Expr > > argList;
    14082
     
    14789        } // anonymous namespace
    14890
    149         std::list< Expression * > makeInitList( Initializer * init ) {
    150                 PassVisitor<InitFlattener_old> flattener;
    151                 maybeAccept( init, flattener );
    152                 return flattener.pass.argList;
    153         }
    154 
    155         bool isDesignated( Initializer * init ) {
    156                 PassVisitor<HasDesignations> finder;
    157                 maybeAccept( init, finder );
    158                 return finder.pass.hasDesignations;
    159         }
    160 
    161         bool checkInitDepth( ObjectDecl * objDecl ) {
    162                 PassVisitor<InitDepthChecker> checker( objDecl->type );
    163                 maybeAccept( objDecl->init, checker );
    164                 return checker.pass.depthOkay;
    165         }
    166 
    16791        bool isDesignated( const ast::Init * init ) {
    168                 ast::Pass<HasDesignations_new> finder;
     92                ast::Pass<HasDesignations> finder;
    16993                maybe_accept( init, finder );
    17094                return finder.core.result;
     
    17296
    17397        bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
    174                 ast::Pass<InitDepthChecker_new> checker( objDecl->type );
     98                ast::Pass<InitDepthChecker> checker( objDecl->type );
    17599                maybe_accept( objDecl->init.get(), checker );
    176100                return checker.core.result;
     
    178102
    179103std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
    180         ast::Pass< InitFlattener_new > flattener;
     104        ast::Pass< InitFlattener > flattener;
    181105        maybe_accept( init, flattener );
    182106        return std::move( flattener.core.argList );
    183107}
    184108
    185         class InitExpander_old::ExpanderImpl {
    186         public:
    187                 virtual ~ExpanderImpl() = default;
    188                 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
    189                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
    190         };
    191 
    192         class InitImpl_old : public InitExpander_old::ExpanderImpl {
    193         public:
    194                 InitImpl_old( Initializer * init ) : init( init ) {}
    195                 virtual ~InitImpl_old() = default;
    196 
    197                 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {
    198                         // this is wrong, but just a placeholder for now
    199                         // if ( ! flattened ) flatten( indices );
    200                         // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
    201                         return makeInitList( init );
    202                 }
    203 
    204                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    205         private:
    206                 Initializer * init;
    207         };
    208 
    209         class ExprImpl_old : public InitExpander_old::ExpanderImpl {
    210         public:
    211                 ExprImpl_old( Expression * expr ) : arg( expr ) {}
    212                 virtual ~ExprImpl_old() { delete arg; }
    213 
    214                 virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
    215                         std::list< Expression * > ret;
    216                         Expression * expr = maybeClone( arg );
    217                         if ( expr ) {
    218                                 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {
    219                                         // go through indices and layer on subscript exprs ?[?]
    220                                         ++it;
    221                                         UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );
    222                                         subscriptExpr->get_args().push_back( expr );
    223                                         subscriptExpr->get_args().push_back( (*it)->clone() );
    224                                         expr = subscriptExpr;
    225                                 }
    226                                 ret.push_back( expr );
    227                         }
    228                         return ret;
    229                 }
    230 
    231                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    232         private:
    233                 Expression * arg;
    234         };
    235 
    236         InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {}
    237 
    238         InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {}
    239 
    240         std::list< Expression * > InitExpander_old::operator*() {
    241                 return cur;
    242         }
    243 
    244         InitExpander_old & InitExpander_old::operator++() {
    245                 cur = expander->next( indices );
    246                 return *this;
    247         }
    248 
    249         // use array indices list to build switch statement
    250         void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) {
    251                 indices.push_back( index );
    252                 indices.push_back( dimension );
    253         }
    254 
    255         void InitExpander_old::clearArrayIndices() {
    256                 deleteAll( indices );
    257                 indices.clear();
    258         }
    259 
    260         bool InitExpander_old::addReference() {
    261                 bool added = false;
    262                 for ( Expression *& expr : cur ) {
    263                         expr = new AddressExpr( expr );
    264                         added = true;
    265                 }
    266                 return added;
    267         }
    268 
    269         namespace {
    270                 /// given index i, dimension d, initializer init, and callExpr f, generates
    271                 ///   if (i < d) f(..., init)
    272                 ///   ++i;
    273                 /// so that only elements within the range of the array are constructed
    274                 template< typename OutIterator >
    275                 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
    276                         UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
    277                         cond->get_args().push_back( index->clone() );
    278                         cond->get_args().push_back( dimension->clone() );
    279 
    280                         std::list< Expression * > args = makeInitList( init );
    281                         callExpr->get_args().splice( callExpr->get_args().end(), args );
    282 
    283                         *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr );
    284 
    285                         UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
    286                         increment->get_args().push_back( index->clone() );
    287                         *out++ = new ExprStmt( increment );
    288                 }
    289 
    290                 template< typename OutIterator >
    291                 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
    292                         if ( idx == idxEnd ) return;
    293                         Expression * index = *idx++;
    294                         assert( idx != idxEnd );
    295                         Expression * dimension = *idx++;
    296 
    297                         // xxx - may want to eventually issue a warning here if we can detect
    298                         // that the number of elements exceeds to dimension of the array
    299                         if ( idx == idxEnd ) {
    300                                 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
    301                                         for ( Initializer * init : *listInit ) {
    302                                                 buildCallExpr( callExpr->clone(), index, dimension, init, out );
    303                                         }
    304                                 } else {
    305                                         buildCallExpr( callExpr->clone(), index, dimension, init, out );
    306                                 }
    307                         } else {
    308                                 std::list< Statement * > branches;
    309 
    310                                 unsigned long cond = 0;
    311                                 ListInit * listInit = dynamic_cast< ListInit * >( init );
    312                                 if ( ! listInit ) {
    313                                         // xxx - this shouldn't be an error, but need a way to
    314                                         // terminate without creating output, so should catch this error
    315                                         SemanticError( init->location, "unbalanced list initializers" );
    316                                 }
    317 
    318                                 static UniqueName targetLabel( "L__autogen__" );
    319                                 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );
    320                                 for ( Initializer * init : *listInit ) {
    321                                         Expression * condition;
    322                                         // check for designations
    323                                         // if ( init-> ) {
    324                                                 condition = new ConstantExpr( Constant::from_ulong( cond ) );
    325                                                 ++cond;
    326                                         // } else {
    327                                         //      condition = // ... take designation
    328                                         //      cond = // ... take designation+1
    329                                         // }
    330                                         std::list< Statement * > stmts;
    331                                         build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
    332                                         stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) );
    333                                         CaseStmt * caseStmt = new CaseStmt( condition, stmts );
    334                                         branches.push_back( caseStmt );
    335                                 }
    336                                 *out++ = new SwitchStmt( index->clone(), branches );
    337                                 *out++ = new NullStmt( { switchLabel } );
    338                         }
    339                 }
    340         }
    341 
    342         // if array came with an initializer list: initialize each element
    343         // may have more initializers than elements in the array - need to check at each index that
    344         // we haven't exceeded size.
    345         // may have fewer initializers than elements in the array - need to default construct
    346         // remaining elements.
    347         // To accomplish this, generate switch statement, consuming all of expander's elements
    348         Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
    349                 if ( ! init ) return nullptr;
    350                 CompoundStmt * block = new CompoundStmt();
    351                 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );
    352                 if ( block->get_kids().empty() ) {
    353                         delete block;
    354                         return nullptr;
    355                 } else {
    356                         init = nullptr; // init was consumed in creating the list init
    357                         return block;
    358                 }
    359         }
    360 
    361         Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
    362                 return nullptr;
    363         }
    364 
    365         Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {
    366                 return expander->buildListInit( dst, indices );
    367         }
    368 
    369 class InitExpander_new::ExpanderImpl {
     109class InitExpander::ExpanderImpl {
    370110public:
    371111        virtual ~ExpanderImpl() = default;
     
    397137        template< typename Out >
    398138        void build(
    399                 ast::UntypedExpr * callExpr, const InitExpander_new::IndexList & indices,
     139                ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices,
    400140                const ast::Init * init, Out & out
    401141        ) {
     
    443183        }
    444184
    445         class InitImpl_new final : public InitExpander_new::ExpanderImpl {
     185        class InitImpl final : public InitExpander::ExpanderImpl {
    446186                ast::ptr< ast::Init > init;
    447187        public:
    448                 InitImpl_new( const ast::Init * i ) : init( i ) {}
    449 
    450                 std::vector< ast::ptr< ast::Expr > > next( InitExpander_new::IndexList & ) override {
     188                InitImpl( const ast::Init * i ) : init( i ) {}
     189
     190                std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override {
    451191                        return makeInitList( init );
    452192                }
    453193
    454194                ast::ptr< ast::Stmt > buildListInit(
    455                         ast::UntypedExpr * callExpr, InitExpander_new::IndexList & indices
     195                        ast::UntypedExpr * callExpr, InitExpander::IndexList & indices
    456196                ) override {
    457197                        // If array came with an initializer list, initialize each element. We may have more
     
    475215        };
    476216
    477         class ExprImpl_new final : public InitExpander_new::ExpanderImpl {
     217        class ExprImpl final : public InitExpander::ExpanderImpl {
    478218                ast::ptr< ast::Expr > arg;
    479219        public:
    480                 ExprImpl_new( const ast::Expr * a ) : arg( a ) {}
     220                ExprImpl( const ast::Expr * a ) : arg( a ) {}
    481221
    482222                std::vector< ast::ptr< ast::Expr > > next(
    483                         InitExpander_new::IndexList & indices
     223                        InitExpander::IndexList & indices
    484224                ) override {
    485225                        if ( ! arg ) return {};
     
    497237
    498238                ast::ptr< ast::Stmt > buildListInit(
    499                         ast::UntypedExpr *, InitExpander_new::IndexList &
     239                        ast::UntypedExpr *, InitExpander::IndexList &
    500240                ) override {
    501241                        return {};
     
    504244} // anonymous namespace
    505245
    506 InitExpander_new::InitExpander_new( const ast::Init * init )
    507 : expander( new InitImpl_new{ init } ), crnt(), indices() {}
    508 
    509 InitExpander_new::InitExpander_new( const ast::Expr * expr )
    510 : expander( new ExprImpl_new{ expr } ), crnt(), indices() {}
    511 
    512 std::vector< ast::ptr< ast::Expr > > InitExpander_new::operator* () { return crnt; }
    513 
    514 InitExpander_new & InitExpander_new::operator++ () {
     246InitExpander::InitExpander( const ast::Init * init )
     247: expander( new InitImpl{ init } ), crnt(), indices() {}
     248
     249InitExpander::InitExpander( const ast::Expr * expr )
     250: expander( new ExprImpl{ expr } ), crnt(), indices() {}
     251
     252std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
     253
     254InitExpander & InitExpander::operator++ () {
    515255        crnt = expander->next( indices );
    516256        return *this;
     
    519259/// builds statement which has the same semantics as a C-style list initializer (for array
    520260/// initializers) using callExpr as the base expression to perform initialization
    521 ast::ptr< ast::Stmt > InitExpander_new::buildListInit( ast::UntypedExpr * callExpr ) {
     261ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
    522262        return expander->buildListInit( callExpr, indices );
    523263}
    524264
    525 void InitExpander_new::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
     265void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
    526266        indices.emplace_back( index );
    527267        indices.emplace_back( dimension );
    528268}
    529269
    530 void InitExpander_new::clearArrayIndices() { indices.clear(); }
    531 
    532 bool InitExpander_new::addReference() {
     270void InitExpander::clearArrayIndices() { indices.clear(); }
     271
     272bool InitExpander::addReference() {
    533273        for ( ast::ptr< ast::Expr > & expr : crnt ) {
    534274                expr = new ast::AddressExpr{ expr };
     
    536276        return ! crnt.empty();
    537277}
    538 
    539         Type * getTypeofThis( FunctionType * ftype ) {
    540                 assertf( ftype, "getTypeofThis: nullptr ftype" );
    541                 ObjectDecl * thisParam = getParamThis( ftype );
    542                 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );
    543                 return refType->base;
    544         }
    545278
    546279        const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
     
    554287        }
    555288
    556         ObjectDecl * getParamThis( FunctionType * ftype ) {
    557                 assertf( ftype, "getParamThis: nullptr ftype" );
    558                 auto & params = ftype->parameters;
    559                 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );
    560                 return strict_dynamic_cast< ObjectDecl * >( params.front() );
    561         }
    562 
    563289        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
    564290                assertf( func, "getParamThis: nullptr ftype" );
     
    566292                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
    567293                return params.front().strict_as<ast::ObjectDecl>();
    568         }
    569 
    570         bool tryConstruct( DeclarationWithType * dwt ) {
    571                 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
    572                 if ( ! objDecl ) return false;
    573                 return (objDecl->get_init() == nullptr ||
    574                                 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))
    575                         && ! objDecl->get_storageClasses().is_extern
    576                         && isConstructable( objDecl->type );
    577         }
    578 
    579         bool isConstructable( Type * type ) {
    580                 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );
    581294        }
    582295
     
    595308        }
    596309
    597         struct CallFinder_old {
    598                 CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
    599 
    600                 void postvisit( ApplicationExpr * appExpr ) {
    601                         handleCallExpr( appExpr );
    602                 }
    603 
    604                 void postvisit( UntypedExpr * untypedExpr ) {
    605                         handleCallExpr( untypedExpr );
    606                 }
    607 
    608                 std::list< Expression * > * matches;
    609         private:
    610                 const std::list< std::string > names;
    611 
    612                 template< typename CallExpr >
    613                 void handleCallExpr( CallExpr * expr ) {
    614                         std::string fname = getFunctionName( expr );
    615                         if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
    616                                 matches->push_back( expr );
    617                         }
    618                 }
    619         };
    620 
    621         struct CallFinder_new final {
     310        struct CallFinder final {
    622311                std::vector< const ast::Expr * > matches;
    623312                const std::vector< std::string > names;
    624313
    625                 CallFinder_new( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
     314                CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
    626315
    627316                void handleCallExpr( const ast::Expr * expr ) {
     
    636325        };
    637326
    638         void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
    639                 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );
    640                 finder.pass.matches = &matches;
    641                 maybeAccept( stmt, finder );
    642         }
    643 
    644327        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    645                 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
     328                ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    646329                maybe_accept( stmt, finder );
    647330                return std::move( finder.core.matches );
    648331        }
    649332
    650         Expression * getCtorDtorCall( Statement * stmt ) {
    651                 std::list< Expression * > matches;
    652                 collectCtorDtorCalls( stmt, matches );
    653                 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );
    654                 return matches.size() == 1 ? matches.front() : nullptr;
    655         }
    656 
    657333        namespace {
    658                 DeclarationWithType * getCalledFunction( Expression * expr );
    659 
    660                 template<typename CallExpr>
    661                 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {
    662                         // (*f)(x) => should get "f"
    663                         std::string name = getFunctionName( expr );
    664                         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
    665                         assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );
    666                         return getCalledFunction( expr->get_args().front() );
    667                 }
    668 
    669                 DeclarationWithType * getCalledFunction( Expression * expr ) {
    670                         assert( expr );
    671                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    672                                 return varExpr->var;
    673                         } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {
    674                                 return memberExpr->member;
    675                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    676                                 return getCalledFunction( castExpr->arg );
    677                         } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {
    678                                 return handleDerefCalledFunction( untypedExpr );
    679                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
    680                                 return handleDerefCalledFunction( appExpr );
    681                         } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
    682                                 return getCalledFunction( addrExpr->arg );
    683                         } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {
    684                                 return getCalledFunction( commaExpr->arg2 );
    685                         }
    686                         return nullptr;
    687                 }
    688 
    689                 DeclarationWithType * getFunctionCore( const Expression * expr ) {
    690                         if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) {
    691                                 return getCalledFunction( appExpr->function );
    692                         } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
    693                                 return getCalledFunction( untyped->function );
    694                         }
    695                         assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() );
    696                 }
    697         }
    698 
    699         DeclarationWithType * getFunction( Expression * expr ) {
    700                 return getFunctionCore( expr );
    701         }
    702 
    703         const DeclarationWithType * getFunction( const Expression * expr ) {
    704                 return getFunctionCore( expr );
    705         }
    706 
    707         ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {
    708                 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );
    709                 if ( ! appExpr ) return nullptr;
    710                 DeclarationWithType * function = getCalledFunction( appExpr->get_function() );
    711                 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );
    712                 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
    713                 // will call all member dtors, and some members may have a user defined dtor.
    714                 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;
    715         }
    716 
    717         namespace {
    718                 template <typename Predicate>
    719                 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {
    720                         std::list< Expression * > callExprs;
    721                         collectCtorDtorCalls( stmt, callExprs );
    722                         return std::all_of( callExprs.begin(), callExprs.end(), pred);
    723                 }
    724 
    725334                template <typename Predicate>
    726335                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
     
    728337                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    729338                }
    730         }
    731 
    732         bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
    733                 return allofCtorDtor( stmt, []( Expression * callExpr ){
    734                         if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
    735                                 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result );
    736                                 assert( funcType );
    737                                 return funcType->get_parameters().size() == 1;
    738                         }
    739                         return false;
    740                 });
    741339        }
    742340
     
    751349                        return false;
    752350                });
    753         }
    754 
    755         bool isIntrinsicCallStmt( Statement * stmt ) {
    756                 return allofCtorDtor( stmt, []( Expression * callExpr ) {
    757                         return isIntrinsicCallExpr( callExpr );
    758                 });
    759         }
    760 
    761         namespace {
    762                 template<typename CallExpr>
    763                 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {
    764                         if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );
    765                         for ( Expression *& arg : callExpr->get_args() ) {
    766                                 if ( pos == 0 ) return arg;
    767                                 pos--;
    768                         }
    769                         assert( false );
    770                 }
    771         }
    772 
    773         Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {
    774                 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {
    775                         return callArg( appExpr, pos );
    776                 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {
    777                         return callArg( untypedExpr, pos );
    778                 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {
    779                         std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();
    780                         assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );
    781                         ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );
    782                         TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );
    783                         assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );
    784                         return getCallArg( tuple->get_exprs().front(), pos );
    785                 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {
    786                         return getCallArg( copyCtor->callExpr, pos );
    787                 } else {
    788                         assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
    789                 }
    790         }
    791 
    792         namespace {
    793                 std::string funcName( Expression * func );
    794 
    795                 template<typename CallExpr>
    796                 std::string handleDerefName( CallExpr * expr ) {
    797                         // (*f)(x) => should get name "f"
    798                         std::string name = getFunctionName( expr );
    799                         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
    800                         assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );
    801                         return funcName( expr->get_args().front() );
    802                 }
    803 
    804                 std::string funcName( Expression * func ) {
    805                         if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {
    806                                 return nameExpr->get_name();
    807                         } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {
    808                                 return varExpr->get_var()->get_name();
    809                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {
    810                                 return funcName( castExpr->get_arg() );
    811                         } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {
    812                                 return memberExpr->get_member()->get_name();
    813                         } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {
    814                                 return funcName( memberExpr->get_member() );
    815                         } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {
    816                                 return handleDerefName( untypedExpr );
    817                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {
    818                                 return handleDerefName( appExpr );
    819                         } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {
    820                                 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );
    821                         } else {
    822                                 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
    823                         }
    824                 }
    825         }
    826 
    827         std::string getFunctionName( Expression * expr ) {
    828                 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and
    829                 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction
    830                 // can't possibly do anything reasonable.
    831                 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {
    832                         return funcName( appExpr->get_function() );
    833                 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {
    834                         return funcName( untypedExpr->get_function() );
    835                 } else {
    836                         std::cerr << expr << std::endl;
    837                         assertf( false, "Unexpected expression type passed to getFunctionName" );
    838                 }
    839         }
    840 
    841         Type * getPointerBase( Type * type ) {
    842                 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {
    843                         return ptrType->get_base();
    844                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    845                         return arrayType->get_base();
    846                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {
    847                         return refType->get_base();
    848                 } else {
    849                         return nullptr;
    850                 }
    851         }
    852 
    853         Type * isPointerType( Type * type ) {
    854                 return getPointerBase( type ) ? type : nullptr;
    855         }
    856 
    857         ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {
    858                 static FunctionDecl * assign = nullptr;
    859                 if ( ! assign ) {
    860                         // temporary? Generate a fake assignment operator to represent bitwise assignments.
    861                         // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.
    862                         TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );
    863                         assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );
    864                 }
    865                 if ( dynamic_cast< ReferenceType * >( dst->result ) ) {
    866                         for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
    867                                 dst = new AddressExpr( dst );
    868                         }
    869                 } else {
    870                         dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );
    871                 }
    872                 if ( dynamic_cast< ReferenceType * >( src->result ) ) {
    873                         for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
    874                                 src = new AddressExpr( src );
    875                         }
    876                 }
    877                 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );
    878351        }
    879352
     
    908381        }
    909382
    910         struct ConstExprChecker : public WithShortCircuiting {
    911                 // most expressions are not const expr
    912                 void previsit( Expression * ) { isConstExpr = false; visit_children = false; }
    913 
    914                 void previsit( AddressExpr *addressExpr ) {
    915                         visit_children = false;
    916 
    917                         // address of a variable or member expression is constexpr
    918                         Expression * arg = addressExpr->get_arg();
    919                         if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false;
    920                 }
    921 
    922                 // these expressions may be const expr, depending on their children
    923                 void previsit( SizeofExpr * ) {}
    924                 void previsit( AlignofExpr * ) {}
    925                 void previsit( UntypedOffsetofExpr * ) {}
    926                 void previsit( OffsetofExpr * ) {}
    927                 void previsit( OffsetPackExpr * ) {}
    928                 void previsit( CommaExpr * ) {}
    929                 void previsit( LogicalExpr * ) {}
    930                 void previsit( ConditionalExpr * ) {}
    931                 void previsit( CastExpr * ) {}
    932                 void previsit( ConstantExpr * ) {}
    933 
    934                 void previsit( VariableExpr * varExpr ) {
    935                         visit_children = false;
    936 
    937                         if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) {
    938                                 long long int value;
    939                                 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    940                                         // enumerators are const expr
    941                                         return;
    942                                 }
    943                         }
    944                         isConstExpr = false;
    945                 }
    946 
    947                 bool isConstExpr = true;
    948         };
    949 
    950         struct ConstExprChecker_new : public ast::WithShortCircuiting {
     383        struct ConstExprChecker : public ast::WithShortCircuiting {
    951384                // most expressions are not const expr
    952385                void previsit( const ast::Expr * ) { result = false; visit_children = false; }
     
    991424        };
    992425
    993         bool isConstExpr( Expression * expr ) {
    994                 if ( expr ) {
    995                         PassVisitor<ConstExprChecker> checker;
    996                         expr->accept( checker );
    997                         return checker.pass.isConstExpr;
    998                 }
    999                 return true;
    1000         }
    1001 
    1002         bool isConstExpr( Initializer * init ) {
    1003                 if ( init ) {
    1004                         PassVisitor<ConstExprChecker> checker;
    1005                         init->accept( checker );
    1006                         return checker.pass.isConstExpr;
    1007                 } // if
    1008                 // for all intents and purposes, no initializer means const expr
    1009                 return true;
    1010         }
    1011 
    1012426        bool isConstExpr( const ast::Expr * expr ) {
    1013427                if ( expr ) {
    1014                         ast::Pass<ConstExprChecker_new> checker;
     428                        ast::Pass<ConstExprChecker> checker;
    1015429                        expr->accept( checker );
    1016430                        return checker.core.result;
     
    1021435        bool isConstExpr( const ast::Init * init ) {
    1022436                if ( init ) {
    1023                         ast::Pass<ConstExprChecker_new> checker;
     437                        ast::Pass<ConstExprChecker> checker;
    1024438                        init->accept( checker );
    1025439                        return checker.core.result;
     
    1029443        }
    1030444
    1031         const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {
    1032                 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );
    1033                 if ( ! function ) return nullptr;
    1034                 if ( function->name != fname ) return nullptr;
    1035                 FunctionType * ftype = function->type;
    1036                 if ( ftype->parameters.size() != 2 ) return nullptr;
    1037 
    1038                 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );
    1039                 Type * t2 = ftype->parameters.back()->get_type();
    1040                 assert( t1 );
    1041 
    1042                 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {
    1043                         return function;
    1044                 } else {
    1045                         return nullptr;
    1046                 }
    1047         }
    1048 
    1049445bool isAssignment( const ast::FunctionDecl * decl ) {
    1050446        return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
     
    1073469        return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
    1074470}
    1075 
    1076 
    1077         const FunctionDecl * isAssignment( const Declaration * decl ) {
    1078                 return isCopyFunction( decl, "?=?" );
    1079         }
    1080         const FunctionDecl * isDestructor( const Declaration * decl ) {
    1081                 if ( CodeGen::isDestructor( decl->name ) ) {
    1082                         return dynamic_cast< const FunctionDecl * >( decl );
    1083                 }
    1084                 return nullptr;
    1085         }
    1086         const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {
    1087                 if ( CodeGen::isConstructor( decl->name ) ) {
    1088                         if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {
    1089                                 if ( func->type->parameters.size() == 1 ) {
    1090                                         return func;
    1091                                 }
    1092                         }
    1093                 }
    1094                 return nullptr;
    1095         }
    1096         const FunctionDecl * isCopyConstructor( const Declaration * decl ) {
    1097                 return isCopyFunction( decl, "?{}" );
    1098         }
    1099471
    1100472        #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
     
    1105477        static const char * const data_section =  ".data" ASM_COMMENT;
    1106478        static const char * const tlsd_section = ".tdata" ASM_COMMENT;
    1107         void addDataSectionAttribute( ObjectDecl * objDecl ) {
    1108                 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();
    1109                 const char * section = is_tls ? tlsd_section : data_section;
    1110                 objDecl->attributes.push_back(new Attribute("section", {
    1111                         new ConstantExpr( Constant::from_string( section ) )
    1112                 }));
    1113         }
    1114479
    1115480        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
     
    1121486        }
    1122487
    1123 }
     488} // namespace InitTweak
  • src/InitTweak/InitTweak.h

    rdf8ba61a r8d182b1  
    2222
    2323#include "AST/Fwd.hpp"        // for AST nodes
    24 #include "SynTree/SynTree.h"  // for Visitor Nodes
    2524
    2625// helper functions for initialization
    2726namespace InitTweak {
    28         const FunctionDecl * isAssignment( const Declaration * decl );
    29         const FunctionDecl * isDestructor( const Declaration * decl );
    30         const FunctionDecl * isDefaultConstructor( const Declaration * decl );
    31         const FunctionDecl * isCopyConstructor( const Declaration * decl );
    32         const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname );
    3327        bool isAssignment( const ast::FunctionDecl * decl );
    3428        bool isDestructor( const ast::FunctionDecl * decl );
     
    3832
    3933        /// returns the base type of the first parameter to a constructor/destructor/assignment function
    40         Type * getTypeofThis( FunctionType * ftype );
    4134        const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
    4235
    4336        /// returns the first parameter of a constructor/destructor/assignment function
    44         ObjectDecl * getParamThis( FunctionType * ftype );
    4537        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4638
    4739        /// generate a bitwise assignment operation.
    48         ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
    49 
    5040        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    5141
    5242        /// transform Initializer into an argument list that can be passed to a call expression
    53         std::list< Expression * > makeInitList( Initializer * init );
    5443        std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    5544
    5645        /// True if the resolver should try to construct dwt
    57         bool tryConstruct( DeclarationWithType * dwt );
    5846        bool tryConstruct( const ast::DeclWithType * dwt );
    5947
    6048        /// True if the type can have a user-defined constructor
    61         bool isConstructable( Type * t );
    6249        bool isConstructable( const ast::Type * t );
    6350
    6451        /// True if the Initializer contains designations
    65         bool isDesignated( Initializer * init );
    6652        bool isDesignated( const ast::Init * init );
    6753
    6854        /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    6955        /// type, where the depth of its type is the number of nested ArrayTypes + 1
    70         bool checkInitDepth( ObjectDecl * objDecl );
    7156        bool checkInitDepth( const ast::ObjectDecl * objDecl );
    72 
    73         /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
    74         DeclarationWithType * getFunction( Expression * expr );
    75         const DeclarationWithType * getFunction( const Expression * expr );
    76 
    77         /// Non-Null if expr is a call expression whose target function is intrinsic
    78         ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
    7957
    8058        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    8159        /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    8260        /// Currently has assertions that make it less than fully general.
    83         bool isIntrinsicSingleArgCallStmt( Statement * stmt );
    8461        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
    8562
    86         /// True if stmt is a call statement where the function called is intrinsic.
    87         bool isIntrinsicCallStmt( Statement * stmt );
    88 
    8963        /// get all Ctor/Dtor call expressions from a Statement
    90         void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    9164        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    9265
    93         /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
    94         Expression * getCtorDtorCall( Statement * stmt );
    95 
    96         /// returns the name of the function being called
    97         std::string getFunctionName( Expression * expr );
    98 
    99         /// returns the argument to a call expression in position N indexed from 0
    100         Expression *& getCallArg( Expression * callExpr, unsigned int pos );
    101 
    102         /// returns the base type of a PointerType or ArrayType, else returns NULL
    103         Type * getPointerBase( Type * );
    104 
    105         /// returns the argument if it is a PointerType or ArrayType, else returns NULL
    106         Type * isPointerType( Type * );
    107 
    10866        /// returns true if expr is trivially a compile-time constant
    109         bool isConstExpr( Expression * expr );
    110         bool isConstExpr( Initializer * init );
    111 
    11267        bool isConstExpr( const ast::Expr * expr );
    11368        bool isConstExpr( const ast::Init * init );
     
    12277        ///    .section .data#,"a"
    12378        /// to avoid assembler warning "ignoring changed section attributes for .data"
    124         void addDataSectionAttribute( ObjectDecl * objDecl );
    125 
    12679        void addDataSectionAttribute( ast::ObjectDecl * objDecl );
    12780
    128         class InitExpander_old {
    129         public:
    130                 // expand by stepping through init to get each list of arguments
    131                 InitExpander_old( Initializer * init );
    132 
    133                 // always expand to expr
    134                 InitExpander_old( Expression * expr );
    135 
    136                 // iterator-like interface
    137                 std::list< Expression * > operator*();
    138                 InitExpander_old & operator++();
    139 
    140                 // builds statement which has the same semantics as a C-style list initializer
    141                 // (for array initializers) using callExpr as the base expression to perform initialization
    142                 Statement * buildListInit( UntypedExpr * callExpr );
    143                 void addArrayIndex( Expression * index, Expression * dimension );
    144                 void clearArrayIndices();
    145                 bool addReference();
    146 
    147                 class ExpanderImpl;
    148 
    149                 typedef std::list< Expression * > IndexList;
    150         private:
    151                 std::shared_ptr< ExpanderImpl > expander;
    152                 std::list< Expression * > cur;
    153 
    154                 // invariant: list of size 2N (elements come in pairs [index, dimension])
    155                 IndexList indices;
    156         };
    157 
    158         class InitExpander_new {
     81        class InitExpander final {
    15982        public:
    16083                using IndexList = std::vector< ast::ptr< ast::Expr > >;
     
    16992        public:
    17093                /// Expand by stepping through init to get each list of arguments
    171                 InitExpander_new( const ast::Init * init );
     94                InitExpander( const ast::Init * init );
    17295
    17396                /// Always expand to expression
    174                 InitExpander_new( const ast::Expr * expr );
     97                InitExpander( const ast::Expr * expr );
    17598
    17699                std::vector< ast::ptr< ast::Expr > > operator* ();
    177                 InitExpander_new & operator++ ();
     100                InitExpander & operator++ ();
    178101
    179102                /// builds statement which has the same semantics as a C-style list initializer (for array
     
    188111                bool addReference();
    189112        };
    190 } // namespace
     113} // namespace InitTweak
    191114
    192115// Local Variables: //
  • src/InitTweak/module.mk

    rdf8ba61a r8d182b1  
    2424        InitTweak/FixGlobalInit.cc \
    2525        InitTweak/FixGlobalInit.h \
    26         InitTweak/FixInit.cc \
    2726        InitTweak/FixInit.h \
    2827        InitTweak/FixInitNew.cpp
  • src/MakeLibCfa.h

    rdf8ba61a r8d182b1  
    2424
    2525namespace LibCfa {
    26         void makeLibCfa( std::list< Declaration* > &prelude );
    2726        void makeLibCfa( ast::TranslationUnit & translationUnit );
    2827} // namespace LibCfa
  • src/Makefile.am

    rdf8ba61a r8d182b1  
    2222      CompilationState.cc \
    2323      CompilationState.h \
    24       MakeLibCfa.cc \
    2524          MakeLibCfaNew.cpp \
    2625        MakeLibCfa.h
     
    4241include AST/module.mk
    4342include CodeGen/module.mk
    44 include CodeTools/module.mk
    4543include Concurrency/module.mk
    4644include Common/module.mk
     
    5149include ResolvExpr/module.mk
    5250include SymTab/module.mk
    53 include SynTree/module.mk
    5451include Tuples/module.mk
    5552include Validate/module.mk
    5653include Virtual/module.mk
    5754
    58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h
     55$(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp
    5956
    6057$(srcdir)/AST/Type.hpp : BasicTypes-gen.cc
  • src/Parser/RunParser.cpp

    rdf8ba61a r8d182b1  
    1616#include "RunParser.hpp"
    1717
    18 #include "AST/Convert.hpp"                  // for convert
    1918#include "AST/TranslationUnit.hpp"          // for TranslationUnit
    20 #include "CodeTools/TrackLoc.h"             // for fillLocations
    2119#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    2220#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
  • src/Parser/parser.yy

    rdf8ba61a r8d182b1  
    5757#include "Common/SemanticError.h"                                               // error_str
    5858#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    59 
    60 #include "SynTree/Attribute.h"                                                  // for Attribute
    6159
    6260// lex uses __null in a boolean context, it's fine.
  • src/ResolvExpr/AdjustExprType.cc

    rdf8ba61a r8d182b1  
    1919#include "AST/Type.hpp"
    2020#include "AST/TypeEnvironment.hpp"
    21 #include "Common/PassVisitor.h"
    22 #include "SymTab/Indexer.h"       // for Indexer
    23 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Kind::Ftype
    24 #include "SynTree/Mutator.h"      // for Mutator
    25 #include "SynTree/Type.h"         // for PointerType, TypeInstType, Type
    26 #include "TypeEnvironment.h"      // for EqvClass, TypeEnvironment
    2721
    2822namespace ResolvExpr {
    2923
    3024namespace {
    31         class AdjustExprType_old final : public WithShortCircuiting {
    32                 public:
    33                 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );
    34                 void premutate( VoidType * ) { visit_children = false; }
    35                 void premutate( BasicType * ) { visit_children = false; }
    36                 void premutate( PointerType * ) { visit_children = false; }
    37                 void premutate( ArrayType * ) { visit_children = false; }
    38                 void premutate( FunctionType * ) { visit_children = false; }
    39                 void premutate( StructInstType * ) { visit_children = false; }
    40                 void premutate( UnionInstType * ) { visit_children = false; }
    41                 void premutate( EnumInstType * ) { visit_children = false; }
    42                 void premutate( TraitInstType * ) { visit_children = false; }
    43                 void premutate( TypeInstType * ) { visit_children = false; }
    44                 void premutate( TupleType * ) { visit_children = false; }
    45                 void premutate( VarArgsType * ) { visit_children = false; }
    46                 void premutate( ZeroType * ) { visit_children = false; }
    47                 void premutate( OneType * ) { visit_children = false; }
    48 
    49                 Type * postmutate( ArrayType * arrayType );
    50                 Type * postmutate( FunctionType * functionType );
    51                 Type * postmutate( TypeInstType * aggregateUseType );
    52 
    53                 private:
    54                 const TypeEnvironment & env;
    55                 const SymTab::Indexer & indexer;
    56         };
    57 
    58         AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )
    59                 : env( env ), indexer( indexer ) {
    60         }
    61 
    62         Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {
    63                 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
    64                 arrayType->base = nullptr;
    65                 delete arrayType;
    66                 return pointerType;
    67         }
    68 
    69         Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {
    70                 return new PointerType{ Type::Qualifiers(), functionType };
    71         }
    72 
    73         Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {
    74                 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    75                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    76                                 return new PointerType{ Type::Qualifiers(), typeInst };
    77                         }
    78                 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) {
    79                         if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) {
    80                                 if ( tyDecl->get_kind() == TypeDecl::Ftype ) {
    81                                         return new PointerType{ Type::Qualifiers(), typeInst };
    82                                 } // if
    83                         } // if
    84                 } // if
    85                 return typeInst;
    86         }
    87 } // anonymous namespace
    88 
    89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    90         PassVisitor<AdjustExprType_old> adjuster( env, indexer );
    91         Type * newType = type->acceptMutator( adjuster );
    92         type = newType;
    93 }
    94 
    95 void adjustExprType( Type *& type ) {
    96         TypeEnvironment env;
    97         SymTab::Indexer indexer;
    98         adjustExprType( type, env, indexer );
    99 }
    100 
    101 namespace {
    102         class AdjustExprType_new final : public ast::WithShortCircuiting {
     25        class AdjustExprType final : public ast::WithShortCircuiting {
    10326                const ast::SymbolTable & symtab;
    10427        public:
    10528                const ast::TypeEnvironment & tenv;
    10629
    107                 AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
     30                AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    10831                : symtab( syms ), tenv( e ) {}
    10932
     
    15275        const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
    15376) {
    154         ast::Pass<AdjustExprType_new> adjuster{ env, symtab };
     77        ast::Pass<AdjustExprType> adjuster{ env, symtab };
    15578        return type->accept( adjuster );
    15679}
  • src/ResolvExpr/AdjustExprType.hpp

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 class Type;
    19 namespace SymTab {
    20         class Indexer;
    21 }
    2218namespace ast {
    2319        class SymbolTable;
     
    2723
    2824namespace ResolvExpr {
    29 
    30 class TypeEnvironment;
    31 
    32 /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function
    33 void adjustExprType( Type *& type, const TypeEnvironment & env, const SymTab::Indexer & indexer );
    34 
    35 /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function using empty TypeEnvironment and Indexer.
    36 void adjustExprType( Type *& type );
    37 
    38 template< typename ForwardIterator >
    39 void adjustExprTypeList( ForwardIterator begin, ForwardIterator end, const TypeEnvironment & env, const SymTab::Indexer & indexer ) {
    40         while ( begin != end ) {
    41                 adjustExprType( *begin++, env, indexer );
    42         } // while
    43 }
    4425
    4526/// Replaces array types with equivalent pointer,
  • src/ResolvExpr/CandidateFinder.cpp

    rdf8ba61a r8d182b1  
    6161namespace {
    6262        /// First index is which argument, second is which alternative, third is which exploded element
    63         using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     63        using ExplodedArgs = std::deque< std::vector< ExplodedArg > >;
    6464
    6565        /// Returns a list of alternatives with the minimum cost in the given list
     
    255255
    256256                /// Gets the list of exploded candidates for this pack
    257                 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
     257                const ExplodedArg & getExpl( const ExplodedArgs & args ) const {
    258258                        return args[ nextArg-1 ][ explAlt ];
    259259                }
     
    281281        bool instantiateArgument(
    282282                const CodeLocation & location,
    283                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     283                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs & args,
    284284                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    285285                unsigned nTuples = 0
     
    618618                        const CodeLocation & location,
    619619                        const CandidateRef & func, const ast::FunctionType * funcType,
    620                         const ExplodedArgs_new & args, CandidateList & out );
     620                        const ExplodedArgs & args, CandidateList & out );
    621621
    622622                /// Adds implicit struct-conversions to the alternative list
     
    737737                const CodeLocation & location,
    738738                const CandidateRef & func, const ast::FunctionType * funcType,
    739                 const ExplodedArgs_new & args, CandidateList & out
     739                const ExplodedArgs & args, CandidateList & out
    740740        ) {
    741741                ast::OpenVarSet funcOpen;
     
    997997
    998998                // pre-explode arguments
    999                 ExplodedArgs_new argExpansions;
     999                ExplodedArgs argExpansions;
    10001000                for ( const CandidateFinder & args : argCandidates ) {
    10011001                        argExpansions.emplace_back();
  • src/ResolvExpr/CastCost.cc

    rdf8ba61a r8d182b1  
    2626#include "ResolvExpr/ConversionCost.h"   // for conversionCost
    2727#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
    28 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, EqvClass
    29 #include "ResolvExpr/typeops.h"          // for ptrsCastable
    3028#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    31 #include "SymTab/Indexer.h"              // for Indexer
    32 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    33 #include "SynTree/Type.h"                // for PointerType, Type, TypeInstType
    3429
    3530#if 0
     
    4035
    4136namespace ResolvExpr {
    42         struct CastCost_old : public ConversionCost {
    43           public:
    44                 CastCost_old( const Type * dest, bool srcIsLvalue,
    45                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );
    4637
     38namespace {
     39        struct CastCost : public ConversionCost {
    4740                using ConversionCost::previsit;
    4841                using ConversionCost::postvisit;
    49                 void postvisit( const BasicType * basicType );
    50                 void postvisit( const PointerType * pointerType );
    51         };
    5242
    53         Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
    54                         const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    55                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    56                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    57                                 if ( eqvClass->type ) {
    58                                         return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    59                                 } else {
    60                                         return Cost::infinity;
    61                                 }
    62                         } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    63                                 // all typedefs should be gone by this point
    64                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );
    65                                 if ( type->base ) {
    66                                         return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;
    67                                 } // if
    68                         } // if
    69                 } // if
    70 
    71                 PRINT(
    72                         std::cerr << "castCost ::: src is ";
    73                         src->print( std::cerr );
    74                         std::cerr << std::endl << "dest is ";
    75                         dest->print( std::cerr );
    76                         std::cerr << std::endl << "env is" << std::endl;
    77                         env.print( std::cerr, 8 );
    78                 )
    79 
    80                 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    81                         PRINT( std::cerr << "compatible!" << std::endl; )
    82                         return Cost::zero;
    83                 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    84                         return Cost::safe;
    85                 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    86                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    87                         return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    88                                 return ptrsCastable( t1, t2, env, indexer );
    89                         });
    90                 } else {
    91                         PassVisitor<CastCost_old> converter(
    92                                 dest, srcIsLvalue, indexer, env,
    93                                 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))
    94                                         castCost );
    95                         src->accept( converter );
    96                         if ( converter.pass.get_cost() == Cost::infinity ) {
    97                                 return Cost::infinity;
    98                         } else {
    99                                 // xxx - why are we adding cost 0 here?
    100                                 return converter.pass.get_cost() + Cost::zero;
    101                         } // if
    102                 } // if
    103         }
    104 
    105         CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,
    106                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    107                 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {
    108         }
    109 
    110         void CastCost_old::postvisit( const BasicType * basicType ) {
    111                 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );
    112                 if ( destAsPointer && basicType->isInteger() ) {
    113                         // necessary for, e.g. unsigned long => void *
    114                         cost = Cost::unsafe;
    115                 } else {
    116                         cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );
    117                 } // if
    118         }
    119 
    120         void CastCost_old::postvisit( const PointerType * pointerType ) {
    121                 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    122                         if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    123                                 cost = Cost::safe;
    124                         } else {
    125                                 TypeEnvironment newEnv( env );
    126                                 newEnv.add( pointerType->forall );
    127                                 newEnv.add( pointerType->base->forall );
    128                                 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer );
    129                                 if ( castResult > 0 ) {
    130                                         cost = Cost::safe;
    131                                 } else if ( castResult < 0 ) {
    132                                         cost = Cost::infinity;
    133                                 } // if
    134                         } // if
    135                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    136                         if ( destAsBasic->isInteger() ) {
    137                                 // necessary for, e.g. void * => unsigned long
    138                                 cost = Cost::unsafe;
    139                         } // if
    140                 }
    141         }
    142 
    143 namespace {
    144         struct CastCost_new : public ConversionCost_new {
    145                 using ConversionCost_new::previsit;
    146                 using ConversionCost_new::postvisit;
    147 
    148                 CastCost_new(
     43                CastCost(
    14944                        const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
    15045                        const ast::TypeEnvironment & env, CostCalculation costFunc )
    151                 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
     46                : ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
    15247
    15348                void postvisit( const ast::BasicType * basicType ) {
     
    18984        };
    19085
    191         #warning For overload resolution between the two versions.
    192         int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
    193                         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
    194                 return ptrsCastable( t1, t2, symtab, env );
    195         }
    196         Cost localCastCost(
    197                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    198                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    199         ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
    20086} // anonymous namespace
    201 
    202 
    20387
    20488Cost castCost(
     
    242126        } else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) {
    243127                PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    244                 #warning cast on ptrsCastable artifact of having two functions, remove when port done
    245128                return convertToReferenceCost(
    246                         src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
     129                        src, refType, srcIsLvalue, symtab, env, ptrsCastable );
    247130        } else {
    248                 #warning cast on castCost artifact of having two functions, remove when port done
    249                 ast::Pass< CastCost_new > converter(
    250                         dst, srcIsLvalue, symtab, env, localCastCost );
     131                ast::Pass< CastCost > converter(
     132                        dst, srcIsLvalue, symtab, env, castCost );
    251133                src->accept( converter );
    252134                return converter.core.cost;
  • src/ResolvExpr/CastCost.hpp

    rdf8ba61a r8d182b1  
    1818#include "ResolvExpr/Cost.h"     // for Cost
    1919
    20 class Type;
    21 namespace SymTab {
    22         class Indexer;
    23 }
    2420namespace ast {
    2521        class SymbolTable;
     
    3026namespace ResolvExpr {
    3127
    32 class TypeEnvironment;
    33 
    34 Cost castCost(
    35         const Type * src, const Type * dest, bool srcIsLvalue,
    36         const SymTab::Indexer & indexer, const TypeEnvironment & env );
    3728Cost castCost(
    3829        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
  • src/ResolvExpr/CommonType.cc

    rdf8ba61a r8d182b1  
    2323#include "AST/Pass.hpp"
    2424#include "AST/Type.hpp"
    25 #include "Common/PassVisitor.h"
    26 #include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
    27 #include "SymTab/Indexer.h"              // for Indexer
    28 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl (ptr...
    29 #include "SynTree/Type.h"                // for BasicType, BasicType::Kind::...
    30 #include "SynTree/Visitor.h"             // for Visitor
    3125#include "Unify.h"                       // for unifyExact, WidenMode
    3226#include "typeops.h"                     // for isFtype
     
    4135
    4236namespace ResolvExpr {
    43         struct CommonType_old : public WithShortCircuiting {
    44                 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
    45                 Type * get_result() const { return result; }
    46 
    47                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
    48 
    49                 void postvisit( VoidType * voidType );
    50                 void postvisit( BasicType * basicType );
    51                 void postvisit( PointerType * pointerType );
    52                 void postvisit( ArrayType * arrayType );
    53                 void postvisit( ReferenceType * refType );
    54                 void postvisit( FunctionType * functionType );
    55                 void postvisit( StructInstType * aggregateUseType );
    56                 void postvisit( UnionInstType * aggregateUseType );
    57                 void postvisit( EnumInstType * aggregateUseType );
    58                 void postvisit( TraitInstType * aggregateUseType );
    59                 void postvisit( TypeInstType * aggregateUseType );
    60                 void postvisit( TupleType * tupleType );
    61                 void postvisit( VarArgsType * varArgsType );
    62                 void postvisit( ZeroType * zeroType );
    63                 void postvisit( OneType * oneType );
    64 
    65           private:
    66                 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );
    67                 template< typename RefType > void handleRefType( RefType * inst, Type * other );
    68 
    69                 Type * result;
    70                 Type * type2;                           // inherited
    71                 bool widenFirst, widenSecond;
    72                 const SymTab::Indexer &indexer;
    73                 TypeEnvironment &env;
    74                 const OpenVarSet &openVars;
    75         };
    76 
    77         Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {
    78                 Type * common = nullptr;
    79                 AssertionSet have, need;
    80                 OpenVarSet newOpen( openVars );
    81                 // need unify to bind type variables
    82                 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {
    83                         PRINT(
    84                                 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
    85                         )
    86                         if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {
    87                                 PRINT(
    88                                         std::cerr << "widen okay" << std::endl;
    89                                 )
    90                                 common->tq |= t1->tq;
    91                                 common->tq |= t2->tq;
    92                                 return common;
    93                         }
    94                 }
    95                 PRINT(
    96                         std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
    97                 )
    98                 return nullptr;
    99         }
    100 
    101         Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
    102                 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
    103 
    104                 int depth1 = type1->referenceDepth();
    105                 int depth2 = type2->referenceDepth();
    106                 if ( depth1 > 0 || depth2 > 0 ) {
    107                         int diff = depth1-depth2;
    108                         // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.
    109                         // if ( diff > 1 || diff < -1 ) return nullptr;
    110 
    111                         // special case where one type has a reference depth of 1 larger than the other
    112                         if ( diff > 0 || diff < 0 ) {
    113                                 PRINT(
    114                                         std::cerr << "reference depth diff: " << diff << std::endl;
    115                                 )
    116                                 Type * result = nullptr;
    117                                 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );
    118                                 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );
    119                                 if ( diff > 0 ) {
    120                                         // deeper on the left
    121                                         assert( ref1 );
    122                                         result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );
    123                                 } else {
    124                                         // deeper on the right
    125                                         assert( ref2 );
    126                                         result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );
    127                                 }
    128                                 if ( result && ref1 ) {
    129                                         // formal is reference, so result should be reference
    130                                         PRINT(
    131                                                 std::cerr << "formal is reference; result should be reference" << std::endl;
    132                                         )
    133                                         result = new ReferenceType( ref1->tq, result );
    134                                 }
    135                                 PRINT(
    136                                         std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;
    137                                 )
    138                                 return result;
    139                         }
    140                         // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.
    141                 }
    142 
    143                 type1->accept( visitor );
    144                 Type * result = visitor.pass.get_result();
    145                 if ( ! result ) {
    146                         // this appears to be handling for opaque type declarations
    147                         if ( widenSecond ) {
    148                                 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {
    149                                         if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {
    150                                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    151                                                 if ( type->get_base() ) {
    152                                                         Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;
    153                                                         AssertionSet have, need;
    154                                                         OpenVarSet newOpen( openVars );
    155                                                         type1->tq = Type::Qualifiers();
    156                                                         type->get_base()->tq = tq1;
    157                                                         if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {
    158                                                                 result = type1->clone();
    159                                                                 result->tq = tq1 | tq2;
    160                                                         } // if
    161                                                         type1->tq = tq1;
    162                                                         type->get_base()->tq = Type::Qualifiers();
    163                                                 } // if
    164                                         } // if
    165                                 } // if
    166                         } // if
    167                 } // if
    168 #ifdef DEBUG
    169                 std::cerr << "============= commonType" << std::endl << "type1 is ";
    170                 type1->print( std::cerr );
    171                 std::cerr << " type2 is ";
    172                 type2->print( std::cerr );
    173                 if ( result ) {
    174                         std::cerr << " common type is ";
    175                         result->print( std::cerr );
    176                 } else {
    177                         std::cerr << " no common type";
    178                 } // if
    179                 std::cerr << std::endl;
    180 #endif
    181                 return result;
    182         }
    18337
    18438        // GENERATED START, DO NOT EDIT
     
    489343        );
    490344
    491         CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )
    492                 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) {
    493         }
    494 
    495         void CommonType_old::postvisit( VoidType * ) {}
    496 
    497         void CommonType_old::postvisit( BasicType * basicType ) {
    498                 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) {
    499                         BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ (ast::BasicType::Kind)(int)otherBasic->get_kind() ];
    500                         if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) {
    501                                 result = new BasicType( basicType->tq | otherBasic->tq, newType );
    502                         } // if
    503                 } else if (  dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    504                         // use signed int in lieu of the enum/zero/one type
    505                         BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ];
    506                         if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    507                                 result = new BasicType( basicType->tq | type2->tq, newType );
    508                         } // if
    509                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) {
    510                         const EnumDecl* enumDecl = enumInst->baseEnum;
    511                         if ( const Type* baseType = enumDecl->base ) {
    512                                 result = baseType->clone();
    513                         } else {
    514                                 BasicType::Kind newType = (BasicType::Kind)(int)commonTypes[ (ast::BasicType::Kind)(int)basicType->get_kind() ][ ast::BasicType::SignedInt ];
    515                                 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    516                                         result = new BasicType( basicType->tq | type2->tq, newType );
    517                                 } // if
    518                         }
    519                 }
    520         }
    521 
    522         template< typename Pointer >
    523         void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) {
    524                 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) {
    525                         OpenVarSet::const_iterator entry = openVars.find( var->get_name() );
    526                         if ( entry != openVars.end() ) {
    527                                 AssertionSet need, have;
    528                                 WidenMode widen( widenFirst, widenSecond );
    529                                 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;
    530                         }
    531                 }
    532                 result = voidPointer->clone();
    533                 result->tq |= otherPointer->tq;
    534         }
    535 
    536         void CommonType_old::postvisit( PointerType * pointerType ) {
    537                 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) {
    538                         // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
    539                         if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
    540                                 getCommonWithVoidPointer( otherPointer, pointerType );
    541                         } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
    542                                 getCommonWithVoidPointer( pointerType, otherPointer );
    543                         } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst )
    544                                            && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) {
    545                                 // std::cerr << "middle case" << std::endl;
    546                                 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq;
    547                                 pointerType->get_base()->tq = Type::Qualifiers();
    548                                 otherPointer->get_base()->tq = Type::Qualifiers();
    549                                 AssertionSet have, need;
    550                                 OpenVarSet newOpen( openVars );
    551                                 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) {
    552                                         // std::cerr << "unifyExact success" << std::endl;
    553                                         if ( tq1 < tq2 ) {
    554                                                 result = pointerType->clone();
    555                                         } else {
    556                                                 result = otherPointer->clone();
    557                                         } // if
    558                                         strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;
    559                                 } else {
    560                                         /// std::cerr << "place for ptr-to-type" << std::endl;
    561                                 } // if
    562                                 pointerType->get_base()->tq = tq1;
    563                                 otherPointer->get_base()->tq = tq2;
    564                         } // if
    565                 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    566                         result = pointerType->clone();
    567                         result->tq |= type2->tq;
    568                 } // if
    569         }
    570 
    571         void CommonType_old::postvisit( ArrayType * ) {}
    572 
    573         void CommonType_old::postvisit( ReferenceType * refType ) {
    574                 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) {
    575                         // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
    576                         // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl;
    577                         if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
    578                                 getCommonWithVoidPointer( otherRef, refType );
    579                         } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
    580                                 getCommonWithVoidPointer( refType, otherRef );
    581                         } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst )
    582                                            && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) {
    583                                 // std::cerr << "middle case" << std::endl;
    584                                 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq;
    585                                 refType->get_base()->tq = Type::Qualifiers();
    586                                 otherRef->get_base()->tq = Type::Qualifiers();
    587                                 AssertionSet have, need;
    588                                 OpenVarSet newOpen( openVars );
    589                                 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {
    590                                         if ( tq1 < tq2 ) {
    591                                                 result = refType->clone();
    592                                         } else {
    593                                                 result = otherRef->clone();
    594                                         } // if
    595                                         strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;
    596                                 } else {
    597                                         /// std::cerr << "place for ptr-to-type" << std::endl;
    598                                 } // if
    599                                 refType->get_base()->tq = tq1;
    600                                 otherRef->get_base()->tq = tq2;
    601                         } // if
    602                 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    603                         result = refType->clone();
    604                         result->tq |= type2->tq;
    605                 } // if
    606         }
    607 
    608         void CommonType_old::postvisit( FunctionType * ) {}
    609         void CommonType_old::postvisit( StructInstType * ) {}
    610         void CommonType_old::postvisit( UnionInstType * ) {}
    611 
    612         void CommonType_old::postvisit( EnumInstType * enumInstType ) {
    613                 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    614                         // reuse BasicType, EnumInstType code by swapping type2 with enumInstType
    615                         result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );
    616                 } // if
    617         }
    618 
    619         void CommonType_old::postvisit( TraitInstType * ) {
    620         }
    621 
    622         void CommonType_old::postvisit( TypeInstType * inst ) {
    623                 if ( widenFirst ) {
    624                         const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() );
    625                         if ( nt ) {
    626                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    627                                 if ( type->get_base() ) {
    628                                         Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq;
    629                                         AssertionSet have, need;
    630                                         OpenVarSet newOpen( openVars );
    631                                         type2->tq = Type::Qualifiers();
    632                                         type->get_base()->tq = tq1;
    633                                         if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) {
    634                                                 result = type2->clone();
    635                                                 result->tq = tq1 | tq2;
    636                                         } // if
    637                                         type2->tq = tq2;
    638                                         type->get_base()->tq = Type::Qualifiers();
    639                                 } // if
    640                         } // if
    641                 } // if
    642         }
    643 
    644         void CommonType_old::postvisit( TupleType * ) {}
    645         void CommonType_old::postvisit( VarArgsType * ) {}
    646 
    647         void CommonType_old::postvisit( ZeroType * zeroType ) {
    648                 if ( widenFirst ) {
    649                         if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
    650                                 if ( widenSecond || zeroType->tq <= type2->tq ) {
    651                                         result = type2->clone();
    652                                         result->tq |= zeroType->tq;
    653                                 }
    654                         } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) {
    655                                 result = new BasicType( zeroType->tq, BasicType::SignedInt );
    656                                 result->tq |= type2->tq;
    657                         }
    658                 }
    659         }
    660 
    661         void CommonType_old::postvisit( OneType * oneType ) {
    662                 if ( widenFirst ) {
    663                         if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
    664                                 if ( widenSecond || oneType->tq <= type2->tq ) {
    665                                         result = type2->clone();
    666                                         result->tq |= oneType->tq;
    667                                 }
    668                         } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    669                                 result = new BasicType( oneType->tq, BasicType::SignedInt );
    670                                 result->tq |= type2->tq;
    671                         }
    672                 }
    673         }
    674 
    675         class CommonType_new final : public ast::WithShortCircuiting {
     345        class CommonType final : public ast::WithShortCircuiting {
    676346                const ast::Type * type2;
    677347                WidenMode widen;
     
    684354                ast::ptr< ast::Type > result;
    685355
    686                 CommonType_new(
     356                CommonType(
    687357                        const ast::Type * t2, WidenMode w,
    688358                        ast::TypeEnvironment & env, const ast::OpenVarSet & o,
     
    718388                                        result = enumDecl->base.get();
    719389                                } else {
    720                                         #warning remove casts when `commonTypes` moved to new AST
    721390                                        ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
    722391                                        if (
     
    1069738        };
    1070739
    1071         // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");
     740        // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
    1072741        namespace {
    1073742                ast::ptr< ast::Type > handleReference(
     
    1141810                }
    1142811                // otherwise both are reference types of the same depth and this is handled by the visitor
    1143                 ast::Pass<CommonType_new> visitor{ type2, widen, env, open, need, have };
     812                ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have };
    1144813                type1->accept( visitor );
    1145814                // ast::ptr< ast::Type > result = visitor.core.result;
  • src/ResolvExpr/CommonType.hpp

    rdf8ba61a r8d182b1  
    1818#include "AST/Fwd.hpp"
    1919#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    20 #include "TypeEnvironment.h"        // for AssertionSet, OpenVarSet
    2120#include "WidenMode.h"              // for WidenMode
    22 
    23 class Type;
    24 namespace SymTab {
    25         class Indexer;
    26 }
    2721
    2822namespace ResolvExpr {
    2923
    30 Type * commonType(
    31         Type * type1, Type * type2, bool widenFirst, bool widenSecond,
    32         const SymTab::Indexer & indexer, TypeEnvironment & env,
    33         const OpenVarSet & openVars );
    3424ast::ptr< ast::Type > commonType(
    3525        const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
  • src/ResolvExpr/ConversionCost.cc

    rdf8ba61a r8d182b1  
    2121
    2222#include "ResolvExpr/Cost.h"             // for Cost
    23 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2423#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    2524#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    26 #include "SymTab/Indexer.h"              // for Indexer
    27 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    28 #include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
    29 
    3025
    3126namespace ResolvExpr {
    32 #if 0
    33         const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0,  0 };
    34         const Cost Cost::infinity =  Cost{ -1, -1, -1, -1, -1,  1, -1 };
    35         const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0,  0 };
    36         const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0,  0 };
    37         const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0,  0 };
    38         const Cost Cost::sign =      Cost{  0,  0,  0,  1,  0,  0,  0 };
    39         const Cost Cost::var =       Cost{  0,  0,  0,  0,  1,  0,  0 };
    40         const Cost Cost::spec =      Cost{  0,  0,  0,  0,  0, -1,  0 };
    41         const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  0,  1 };
    42 #endif
    4327
    4428#if 0
     
    4731#define PRINT(x)
    4832#endif
    49 
    50         Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,
    51                         const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    52                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    53                         PRINT( std::cerr << "type inst " << destAsTypeInst->name; )
    54                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    55                                 if ( eqvClass->type ) {
    56                                         return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    57                                 } else {
    58                                         return Cost::infinity;
    59                                 }
    60                         } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    61                                 PRINT( std::cerr << " found" << std::endl; )
    62                                 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    63                                 // all typedefs should be gone by this point
    64                                 assert( type );
    65                                 if ( type->base ) {
    66                                         return conversionCost( src, type->base, srcIsLvalue, indexer, env )
    67                                                 + Cost::safe;
    68                                 } // if
    69                         } // if
    70                         PRINT( std::cerr << " not found" << std::endl; )
    71                 } // if
    72                 PRINT(
    73                         std::cerr << "src is ";
    74                         src->print( std::cerr );
    75                         std::cerr << std::endl << "dest is ";
    76                         dest->print( std::cerr );
    77                         std::cerr << std::endl << "env is" << std::endl;
    78                         env.print( std::cerr, 8 );
    79                 )
    80                 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    81                         PRINT( std::cerr << "compatible!" << std::endl; )
    82                         return Cost::zero;
    83                 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    84                         return Cost::safe;
    85                 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    86                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    87                         return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){
    88                                 return ptrsAssignable( t1, t2, env );
    89                         });
    90                 } else {
    91                         PassVisitor<ConversionCost> converter(
    92                                 dest, srcIsLvalue, indexer, env,
    93                                 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
    94                                         conversionCost );
    95                         src->accept( converter );
    96                         if ( converter.pass.get_cost() == Cost::infinity ) {
    97                                 return Cost::infinity;
    98                         } else {
    99                                 return converter.pass.get_cost() + Cost::zero;
    100                         } // if
    101                 } // if
    102         }
    103 
    104         static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,
    105                         int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    106                 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )
    107                 if ( diff > 0 ) {
    108                         // TODO: document this
    109                         Cost cost = convertToReferenceCost(
    110                                 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,
    111                                 diff-1, indexer, env, func );
    112                         cost.incReference();
    113                         return cost;
    114                 } else if ( diff < -1 ) {
    115                         // TODO: document this
    116                         Cost cost = convertToReferenceCost(
    117                                 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,
    118                                 diff+1, indexer, env, func );
    119                         cost.incReference();
    120                         return cost;
    121                 } else if ( diff == 0 ) {
    122                         const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );
    123                         const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    124                         if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
    125                                 PRINT( std::cerr << "converting between references" << std::endl; )
    126                                 Type::Qualifiers tq1 = srcAsRef->base->tq;
    127                                 Type::Qualifiers tq2 = destAsRef->base->tq;
    128                                 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {
    129                                         PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    130                                         if ( tq1 == tq2 ) {
    131                                                 // types are the same
    132                                                 return Cost::zero;
    133                                         } else {
    134                                                 // types are the same, except otherPointer has more qualifiers
    135                                                 return Cost::safe;
    136                                         }
    137                                 } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    138                                         int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );
    139                                         PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
    140                                         if ( assignResult > 0 ) {
    141                                                 return Cost::safe;
    142                                         } else if ( assignResult < 0 ) {
    143                                                 return Cost::unsafe;
    144                                         } // if
    145                                 } // if
    146                         } else {
    147                                 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
    148                                 PassVisitor<ConversionCost> converter(
    149                                         dest, srcIsLvalue, indexer, env,
    150                                         (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
    151                                                 conversionCost );
    152                                 src->accept( converter );
    153                                 return converter.pass.get_cost();
    154                         } // if
    155                 } else {
    156                         const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    157                         assert( diff == -1 && destAsRef );
    158                         PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )
    159                         if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {
    160                                 PRINT( std::cerr << "converting compatible base type" << std::endl; )
    161                                 if ( srcIsLvalue ) {
    162                                         PRINT(
    163                                                 std::cerr << "lvalue to reference conversion" << std::endl;
    164                                                 std::cerr << src << " => " << destAsRef << std::endl;
    165                                         )
    166                                         // lvalue-to-reference conversion:  cv lvalue T => cv T &
    167                                         if ( src->tq == destAsRef->base->tq ) {
    168                                                 return Cost::reference; // cost needs to be non-zero to add cast
    169                                         } if ( src->tq < destAsRef->base->tq ) {
    170                                                 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    171                                         } else {
    172                                                 return Cost::unsafe;
    173                                         } // if
    174                                 } else if ( destAsRef->base->get_const() ) {
    175                                         PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
    176                                         // rvalue-to-const-reference conversion: T => const T &
    177                                         return Cost::safe;
    178                                 } else {
    179                                         PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
    180                                         // rvalue-to-reference conversion: T => T &
    181                                         return Cost::unsafe;
    182                                 } // if
    183                         } // if
    184                         PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
    185                 }
    186                 return Cost::infinity;
    187         }
    188 
    189         Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
    190                         const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    191                 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
    192                 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );
    193                 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )
    194                 return cost;
    195         }
    196 
    197         ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    198                 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {
    199         }
    20033
    20134        // GENERATED START, DO NOT EDIT
     
    319152        );
    320153
    321         void ConversionCost::postvisit( const VoidType * ) {
    322                 cost = Cost::infinity;
    323         }
    324 
    325         // refactor for code resue
    326         void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {
    327                 int tableResult = costMatrix[ src->kind ][ dest->kind ];
    328                 if ( tableResult == -1 ) {
    329                         cost = Cost::unsafe;
    330                 } else {
    331                         cost = Cost::zero;
    332                         cost.incSafe( tableResult );
    333                         cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
    334                 } // if
    335         } // ConversionCost::conversionCostFromBasicToBasic
    336 
    337         void ConversionCost::postvisit(const BasicType * basicType) {
    338                 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    339                         conversionCostFromBasicToBasic(basicType, destAsBasic);
    340                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {
    341                         const EnumDecl * base_enum = enumInst->baseEnum;
    342                         if ( const Type * base = base_enum->base ) {
    343                                 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {
    344                                         conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);
    345                                 } else {
    346                                         cost = Cost::infinity;
    347                                 } // if
    348                         } else {
    349                                 cost = Cost::unsafe;
    350                         } // if
    351                 } // if
    352                 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.
    353         }
    354 
    355         void ConversionCost::postvisit( const PointerType * pointerType ) {
    356                 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    357                         PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )
    358                         Type::Qualifiers tq1 = pointerType->base->tq;
    359                         Type::Qualifiers tq2 = destAsPtr->base->tq;
    360                         if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    361                                 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    362                                 if ( tq1 == tq2 ) {
    363                                         // types are the same
    364                                         cost = Cost::zero;
    365                                 } else {
    366                                         // types are the same, except otherPointer has more qualifiers
    367                                         cost = Cost::safe;
    368                                 } // if
    369                         } else {
    370                                 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
    371                                 PRINT( std::cerr << " :: " << assignResult << std::endl; )
    372                                 if ( assignResult > 0 && tq1 <= tq2 ) {
    373                                         // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?
    374                                         if ( tq1 == tq2 ) {
    375                                                 cost = Cost::safe;
    376                                         } else if ( tq1 < tq2 ) {
    377                                                 cost = Cost::safe+Cost::safe;
    378                                         }
    379                                 } else if ( assignResult < 0 ) {
    380                                         cost = Cost::unsafe;
    381                                 } // if
    382                                 // assignResult == 0 means Cost::Infinity
    383                         } // if
    384                         // case case for zero_t because it should not be possible to convert pointers to zero_t.
    385                 } // if
    386         }
    387 
    388         void ConversionCost::postvisit( const ArrayType * ) {}
    389 
    390         void ConversionCost::postvisit( const ReferenceType * refType ) {
    391                 // Note: dest can never be a reference, since it would have been caught in an earlier check
    392                 assert( ! dynamic_cast< const ReferenceType * >( dest ) );
    393                 // convert reference to rvalue: cv T1 & => T2
    394                 // recursively compute conversion cost from T1 to T2.
    395                 // cv can be safely dropped because of 'implicit dereference' behavior.
    396                 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );
    397                 if ( refType->base->tq == dest->tq ) {
    398                         cost.incReference();  // prefer exact qualifiers
    399                 } else if ( refType->base->tq < dest->tq ) {
    400                         cost.incSafe(); // then gaining qualifiers
    401                 } else {
    402                         cost.incUnsafe(); // lose qualifiers as last resort
    403                 }
    404                 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
    405         }
    406 
    407         void ConversionCost::postvisit( const FunctionType * ) {}
    408 
    409         void ConversionCost::postvisit( const EnumInstType * enumInst) {
    410                 const EnumDecl * enumDecl = enumInst -> baseEnum;
    411                 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum
    412                         cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );
    413                 } else {
    414                         static Type::Qualifiers q;
    415                         static BasicType integer( q, BasicType::SignedInt );
    416                         cost = costFunc( &integer, dest, srcIsLvalue, indexer, env );  // safe if dest >= int
    417                 } // if
    418                 if ( cost < Cost::unsafe ) {
    419                                 cost.incSafe();
    420                 } // if
    421         }
    422 
    423         void ConversionCost::postvisit( const TraitInstType * ) {}
    424 
    425         void ConversionCost::postvisit( const TypeInstType * inst ) {
    426                 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    427                         cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );
    428                 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    429                         if ( inst->name == destAsInst->name ) {
    430                                 cost = Cost::zero;
    431                         }
    432                 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {
    433                         const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    434                         // all typedefs should be gone by this point
    435                         assert( type );
    436                         if ( type->base ) {
    437                                 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;
    438                         } // if
    439                 } // if
    440         }
    441 
    442         void ConversionCost::postvisit( const TupleType * tupleType ) {
    443                 Cost c = Cost::zero;
    444                 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {
    445                         std::list< Type * >::const_iterator srcIt = tupleType->types.begin();
    446                         std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();
    447                         while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {
    448                                 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );
    449                                 if ( newCost == Cost::infinity ) {
    450                                         return;
    451                                 } // if
    452                                 c += newCost;
    453                         } // while
    454                         if ( destIt != destAsTuple->types.end() ) {
    455                                 cost = Cost::infinity;
    456                         } else {
    457                                 cost = c;
    458                         } // if
    459                 } // if
    460         }
    461 
    462         void ConversionCost::postvisit( const VarArgsType * ) {
    463                 if ( dynamic_cast< const VarArgsType * >( dest ) ) {
    464                         cost = Cost::zero;
    465                 }
    466         }
    467 
    468         void ConversionCost::postvisit( const ZeroType * ) {
    469                 if ( dynamic_cast< const ZeroType * >( dest ) ) {
    470                         cost = Cost::zero;
    471                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    472                         // copied from visit(BasicType *) for signed int, but +1 for safe conversions
    473                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    474                         if ( tableResult == -1 ) {
    475                                 cost = Cost::unsafe;
    476                         } else {
    477                                 cost = Cost::zero;
    478                                 cost.incSafe( tableResult + 1 );
    479                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
    480                         } // if
    481                 } else if ( dynamic_cast< const PointerType * >( dest ) ) {
    482                         cost = Cost::zero;
    483                         cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
    484                 } // if
    485         }
    486 
    487         void ConversionCost::postvisit( const OneType * ) {
    488                 if ( dynamic_cast< const OneType * >( dest ) ) {
    489                         cost = Cost::zero;
    490                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    491                         // copied from visit(BasicType *) for signed int, but +1 for safe conversions
    492                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    493                         if ( tableResult == -1 ) {
    494                                 cost = Cost::unsafe;
    495                         } else {
    496                                 cost = Cost::zero;
    497                                 cost.incSafe( tableResult + 1 );
    498                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
    499                         } // if
    500                 } // if
    501         }
    502 
    503154namespace {
    504         # warning For overload resolution between the two versions.
    505155        int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    506156                        const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
    507157                return ptrsAssignable( t1, t2, env );
    508158        }
    509         Cost localConversionCost(
    510                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    511                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    512         ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }
    513159}
    514160
     
    540186                return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
    541187        } else {
    542                 return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );
     188                return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost );
    543189        }
    544190}
     
    581227                        }
    582228                } else {
    583                         return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );
     229                        return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost );
    584230                }
    585231        } else {
     
    613259}
    614260
    615 void ConversionCost_new::postvisit( const ast::VoidType * voidType ) {
     261void ConversionCost::postvisit( const ast::VoidType * voidType ) {
    616262        (void)voidType;
    617263        cost = Cost::infinity;
    618264}
    619265
    620 void ConversionCost_new::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {
     266void ConversionCost::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {
    621267        int tableResult = costMatrix[ src->kind ][ dest->kind ];
    622268        if ( tableResult == -1 ) {
     
    629275}
    630276
    631 void ConversionCost_new::postvisit( const ast::BasicType * basicType ) {
     277void ConversionCost::postvisit( const ast::BasicType * basicType ) {
    632278        if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
    633279                conversionCostFromBasicToBasic( basicType, dstAsBasic );
     
    635281                const ast::EnumDecl * enumDecl = enumInst->base.get();
    636282                if ( enumDecl->isTyped && !enumDecl->base.get() ) {
    637                         cost = Cost::infinity; 
     283                        cost = Cost::infinity;
    638284                } else if ( const ast::Type * enumType = enumDecl->base.get() ) {
    639285                        if ( const ast::BasicType * enumTypeAsBasic = dynamic_cast<const ast::BasicType *>(enumType) ) {
     
    648294}
    649295
    650 void ConversionCost_new::postvisit( const ast::PointerType * pointerType ) {
     296void ConversionCost::postvisit( const ast::PointerType * pointerType ) {
    651297        if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) {
    652298                ast::CV::Qualifiers tq1 = pointerType->base->qualifiers;
     
    694340}
    695341
    696 void ConversionCost_new::postvisit( const ast::ArrayType * arrayType ) {
     342void ConversionCost::postvisit( const ast::ArrayType * arrayType ) {
    697343        (void)arrayType;
    698344}
    699345
    700 void ConversionCost_new::postvisit( const ast::ReferenceType * refType ) {
     346void ConversionCost::postvisit( const ast::ReferenceType * refType ) {
    701347        assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
    702348
     
    716362}
    717363
    718 void ConversionCost_new::postvisit( const ast::FunctionType * functionType ) {
     364void ConversionCost::postvisit( const ast::FunctionType * functionType ) {
    719365        (void)functionType;
    720366}
    721367
    722 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
     368void ConversionCost::postvisit( const ast::EnumInstType * enumInstType ) {
    723369        const ast::EnumDecl * baseEnum = enumInstType->base;
    724370        if ( const ast::Type * baseType = baseEnum->base ) {
     
    733379}
    734380
    735 void ConversionCost_new::postvisit( const ast::TraitInstType * traitInstType ) {
     381void ConversionCost::postvisit( const ast::TraitInstType * traitInstType ) {
    736382        (void)traitInstType;
    737383}
    738384
    739 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
     385void ConversionCost::postvisit( const ast::TypeInstType * typeInstType ) {
    740386        if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
    741387                cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
     
    754400}
    755401
    756 void ConversionCost_new::postvisit( const ast::TupleType * tupleType ) {
     402void ConversionCost::postvisit( const ast::TupleType * tupleType ) {
    757403        Cost c = Cost::zero;
    758404        if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) {
     
    776422}
    777423
    778 void ConversionCost_new::postvisit( const ast::VarArgsType * varArgsType ) {
     424void ConversionCost::postvisit( const ast::VarArgsType * varArgsType ) {
    779425        (void)varArgsType;
    780426        if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) {
     
    783429}
    784430
    785 void ConversionCost_new::postvisit( const ast::ZeroType * zeroType ) {
     431void ConversionCost::postvisit( const ast::ZeroType * zeroType ) {
    786432        (void)zeroType;
    787433        if ( dynamic_cast< const ast::ZeroType * >( dst ) ) {
     
    810456}
    811457
    812 void ConversionCost_new::postvisit( const ast::OneType * oneType ) {
     458void ConversionCost::postvisit( const ast::OneType * oneType ) {
    813459        (void)oneType;
    814460        if ( dynamic_cast< const ast::OneType * >( dst ) ) {
    815461                cost = Cost::zero;
    816462        } else if ( const ast::BasicType * dstAsBasic =
    817                         dynamic_cast< const ast::BasicType * >( dst ) ) {               
     463                        dynamic_cast< const ast::BasicType * >( dst ) ) {
    818464                int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
    819465                if ( -1 == tableResult ) {
     
    824470                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    825471                }
    826                
    827                 // cost = Cost::zero;
    828         }
    829 }
    830 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
     472        }
     473}
     474
     475// size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
    831476
    832477} // namespace ResolvExpr
  • src/ResolvExpr/ConversionCost.h

    rdf8ba61a r8d182b1  
    2222#include "AST/Fwd.hpp"
    2323#include "AST/Pass.hpp"       // for WithShortCircuiting
    24 #include "Common/PassVisitor.h"
    25 #include "SynTree/Visitor.h"  // for Visitor
    26 #include "SynTree/SynTree.h"  // for Visitor Nodes
    27 
    28 namespace SymTab {
    29         class Indexer;
    30 }  // namespace SymTab
    3124
    3225namespace ResolvExpr {
    33         class TypeEnvironment;
    34 
    35         Cost conversionCost(
    36                 const Type * src, const Type * dest, bool srcIsLvalue,
    37                 const SymTab::Indexer & indexer, const TypeEnvironment & env );
    38 
    39         typedef std::function<Cost(const Type *, const Type *, bool,
    40                 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;
    41 
    42         struct ConversionCost : public WithShortCircuiting {
    43           public:
    44                 ConversionCost( const Type * dest, bool srcIsLvalue,
    45                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );
    46 
    47                 Cost get_cost() const { return cost; }
    48 
    49                 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    50 
    51                 void postvisit( const VoidType * voidType );
    52                 void postvisit( const BasicType * basicType );
    53                 void postvisit( const PointerType * pointerType );
    54                 void postvisit( const ArrayType * arrayType );
    55                 void postvisit( const ReferenceType * refType );
    56                 void postvisit( const FunctionType * functionType );
    57                 void postvisit( const EnumInstType * aggregateUseType );
    58                 void postvisit( const TraitInstType * aggregateUseType );
    59                 void postvisit( const TypeInstType * aggregateUseType );
    60                 void postvisit( const TupleType * tupleType );
    61                 void postvisit( const VarArgsType * varArgsType );
    62                 void postvisit( const ZeroType * zeroType );
    63                 void postvisit( const OneType * oneType );
    64           protected:
    65                 const Type * dest;
    66                 bool srcIsLvalue;
    67                 const SymTab::Indexer &indexer;
    68                 Cost cost;
    69                 const TypeEnvironment &env;
    70                 CostFunction costFunc;
    71           private:
    72                 // refactor for code resue
    73                 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );
    74         };
    75 
    76         typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;
    77         Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
    78                 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );
    7926
    8027// Some function pointer types, differ in return type.
     
    9239        PtrsCalculation func );
    9340
    94 #warning when the old ConversionCost is removed, get ride of the _new suffix.
    95 class ConversionCost_new : public ast::WithShortCircuiting {
     41class ConversionCost : public ast::WithShortCircuiting {
    9642protected:
    9743        const ast::Type * dst;
     
    10551        Cost result() { return cost; }
    10652
    107         ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
     53        ConversionCost( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
    10854                        const ast::TypeEnvironment & env, CostCalculation costCalc ) :
    10955                dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
  • src/ResolvExpr/CurrentObject.cc

    rdf8ba61a r8d182b1  
    3333#include "Common/utility.h"            // for toString
    3434#include "CurrentObject.h"
    35 #include "SynTree/Constant.h"          // for Constant
    36 #include "SynTree/Declaration.h"       // for ObjectDecl, Declaration, Struc...
    37 #include "SynTree/Expression.h"        // for InitAlternative, VariableExpr
    38 #include "SynTree/Initializer.h"       // for Designation, operator<<
    39 #include "SynTree/Type.h"              // for Type, StructInstType, UnionIns...
    40 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
    4135
    4236#if 0
     
    4539#define PRINT(x)
    4640#endif
    47 
    48 namespace ResolvExpr {
    49         template< typename AggrInst >
    50         TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {
    51                 assert( inst );
    52                 assert( inst->get_baseParameters() );
    53                 std::list< TypeDecl * > baseParams = *inst->get_baseParameters();
    54                 std::list< Expression * > typeSubs = inst->get_parameters();
    55                 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
    56                 return subs;
    57         }
    58 
    59         TypeSubstitution makeGenericSubstitution( Type * type ) {
    60                 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {
    61                         return makeGenericSubstitution( inst );
    62                 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {
    63                         return makeGenericSubstitution( inst );
    64                 } else {
    65                         return TypeSubstitution();
    66                 }
    67         }
    68 
    69         class MemberIterator {
    70         public:
    71                 virtual ~MemberIterator() {}
    72 
    73                 /// walks the current object using the given designators as a guide
    74                 virtual void setPosition( std::list< Expression * > & designators ) = 0;
    75 
    76                 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object
    77                 virtual std::list<InitAlternative> operator*() const = 0;
    78 
    79                 /// true if the iterator is not currently at the end
    80                 virtual operator bool() const = 0;
    81 
    82                 /// moves the iterator by one member in the current object
    83                 virtual MemberIterator & bigStep() = 0;
    84 
    85                 /// moves the iterator by one member in the current subobject
    86                 virtual MemberIterator & smallStep() = 0;
    87 
    88                 /// the type of the current object
    89                 virtual Type * getType() = 0;
    90 
    91                 /// the type of the current subobject
    92                 virtual Type * getNext() = 0;
    93 
    94                 /// printing for debug
    95                 virtual void print( std::ostream & out, Indenter indent ) const = 0;
    96 
    97                 /// helper for operator*; aggregates must add designator to each init alternative, but
    98                 /// adding designators in operator* creates duplicates.
    99                 virtual std::list<InitAlternative> first() const = 0; // should be protected
    100         };
    101 
    102         std::ostream & operator<<(std::ostream & out, const MemberIterator & it) {
    103                 Indenter indenter;
    104                 it.print( out, indenter );
    105                 return out;
    106         }
    107 
    108         /// create a new MemberIterator that traverses a type correctly
    109         MemberIterator * createMemberIterator( Type * type );
    110 
    111         /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry
    112         class SimpleIterator : public MemberIterator {
    113         public:
    114                 SimpleIterator( Type * type ) : type( type ) {}
    115 
    116                 virtual void setPosition( std::list< Expression * > & designators ) {
    117                         assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error
    118                 }
    119 
    120                 virtual std::list<InitAlternative> operator*() const { return first(); }
    121                 virtual operator bool() const { return type; }
    122 
    123                 // big step is the same as small step
    124                 virtual MemberIterator & bigStep() { return smallStep(); }
    125                 virtual MemberIterator & smallStep() {
    126                         type = nullptr;  // type is nullified on increment since SimpleIterators do not have members
    127                         return *this;
    128                 }
    129 
    130                 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const {
    131                         out << "SimpleIterator(" << type << ")";
    132                 }
    133 
    134                 virtual Type * getType() { return type; }
    135                 virtual Type * getNext() { return type; }
    136 
    137         protected:
    138                 virtual std::list<InitAlternative> first() const {
    139                         if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } };
    140                         else return std::list<InitAlternative>{};
    141                 }
    142         private:
    143                 Type * type = nullptr;
    144         };
    145 
    146         class ArrayIterator : public MemberIterator {
    147         public:
    148                 ArrayIterator( ArrayType * at ) : array( at ) {
    149                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    150                         base = at->base;
    151                         memberIter = createMemberIterator( base );
    152                         if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );
    153                         setSize( at->dimension );
    154                 }
    155 
    156                 ~ArrayIterator() {
    157                         delete memberIter;
    158                 }
    159 
    160         private:
    161                 void setSize( Expression * expr ) {
    162                         auto res = eval( expr );
    163                         if (res.second) {
    164                                 size = res.first;
    165                         } else {
    166                                 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );
    167                         }
    168                 }
    169 
    170         public:
    171                 void setPosition( Expression * expr ) {
    172                         // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions
    173                         auto arg = eval( expr );
    174                         index = arg.first;
    175                         return;
    176 
    177                         // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
    178                         //      try {
    179                         //              index = constExpr->intValue();
    180                         //      } catch( SemanticErrorException & ) {
    181                         //              SemanticError( expr, "Constant expression of non-integral type in array designator: " );
    182                         //      }
    183                         // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    184                         //      setPosition( castExpr->get_arg() );
    185                         // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    186                         //      EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );
    187                         //      assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
    188                         //      long long int value;
    189                         //      if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    190                         //              index = value;
    191                         //      }
    192                         // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {
    193                         //      index = 0; // xxx - get actual sizeof/alignof value?
    194                         // } else {
    195                         //      assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    196                         // }
    197                 }
    198 
    199                 virtual void setPosition( std::list< Expression * > & designators ) {
    200                         if ( ! designators.empty() ) {
    201                                 setPosition( designators.front() );
    202                                 designators.pop_front();
    203                                 memberIter->setPosition( designators );
    204                         }
    205                 }
    206 
    207                 virtual std::list<InitAlternative> operator*() const {
    208                         return first();
    209                 }
    210 
    211                 virtual operator bool() const { return index < size; }
    212 
    213                 virtual MemberIterator & bigStep() {
    214                         PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    215                         ++index;
    216                         delete memberIter;
    217                         if ( index < size ) memberIter = createMemberIterator( base );
    218                         else memberIter = nullptr;
    219                         return *this;
    220                 }
    221 
    222                 virtual MemberIterator & smallStep() {
    223                         PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    224                         if ( memberIter ) {
    225                                 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
    226                                 memberIter->smallStep();
    227                                 if ( *memberIter ) {
    228                                         PRINT( std::cerr << "has valid member iter" << std::endl; )
    229                                         return *this;
    230                                 }
    231                         }
    232                         return bigStep();
    233                 }
    234 
    235                 virtual Type * getType() { return array; }
    236                 virtual Type * getNext() { return base; }
    237 
    238                 virtual std::list<InitAlternative> first() const {
    239                         PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    240                         if ( memberIter && *memberIter ) {
    241                                 std::list<InitAlternative> ret = memberIter->first();
    242                                 for ( InitAlternative & alt : ret ) {
    243                                         alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) );
    244                                 }
    245                                 return ret;
    246                         }
    247                         return std::list<InitAlternative>();
    248                 }
    249 
    250                 virtual void print( std::ostream & out, Indenter indent ) const {
    251                         out << "ArrayIterator(Array of " << base << ")";
    252                         if ( memberIter ) {
    253                                 Indenter childIndent = indent+1;
    254                                 out << std::endl << childIndent;
    255                                 memberIter->print( out, childIndent );
    256                         }
    257                 }
    258 
    259         private:
    260                 ArrayType * array = nullptr;
    261                 Type * base = nullptr;
    262                 size_t index = 0;
    263                 size_t size = 0;
    264                 MemberIterator * memberIter = nullptr;
    265         };
    266 
    267         class AggregateIterator : public MemberIterator {
    268         public:
    269                 typedef std::list<Declaration *> MemberList;
    270                 typedef MemberList::const_iterator iterator;
    271                 std::string kind = ""; // for debug
    272                 std::string name;
    273                 Type * inst = nullptr;
    274                 const MemberList & members;
    275                 iterator curMember;
    276                 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning
    277                 Type * curType = nullptr;
    278                 MemberIterator * memberIter = nullptr;
    279                 mutable TypeSubstitution sub;
    280 
    281                 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) {
    282                         PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
    283                         init();
    284                 }
    285 
    286                 virtual ~AggregateIterator() {
    287                         delete memberIter;
    288                 }
    289 
    290                 bool init() {
    291                         PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
    292                         if ( curMember != members.end() ) {
    293                                 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) {
    294                                         PRINT( std::cerr << "incremented to field: " << field << std::endl; )
    295                                         curType = field->get_type();
    296                                         memberIter = createMemberIterator( curType );
    297                                         return true;
    298                                 }
    299                         }
    300                         return false;
    301                 }
    302 
    303                 virtual std::list<InitAlternative> operator*() const {
    304                         if (memberIter && *memberIter) {
    305                                 std::list<InitAlternative> ret = memberIter->first();
    306                                 PRINT( std::cerr << "sub: " << sub << std::endl; )
    307                                 for ( InitAlternative & alt : ret ) {
    308                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    309                                         alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );
    310                                         // need to substitute for generic types, so that casts are to concrete types
    311                                         PRINT( std::cerr << "  type is: " << alt.type; )
    312                                         sub.apply( alt.type ); // also apply to designation??
    313                                         PRINT( std::cerr << " ==> " << alt.type << std::endl; )
    314                                 }
    315                                 return ret;
    316                         }
    317                         return std::list<InitAlternative>();
    318                 }
    319 
    320                 virtual void setPosition( std::list< Expression * > & designators ) {
    321                         if ( ! designators.empty() ) {
    322                                 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) {
    323                                         for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
    324                                                 if ( *curMember == varExpr->get_var() ) {
    325                                                         designators.pop_front();
    326                                                         delete memberIter;
    327                                                         memberIter = createMemberIterator( varExpr->get_result() );
    328                                                         curType = varExpr->get_result();
    329                                                         atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin??
    330                                                         memberIter->setPosition( designators );
    331                                                         return;
    332                                                 } // if
    333                                         } // for
    334                                         assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    335                                 } else {
    336                                         assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );
    337                                 } // if
    338                         } // if
    339                 }
    340 
    341                 virtual MemberIterator & smallStep() {
    342                         PRINT( std::cerr << "smallStep in " << kind << std::endl; )
    343                         atbegin = false;
    344                         if ( memberIter ) {
    345                                 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
    346                                 memberIter->smallStep();
    347                                 if ( *memberIter ) {
    348                                         PRINT( std::cerr << "success!" << std::endl; )
    349                                         return *this;
    350                                 }
    351                         }
    352                         return bigStep();
    353                 }
    354 
    355                 virtual Type * getType() { return inst; }
    356                 virtual Type * getNext() {
    357                         if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call???
    358                         return nullptr;
    359                 }
    360 
    361                 virtual std::list<InitAlternative> first() const {
    362                         std::list<InitAlternative> ret;
    363                         PRINT( std::cerr << "first " << kind << std::endl; )
    364                         if ( memberIter && *memberIter ) { // might not need *memberIter??
    365                                 PRINT( std::cerr << "adding children" << std::endl; )
    366                                 ret = memberIter->first();
    367                                 for ( InitAlternative & alt : ret ) {
    368                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    369                                         alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );
    370                                 }
    371                         }
    372                         if ( atbegin ) {
    373                                 // xxx - what about case of empty struct??
    374                                 // only add self if at the very beginning of the structure
    375                                 PRINT( std::cerr << "adding self" << std::endl; )
    376                                 ret.push_front( { inst->clone(), new Designation( {} ) } );
    377                         }
    378                         return ret;
    379                 }
    380 
    381                 virtual void print( std::ostream & out, Indenter indent ) const {
    382                         out << kind << "(" << name << ")";
    383                         if ( memberIter ) {
    384                                 Indenter childIndent = indent+1;
    385                                 out << std::endl << childIndent;
    386                                 memberIter->print( out, childIndent );
    387                         }
    388                 }
    389         };
    390 
    391         class UnionIterator : public AggregateIterator {
    392         public:
    393                 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {}
    394 
    395                 virtual operator bool() const { return (memberIter && *memberIter); }
    396                 virtual MemberIterator & bigStep() {
    397                         // unions only initialize one member
    398                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    399                         atbegin = false;
    400                         delete memberIter;
    401                         memberIter = nullptr;
    402                         curType = nullptr;
    403                         curMember = members.end();
    404                         return *this;
    405                 }
    406         };
    407 
    408         class StructIterator : public AggregateIterator {
    409         public:
    410                 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {}
    411 
    412                 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }
    413 
    414                 virtual MemberIterator & bigStep() {
    415                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    416                         atbegin = false;
    417                         delete memberIter;
    418                         memberIter = nullptr;
    419                         curType = nullptr;
    420                         for ( ; curMember != members.end(); ) {
    421                                 ++curMember;
    422                                 if ( init() ) {
    423                                         return *this;
    424                                 }
    425                         }
    426                         return *this;
    427                 }
    428         };
    429 
    430         class TupleIterator : public AggregateIterator {
    431         public:
    432                 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {}
    433 
    434                 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }
    435 
    436                 virtual MemberIterator & bigStep() {
    437                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    438                         atbegin = false;
    439                         delete memberIter;
    440                         memberIter = nullptr;
    441                         curType = nullptr;
    442                         for ( ; curMember != members.end(); ) {
    443                                 ++curMember;
    444                                 if ( init() ) {
    445                                         return *this;
    446                                 }
    447                         }
    448                         return *this;
    449                 }
    450         };
    451 
    452         MemberIterator * createMemberIterator( Type * type ) {
    453                 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) {
    454                         if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) {
    455                                 return new StructIterator( sit );
    456                         } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) {
    457                                 return new UnionIterator( uit );
    458                         } else {
    459                                 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );
    460                                 return new SimpleIterator( type );
    461                         }
    462                 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    463                         return new ArrayIterator( at );
    464                 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) {
    465                         return new TupleIterator( tt );
    466                 } else {
    467                         return new SimpleIterator( type );
    468                 }
    469         }
    470 
    471         CurrentObject::CurrentObject() {}
    472         CurrentObject::CurrentObject( Type * type ) {
    473                 objStack.push( new SimpleIterator( type ) );
    474         }
    475 
    476 
    477         void CurrentObject::setNext( Designation * designation ) {
    478                 assertf( ! objStack.empty(), "obj stack empty in setNext" );
    479                 PRINT( std::cerr << "____setNext" << designation << std::endl; )
    480                 objStack.top()->setPosition( designation->get_designators() );
    481         }
    482 
    483         Designation * CurrentObject::findNext( Designation * designation ) {
    484                 typedef std::list< Expression * > DesignatorChain;
    485                 PRINT( std::cerr << "___findNext" << std::endl; )
    486                 // find all the d's
    487                 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts;
    488                 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes;
    489                 for ( Expression * expr : designation->get_designators() ) {
    490                         PRINT( std::cerr << "____untyped: " << expr << std::endl; )
    491                         std::list<DesignatorChain>::iterator dit = desigAlts.begin();
    492                         if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) {
    493                                 for ( Type * t : curTypes ) {
    494                                         assert( dit != desigAlts.end() );
    495                                         DesignatorChain & d = *dit;
    496                                         PRINT( std::cerr << "____actual: " << t << std::endl; )
    497                                         ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t);
    498                                         std::list<Declaration *> members;
    499                                         if ( refType ) {
    500                                                 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name
    501                                                 // xxx - need to also include anonymous members in this somehow...
    502                                                 for ( Declaration * mem: members ) {
    503                                                         if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) {
    504                                                                 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; )
    505                                                                 DesignatorChain newD = d;
    506                                                                 newD.push_back( new VariableExpr( field ) );
    507                                                                 newDesigAlts.push_back( newD );
    508                                                                 newTypes.push_back( field->get_type() );
    509                                                         } // if
    510                                                 } // for
    511                                         } // if
    512                                         ++dit;
    513                                 } // for
    514                         } else {
    515                                 for ( Type * t : curTypes ) {
    516                                         assert( dit != desigAlts.end() );
    517                                         DesignatorChain & d = *dit;
    518                                         if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) {
    519                                                 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
    520                                                 d.push_back( expr );
    521                                                 newDesigAlts.push_back( d );
    522                                                 newTypes.push_back( at->get_base() );
    523                                         }
    524                                         ++dit;
    525                                 } // for
    526                         } // if
    527                         desigAlts = newDesigAlts;
    528                         newDesigAlts.clear();
    529                         curTypes = newTypes;
    530                         newTypes.clear();
    531                         assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
    532                 } // for
    533                 if ( desigAlts.size() > 1 ) {
    534                         SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
    535                 } else if ( desigAlts.size() == 0 ) {
    536                         SemanticError( designation, "No reasonable alternatives for designation: " );
    537                 }
    538                 DesignatorChain & d = desigAlts.back();
    539                 PRINT( for ( Expression * expr : d ) {
    540                         std::cerr << "____desig: " << expr << std::endl;
    541                 } ) // for
    542                 assertf( ! curTypes.empty(), "empty designator chosen");
    543 
    544                 // set new designators
    545                 assertf( ! objStack.empty(), "empty object stack when setting designation" );
    546                 Designation * actualDesignation = new Designation( d );
    547                 objStack.top()->setPosition( d ); // destroys d
    548                 return actualDesignation;
    549         }
    550 
    551         void CurrentObject::increment() {
    552                 PRINT( std::cerr << "____increment" << std::endl; )
    553                 if ( ! objStack.empty() ) {
    554                         PRINT( std::cerr << *objStack.top() << std::endl; )
    555                         objStack.top()->smallStep();
    556                 }
    557         }
    558 
    559         void CurrentObject::enterListInit() {
    560                 PRINT( std::cerr << "____entering list init" << std::endl; )
    561                 assertf( ! objStack.empty(), "empty obj stack entering list init" );
    562                 Type * type = objStack.top()->getNext();
    563                 if ( type ) {
    564                         objStack.push( createMemberIterator( type ) );
    565                 } else {
    566                         assertf( false, "not sure about this case..." );
    567                 }
    568         }
    569 
    570         void CurrentObject::exitListInit() {
    571                 PRINT( std::cerr << "____exiting list init" << std::endl; )
    572                 assertf( ! objStack.empty(), "objstack empty" );
    573                 delete objStack.top();
    574                 objStack.pop();
    575                 if ( ! objStack.empty() ) {
    576                         PRINT( std::cerr << *objStack.top() << std::endl; )
    577                         objStack.top()->bigStep();
    578                 }
    579         }
    580 
    581         std::list< InitAlternative > CurrentObject::getOptions() {
    582                 PRINT( std::cerr << "____getting current options" << std::endl; )
    583                 assertf( ! objStack.empty(), "objstack empty in getOptions" );
    584                 return **objStack.top();
    585         }
    586 
    587         Type * CurrentObject::getCurrentType() {
    588                 PRINT( std::cerr << "____getting current type" << std::endl; )
    589                 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
    590                 return objStack.top()->getNext();
    591         }
    592 } // namespace ResolvExpr
    59341
    59442namespace ast {
  • src/ResolvExpr/FindOpenVars.cc

    rdf8ba61a r8d182b1  
    1616#include "FindOpenVars.h"
    1717
    18 #include <list>                   // for _List_const_iterator, list<>::const...
    19 #include <map>                    // for map<>::mapped_type
    20 
    2118#include "AST/Pass.hpp"
    2219#include "AST/Type.hpp"
    2320#include "AST/TypeEnvironment.hpp"
    24 #include "Common/PassVisitor.h"
    25 #include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
    26 #include "SynTree/Type.h"         // for Type, Type::ForallList, ArrayType
    2721
    2822#include <iostream>
    2923
    3024namespace ResolvExpr {
    31         struct FindOpenVars_old : public WithGuards {
    32                 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    33 
    34                 void previsit( const PointerType * pointerType );
    35                 void previsit( const ArrayType * arrayType );
    36                 void previsit( const FunctionType * functionType );
    37                 void previsit( const TupleType * tupleType );
    38 
    39                 void common_action( const Type *type );
    40 
    41                 OpenVarSet &openVars, &closedVars;
    42                 AssertionSet &needAssertions, &haveAssertions;
    43                 bool nextIsOpen;
    44         };
    45 
    46         void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {
    47                 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
    48                 type->accept( finder );
    49         }
    50 
    51         FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )
    52                 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {
    53         }
    54 
    55         void FindOpenVars_old::common_action( const Type * type ) {
    56                 if ( nextIsOpen ) {
    57                         for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    58                                 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    59                                 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
    60                                         needAssertions[ *assert ].isUsed = false;
    61                                 }
    62 ///       cloneAll( (*i)->get_assertions(), needAssertions );
    63 ///       needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );
    64                         }
    65                 } else {
    66                         for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    67                                 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    68                                 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
    69                                         haveAssertions[ *assert ].isUsed = false;
    70                                 }
    71 ///       cloneAll( (*i)->get_assertions(), haveAssertions );
    72 ///       haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );
    73                         } // for
    74                 } // if
    75 ///   std::cerr << "type is ";
    76 ///   type->print( std::cerr );
    77 ///   std::cerr << std::endl << "need is" << std::endl;
    78 ///   printAssertionSet( needAssertions, std::cerr );
    79 ///   std::cerr << std::endl << "have is" << std::endl;
    80 ///   printAssertionSet( haveAssertions, std::cerr );
    81         }
    82 
    83         void FindOpenVars_old::previsit(const PointerType * pointerType) {
    84                 common_action( pointerType );
    85         }
    86 
    87         void FindOpenVars_old::previsit(const ArrayType * arrayType) {
    88                 common_action( arrayType );
    89         }
    90 
    91         void FindOpenVars_old::previsit(const FunctionType * functionType) {
    92                 common_action( functionType );
    93                 nextIsOpen = ! nextIsOpen;
    94                 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
    95         }
    96 
    97         void FindOpenVars_old::previsit(const TupleType * tupleType) {
    98                 common_action( tupleType );
    99         }
    10025
    10126        namespace {
    102                 struct FindOpenVars_new final : public ast::WithGuards {
     27                struct FindOpenVars final : public ast::WithGuards {
    10328                        ast::OpenVarSet & open;
    10429                        ast::OpenVarSet & closed;
     
    10833                        bool nextIsOpen;
    10934
    110                         FindOpenVars_new(
     35                        FindOpenVars(
    11136                                ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
    11237                                ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
     
    14873                        const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
    14974                        ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
    150                 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, env, firstIsOpen };
     75                ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen };
    15176                type->accept( finder );
    15277
  • src/ResolvExpr/FindOpenVars.h

    rdf8ba61a r8d182b1  
    1717
    1818#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    19 #include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    2019
    21 class Type;
    2220namespace ast {
    2321        class Type;
     
    2523
    2624namespace ResolvExpr {
    27         // Updates open and closed variables and their associated assertions
    28         void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    29 
    3025        enum FirstMode { FirstClosed, FirstOpen };
    3126
  • src/ResolvExpr/PolyCost.cc

    rdf8ba61a r8d182b1  
    1818#include "AST/Type.hpp"
    1919#include "AST/TypeEnvironment.hpp"
    20 #include "Common/PassVisitor.h"
    21 #include "SymTab/Indexer.h"   // for Indexer
    22 #include "SynTree/Type.h"     // for TypeInstType, Type
    23 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2420
    2521namespace ResolvExpr {
    26         struct PolyCost {
    27                 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );
    2822
    29                 void previsit( TypeInstType * aggregateUseType );
    30                 int result;
    31                 const TypeEnvironment &tenv;
    32                 const SymTab::Indexer &indexer;
    33         };
    34 
    35         int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) {
    36                 PassVisitor<PolyCost> coster( env, indexer );
    37                 type->accept( coster );
    38                 return (coster.pass.result > 0) ? 1 : 0;
    39         }
    40 
    41         PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) {
    42         }
    43 
    44         void PolyCost::previsit(TypeInstType * typeInst) {
    45                 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {
    46                         if ( eqvClass->type ) {
    47                                 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) {
    48                                         if ( indexer.lookupType( otherTypeInst->name ) ) {
    49                                                 // bound to opaque type
    50                                                 result += 1;
    51                                         } // if
    52                                 } else {
    53                                         // bound to concrete type
    54                                         result += 1;
    55                                 } // if
    56                         } // if
    57                 } // if
    58         }
    59 
    60 // TODO: When the old PolyCost is torn out get rid of the _new suffix.
    61 class PolyCost_new {
     23class PolyCost {
    6224        const ast::SymbolTable &symtab;
    6325public:
     
    6527        const ast::TypeEnvironment &env_;
    6628
    67         PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
     29        PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
    6830        : symtab( symtab ), result( 0 ), env_( env ) {}
    6931
     
    8648        const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    8749) {
    88         ast::Pass<PolyCost_new> costing( symtab, env );
     50        ast::Pass<PolyCost> costing( symtab, env );
    8951        type->accept( costing );
    9052        return (costing.core.result > 0) ? 1 : 0;
  • src/ResolvExpr/PolyCost.hpp

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 class Type;
    19 namespace SymTab {
    20     class Indexer;
    21 }
    2218namespace ast {
    2319    class SymbolTable;
     
    2824namespace ResolvExpr {
    2925
    30 class TypeEnvironment;
    31 
    32 int polyCost( Type * type,
    33         const TypeEnvironment & env, const SymTab::Indexer & indexer );
    3426int polyCost( const ast::Type * type,
    3527        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
  • src/ResolvExpr/PtrsAssignable.cc

    rdf8ba61a r8d182b1  
    1919#include "AST/Type.hpp"
    2020#include "AST/TypeEnvironment.hpp"
    21 #include "Common/PassVisitor.h"
    22 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    23 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    24 #include "SynTree/Visitor.h"             // for Visitor
    25 
    2621
    2722namespace ResolvExpr {
    28         struct PtrsAssignable : public WithShortCircuiting {
    29                 PtrsAssignable( const Type * dest, const TypeEnvironment &env );
    3023
    31                 int get_result() const { return result; }
    32 
    33                 void previsit( const Type * ) { visit_children = false; }
    34 
    35                 void postvisit( const VoidType * voidType );
    36                 void postvisit( const BasicType * basicType );
    37                 void postvisit( const PointerType * pointerType );
    38                 void postvisit( const ArrayType * arrayType );
    39                 void postvisit( const FunctionType * functionType );
    40                 void postvisit( const StructInstType * inst );
    41                 void postvisit( const UnionInstType * inst );
    42                 void postvisit( const EnumInstType * inst );
    43                 void postvisit( const TraitInstType * inst );
    44                 void postvisit( const TypeInstType * inst );
    45                 void postvisit( const TupleType * tupleType );
    46                 void postvisit( const VarArgsType * varArgsType );
    47                 void postvisit( const ZeroType * zeroType );
    48                 void postvisit( const OneType * oneType );
    49           private:
    50                 const Type * dest;
    51                 int result;
    52                 const TypeEnvironment &env;
    53         };
    54 
    55         int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) {
    56                 // std::cerr << "assignable: " << src << " | " << dest << std::endl;
    57                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
    58                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    59                                 return ptrsAssignable( src, eqvClass->type, env );
    60                         } // if
    61                 } // if
    62                 if ( dynamic_cast< const VoidType* >( dest ) ) {
    63                         // void * = T * for any T is unsafe
    64                         // xxx - this should be safe, but that currently breaks the build
    65                         return -1;
    66                 } else {
    67                         PassVisitor<PtrsAssignable> ptrs( dest, env );
    68                         src->accept( ptrs );
    69                         return ptrs.pass.get_result();
    70                 } // if
    71         }
    72 
    73         PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
    74 
    75         void PtrsAssignable::postvisit( const VoidType * ) {
    76                 // T * = void * is disallowed - this is a change from C, where any
    77                 // void * can be assigned or passed to a non-void pointer without a cast.
    78         }
    79 
    80         void PtrsAssignable::postvisit( const BasicType * ) {}
    81         void PtrsAssignable::postvisit( const PointerType * ) {}
    82         void PtrsAssignable::postvisit( const ArrayType * ) {}
    83         void PtrsAssignable::postvisit( const FunctionType * ) {}
    84 
    85         void PtrsAssignable::postvisit( const StructInstType * ) {}
    86         void PtrsAssignable::postvisit( const UnionInstType * ) {}
    87 
    88         void PtrsAssignable::postvisit( const EnumInstType * ) {
    89                 if ( dynamic_cast< const BasicType* >( dest ) ) {
    90                         // int * = E *, etc. is safe. This isn't technically correct, as each
    91                         // enum has one basic type that it is compatible with, an that type can
    92                         // differ from enum to enum. Without replicating GCC's internal logic,
    93                         // there is no way to know which type this particular enum is compatible
    94                         // with, so punt on this for now.
    95                         result = 1;
    96                 }
    97         }
    98 
    99         void PtrsAssignable::postvisit(  const TraitInstType * ) {}
    100         void PtrsAssignable::postvisit( const TypeInstType * inst ) {
    101                 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    102                         if ( eqvClass->type ) {
    103                                 // T * = S * for any S depends on the type bound to T
    104                                 result = ptrsAssignable( eqvClass->type, dest, env );
    105                         }
    106                 } // if
    107         }
    108 
    109         void PtrsAssignable::postvisit( const TupleType * ) {}
    110         void PtrsAssignable::postvisit( const VarArgsType * ) {}
    111         void PtrsAssignable::postvisit( const ZeroType * ) {}
    112         void PtrsAssignable::postvisit( const OneType * ) {}
    113 
    114 // TODO: Get rid of the `_new` suffix when the old version is removed.
    115 struct PtrsAssignable_new : public ast::WithShortCircuiting {
     24struct PtrsAssignable : public ast::WithShortCircuiting {
    11625        const ast::Type * dst;
    11726        const ast::TypeEnvironment & typeEnv;
    11827        int result;
    11928
    120         PtrsAssignable_new( const ast::Type * dst, const ast::TypeEnvironment & env ) :
     29        PtrsAssignable( const ast::Type * dst, const ast::TypeEnvironment & env ) :
    12130                dst( dst ), typeEnv( env ), result( 0 ) {}
    12231
    123         void previsit( Type * ) { visit_children = false; }
     32        void previsit( ast::Type * ) { visit_children = false; }
    12433
    12534        void postvisit( const ast::EnumInstType * ) {
     
    15362                return -1;
    15463        } else {
    155                 ast::Pass<PtrsAssignable_new> visitor( dst, env );
     64                ast::Pass<PtrsAssignable> visitor( dst, env );
    15665                src->accept( visitor );
    15766                return visitor.core.result;
  • src/ResolvExpr/PtrsAssignable.hpp

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 class Type;
    1918namespace ast {
    2019        class Type;
     
    2423namespace ResolvExpr {
    2524
    26 class TypeEnvironment;
    27 
    28 int ptrsAssignable( const Type * src, const Type * dest,
    29         const TypeEnvironment & env );
    3025int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
    3126        const ast::TypeEnvironment & env );
  • src/ResolvExpr/PtrsCastable.cc

    rdf8ba61a r8d182b1  
    2020#include "AST/Type.hpp"
    2121#include "AST/TypeEnvironment.hpp"
    22 #include "Common/PassVisitor.h"
    2322#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    24 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    25 #include "SymTab/Indexer.h"              // for Indexer
    26 #include "SynTree/Declaration.h"         // for TypeDecl, TypeDecl::Kind::Ftype
    27 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    28 #include "SynTree/Visitor.h"             // for Visitor
    2923
    3024namespace ResolvExpr {
    31         struct PtrsCastable_old : public WithShortCircuiting  {
    32           public:
    33                 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
    34 
    35                 int get_result() const { return result; }
    36 
    37                 void previsit( const Type * ) { visit_children = false; }
    38 
    39                 void postvisit( const VoidType * voidType );
    40                 void postvisit( const BasicType * basicType );
    41                 void postvisit( const PointerType * pointerType );
    42                 void postvisit( const ArrayType * arrayType );
    43                 void postvisit( const FunctionType * functionType );
    44                 void postvisit( const StructInstType * inst );
    45                 void postvisit( const UnionInstType * inst );
    46                 void postvisit( const EnumInstType * inst );
    47                 void postvisit( const TraitInstType * inst );
    48                 void postvisit( const TypeInstType * inst );
    49                 void postvisit( const TupleType * tupleType );
    50                 void postvisit( const VarArgsType * varArgsType );
    51                 void postvisit( const ZeroType * zeroType );
    52                 void postvisit( const OneType * oneType );
    53           private:
    54                 const Type * dest;
    55                 int result;
    56                 const TypeEnvironment &env;
    57                 const SymTab::Indexer &indexer;
    58         };
    59 
    60         namespace {
    61                 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    62                         if ( dynamic_cast< const FunctionType* >( src ) ) {
    63                                 return -1;
    64                         } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {
    65                                 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {
    66                                         if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {
    67                                                 if ( tyDecl->kind == TypeDecl::Ftype ) {
    68                                                         return -1;
    69                                                 } // if
    70                                         } //if
    71                                 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    72                                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    73                                                 return -1;
    74                                         } // if
    75                                 } // if
    76                         } //if
    77                         return 1;
    78                 }
    79                 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    80                         return -1 * objectCast( src, env, indexer );  // reverse the sense of objectCast
    81                 }
    82         }
    83 
    84         int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    85                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
    86                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    87                                 // xxx - should this be ptrsCastable?
    88                                 return ptrsAssignable( src, eqvClass->type, env );
    89                         } // if
    90                 } // if
    91                 if ( dynamic_cast< const VoidType* >( dest ) ) {
    92                         return objectCast( src, env, indexer );
    93                 } else {
    94                         PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );
    95                         src->accept( ptrs );
    96                         return ptrs.pass.get_result();
    97                 } // if
    98         }
    99 
    100         PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )
    101                 : dest( dest ), result( 0 ), env( env ), indexer( indexer )     {
    102         }
    103 
    104         void PtrsCastable_old::postvisit( const VoidType * ) {
    105                 result = objectCast( dest, env, indexer );
    106         }
    107 
    108         void PtrsCastable_old::postvisit( const BasicType * ) {
    109                 result = objectCast( dest, env, indexer );
    110         }
    111 
    112         void PtrsCastable_old::postvisit( const PointerType * ) {
    113                 result = objectCast( dest, env, indexer );
    114         }
    115 
    116         void PtrsCastable_old::postvisit( const ArrayType * ) {
    117                 result = objectCast( dest, env, indexer );
    118         }
    119 
    120         void PtrsCastable_old::postvisit( const FunctionType * ) {
    121                 // result = -1;
    122                 result = functionCast( dest, env, indexer );
    123         }
    124 
    125         void PtrsCastable_old::postvisit( const StructInstType * ) {
    126                 result = objectCast( dest, env, indexer );
    127         }
    128 
    129         void PtrsCastable_old::postvisit( const UnionInstType * ) {
    130                 result = objectCast( dest, env, indexer );
    131         }
    132 
    133         void PtrsCastable_old::postvisit( const EnumInstType * ) {
    134                 if ( dynamic_cast< const EnumInstType * >( dest ) ) {
    135                         result = 1;
    136                 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {
    137                         if ( bt->kind == BasicType::SignedInt ) {
    138                                 result = 0;
    139                         } else {
    140                                 result = 1;
    141                         }
    142                 } else {
    143                         result = objectCast( dest, env, indexer );
    144                 }
    145         }
    146 
    147         void PtrsCastable_old::postvisit( const TraitInstType * ) {}
    148 
    149         void PtrsCastable_old::postvisit( const TypeInstType *inst ) {
    150                 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;
    151                 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;
    152         }
    153 
    154         void PtrsCastable_old::postvisit( const TupleType * ) {
    155                 result = objectCast( dest, env, indexer );
    156         }
    157 
    158         void PtrsCastable_old::postvisit( const VarArgsType * ) {
    159                 result = objectCast( dest, env, indexer );
    160         }
    161 
    162         void PtrsCastable_old::postvisit( const ZeroType * ) {
    163                 result = objectCast( dest, env, indexer );
    164         }
    165 
    166         void PtrsCastable_old::postvisit( const OneType * ) {
    167                 result = objectCast( dest, env, indexer );
    168         }
    16925
    17026namespace {
     
    19955        }
    20056
    201         class PtrsCastable_new : public ast::WithShortCircuiting {
     57        class PtrsCastable : public ast::WithShortCircuiting {
    20258                const ast::Type * dst;
    20359                const ast::TypeEnvironment & env;
     
    20662                int result;
    20763
    208                 PtrsCastable_new(
     64                PtrsCastable(
    20965                        const ast::Type * d, const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    21066                : dst( d ), env( e ), symtab( syms ), result( 0 ) {}
     
    293149                return objectCast( src, env, symtab );
    294150        } else {
    295                 return ast::Pass<PtrsCastable_new>::read( src, dst, env, symtab );
     151                return ast::Pass<PtrsCastable>::read( src, dst, env, symtab );
    296152        }
    297153}
  • src/ResolvExpr/PtrsCastable.hpp

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 class Type;
    19 namespace SymTab {
    20     class Indexer;
    21 }
    2218namespace ast {
    2319    class SymbolTable;
     
    2824namespace ResolvExpr {
    2925
    30 class TypeEnvironment;
    31 
    32 int ptrsCastable(
    33         const Type * src, const Type * dst,
    34         const TypeEnvironment & env, const SymTab::Indexer & indexer );
    3526int ptrsCastable(
    3627        const ast::Type * src, const ast::Type * dst,
  • src/ResolvExpr/RenameVars.cc

    rdf8ba61a r8d182b1  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
    23 #include "Common/PassVisitor.h"
    2423#include "Common/ScopedMap.h"
    2524#include "Common/SemanticError.h"  // for SemanticError
    2625#include "RenameVars.h"
    27 #include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
    28 #include "SynTree/Expression.h"    // for Expression
    29 #include "SynTree/Type.h"          // for Type, TypeInstType, TraitInstType
    30 #include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3126
    3227#include "AST/Copy.hpp"
     
    4944                }
    5045
    51                 void rename( TypeInstType * type ) {
    52                         auto it = nameMap.find( type->name );
    53                         if ( it != nameMap.end() ) {
    54                                 type->name = it->second;
    55                         }
    56                 }
    57 
    5846                void nextUsage() {
    5947                        ++next_usage_id;
    60                 }
    61 
    62                 void openLevel( Type * type ) {
    63                         if ( ! type->forall.empty() ) {
    64                                 nameMap.beginScope();
    65                                 // renames all "forall" type names to `_${level}_${name}'
    66                                 for ( auto td : type->forall ) {
    67                                         std::ostringstream output;
    68                                         output << "_" << resetCount << "_" << level << "_" << td->name;
    69                                         std::string newname( output.str() );
    70                                         nameMap[ td->get_name() ] = newname;
    71                                         td->name = newname;
    72                                         // ditto for assertion names, the next level in
    73                                         level++;
    74                                 }
    75                         }
    76                 }
    77 
    78                 void closeLevel( Type * type ) {
    79                         if ( !type->forall.empty() ) {
    80                                 nameMap.endScope();
    81                         }
    8248                }
    8349
     
    135101        RenamingData renaming;
    136102
    137         struct RenameVars_old {
    138                 void previsit( TypeInstType * instType ) {
    139                         renaming.openLevel( (Type*)instType );
    140                         renaming.rename( instType );
    141                 }
    142                 void previsit( Type * type ) {
    143                         renaming.openLevel( type );
    144                 }
    145                 void postvisit( Type * type ) {
    146                         renaming.closeLevel( type );
    147                 }
    148         };
    149 
    150         struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
     103        struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    151104                RenameMode mode;
    152105
     
    178131} // namespace
    179132
    180 void renameTyVars( Type * t ) {
    181         PassVisitor<RenameVars_old> renamer;
    182         t->accept( renamer );
    183 }
    184 
    185133const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
    186         ast::Pass<RenameVars_new> renamer;
     134        ast::Pass<RenameVars> renamer;
    187135        renamer.core.mode = mode;
    188136        if (mode == GEN_USAGE && reset) {
  • src/ResolvExpr/RenameVars.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 #include <list>               // for list
    19 #include <map>                // for map
    20 #include <string>             // for string
    21 
    22 #include "SynTree/SynTree.h"  // for Visitor Nodes
    23 #include "SynTree/Visitor.h"  // for Visitor
    24 
    2518namespace ast {
    2619        class Type;
     
    2821
    2922namespace ResolvExpr {
    30         /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    31         void renameTyVars( Type * );
    32 
    3323        enum RenameMode {
    3424                GEN_USAGE, // for type in VariableExpr
  • src/ResolvExpr/ResolveTypeof.cc

    rdf8ba61a r8d182b1  
    2424#include "AST/Type.hpp"
    2525#include "AST/TypeEnvironment.hpp"
    26 #include "Common/PassVisitor.h"   // for PassVisitor
    2726#include "Common/utility.h"       // for copy
    2827#include "InitTweak/InitTweak.h"  // for isConstExpr
     
    3029#include "Resolver.h"  // for resolveInVoidContext
    3130#include "SymTab/Mangler.h"
    32 #include "SynTree/Expression.h"  // for Expression
    33 #include "SynTree/Mutator.h"     // for Mutator
    34 #include "SynTree/Type.h"        // for TypeofType, Type
    35 
    36 namespace SymTab {
    37 class Indexer;
    38 }  // namespace SymTab
    3931
    4032namespace ResolvExpr {
    41 namespace {
    42 #if 0
    43                 void
    44                 printAlts( const AltList &list, std::ostream &os, int indent = 0 )
    45                 {
    46                         for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    47                                 i->print( os, indent );
    48                                 os << std::endl;
    49                         }
    50                 }
    51 #endif
    52         }
    53 
    54 class ResolveTypeof_old : public WithShortCircuiting {
    55    public:
    56                 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}
    57                 void premutate( TypeofType *typeofType );
    58                 Type * postmutate( TypeofType *typeofType );
    59 
    60    private:
    61     const SymTab::Indexer &indexer;
    62 };
    63 
    64         Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {
    65                 PassVisitor<ResolveTypeof_old> mutator( indexer );
    66                 return type->acceptMutator( mutator );
    67         }
    68 
    69         void ResolveTypeof_old::premutate( TypeofType * ) {
    70                 visit_children = false;
    71         }
    72 
    73     Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {
    74 #if 0
    75                 std::cerr << "resolving typeof: ";
    76                 typeofType->print( std::cerr );
    77                 std::cerr << std::endl;
    78 #endif
    79     // pass on null expression
    80                 if ( ! typeofType->expr ) return typeofType;
    81 
    82     bool isBasetypeof = typeofType->is_basetypeof;
    83     auto oldQuals = typeofType->get_qualifiers().val;
    84 
    85     Type* newType;
    86                 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {
    87         // typeof wrapping type
    88         newType = tyExpr->type;
    89         tyExpr->type = nullptr;
    90         delete tyExpr;
    91     } else {
    92         // typeof wrapping expression
    93                         Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );
    94                         assert( newExpr->result && ! newExpr->result->isVoid() );
    95         newType = newExpr->result;
    96         newExpr->result = nullptr;
    97         delete typeofType;
    98         delete newExpr;
    99     }
    100 
    101     // clear qualifiers for base, combine with typeoftype quals in any case
    102     if ( isBasetypeof ) {
    103                         // replace basetypeof(<enum>) by int
    104                         if ( dynamic_cast<EnumInstType*>(newType) ) {
    105                                 Type* newerType =
    106                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
    107                                         newType->attributes };
    108                                 delete newType;
    109                                 newType = newerType;
    110                         }
    111                         newType->get_qualifiers().val
    112                                 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    113                 } else {
    114         newType->get_qualifiers().val |= oldQuals;
    115     }
    116 
    117     return newType;
    118 }
    11933
    12034namespace {
    121 struct ResolveTypeof_new : public ast::WithShortCircuiting {
     35struct ResolveTypeof : public ast::WithShortCircuiting {
    12236    const ResolveContext & context;
    12337
    124                 ResolveTypeof_new( const ResolveContext & context ) :
     38                ResolveTypeof( const ResolveContext & context ) :
    12539                        context( context ) {}
    12640
     
    16478
    16579const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) {
    166         ast::Pass< ResolveTypeof_new > mutator( context );
     80        ast::Pass< ResolveTypeof > mutator( context );
    16781        return type->accept( mutator );
    16882}
  • src/ResolvExpr/ResolveTypeof.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 class Type;
    19 namespace SymTab {
    20 class Indexer;
    21 }  // namespace SymTab
    2218namespace ast {
    2319        class Type;
     
    2824        struct ResolveContext;
    2925
    30         Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
    3126        const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
    3227        const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
    3328        const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
    34         const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext &);
     29        const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );
    3530} // namespace ResolvExpr
    3631
  • src/ResolvExpr/Resolver.cc

    rdf8ba61a r8d182b1  
    1919#include <vector>                        // for vector
    2020
    21 #include "Alternative.h"                 // for Alternative, AltList
    22 #include "AlternativeFinder.h"           // for AlternativeFinder, resolveIn...
    2321#include "Candidate.hpp"
    2422#include "CandidateFinder.hpp"
     
    4038#include "Common/Eval.h"                 // for eval
    4139#include "Common/Iterate.hpp"            // for group_iterate
    42 #include "Common/PassVisitor.h"          // for PassVisitor
    4340#include "Common/SemanticError.h"        // for SemanticError
    4441#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    4542#include "Common/ToString.hpp"           // for toCString
     43#include "Common/UniqueName.h"           // for UniqueName
    4644#include "InitTweak/GenInit.h"
    4745#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
    48 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    49 #include "SymTab/Autogen.h"              // for SizeType
    50 #include "SymTab/Indexer.h"              // for Indexer
    5146#include "SymTab/Mangler.h"              // for Mangler
    52 #include "SynTree/Declaration.h"         // for ObjectDecl, TypeDecl, Declar...
    53 #include "SynTree/Expression.h"          // for Expression, CastExpr, InitExpr
    54 #include "SynTree/Initializer.h"         // for ConstructorInit, SingleInit
    55 #include "SynTree/Statement.h"           // for ForStmt, Statement, BranchStmt
    56 #include "SynTree/Type.h"                // for Type, BasicType, PointerType
    57 #include "SynTree/TypeSubstitution.h"    // for TypeSubstitution
    58 #include "SynTree/Visitor.h"             // for acceptAll, maybeAccept
    5947#include "Tuples/Tuples.h"
    6048#include "Validate/FindSpecialDecls.h"   // for SizeType
     
    6351
    6452namespace ResolvExpr {
    65         struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {
    66                 Resolver_old() {}
    67                 Resolver_old( const SymTab::Indexer & other ) {
    68                         indexer = other;
    69                 }
    70 
    71                 void previsit( FunctionDecl * functionDecl );
    72                 void postvisit( FunctionDecl * functionDecl );
    73                 void previsit( ObjectDecl * objectDecll );
    74                 void previsit( EnumDecl * enumDecl );
    75                 void previsit( StaticAssertDecl * assertDecl );
    76 
    77                 void previsit( ArrayType * at );
    78                 void previsit( PointerType * at );
    79 
    80                 void previsit( ExprStmt * exprStmt );
    81                 void previsit( AsmExpr * asmExpr );
    82                 void previsit( AsmStmt * asmStmt );
    83                 void previsit( IfStmt * ifStmt );
    84                 void previsit( WhileDoStmt * whileDoStmt );
    85                 void previsit( ForStmt * forStmt );
    86                 void previsit( SwitchStmt * switchStmt );
    87                 void previsit( CaseStmt * caseStmt );
    88                 void previsit( BranchStmt * branchStmt );
    89                 void previsit( ReturnStmt * returnStmt );
    90                 void previsit( ThrowStmt * throwStmt );
    91                 void previsit( CatchStmt * catchStmt );
    92                 void postvisit( CatchStmt * catchStmt );
    93                 void previsit( WaitForStmt * stmt );
    94 
    95                 void previsit( SingleInit * singleInit );
    96                 void previsit( ListInit * listInit );
    97                 void previsit( ConstructorInit * ctorInit );
    98           private:
    99                 typedef std::list< Initializer * >::iterator InitIterator;
    100 
    101                 template< typename PtrType >
    102                 void handlePtrType( PtrType * type );
    103 
    104                 void fallbackInit( ConstructorInit * ctorInit );
    105 
    106                 Type * functionReturn = nullptr;
    107                 CurrentObject currentObject = nullptr;
    108                 bool inEnumDecl = false;
    109         };
    110 
    111         struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {
    112                 void previsit( FunctionDecl * );
    113                 void previsit( WithStmt * );
    114 
    115                 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );
    116         };
    117 
    118         void resolve( std::list< Declaration * > translationUnit ) {
    119                 PassVisitor<Resolver_old> resolver;
    120                 acceptAll( translationUnit, resolver );
    121         }
    122 
    123         void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {
    124                 PassVisitor<Resolver_old> resolver( indexer );
    125                 maybeAccept( decl, resolver );
    126         }
    127 
    128         namespace {
    129                 struct DeleteFinder_old : public WithShortCircuiting    {
    130                         DeletedExpr * delExpr = nullptr;
    131                         void previsit( DeletedExpr * expr ) {
    132                                 if ( delExpr ) visit_children = false;
    133                                 else delExpr = expr;
    134                         }
    135 
    136                         void previsit( Expression * ) {
    137                                 if ( delExpr ) visit_children = false;
    138                         }
    139                 };
    140         }
    141 
    142         DeletedExpr * findDeletedExpr( Expression * expr ) {
    143                 PassVisitor<DeleteFinder_old> finder;
    144                 expr->accept( finder );
    145                 return finder.pass.delExpr;
    146         }
    147 
    148         namespace {
    149                 struct StripCasts_old {
    150                         Expression * postmutate( CastExpr * castExpr ) {
    151                                 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
    152                                         // generated cast is to the same type as its argument, so it's unnecessary -- remove it
    153                                         Expression * expr = castExpr->arg;
    154                                         castExpr->arg = nullptr;
    155                                         std::swap( expr->env, castExpr->env );
    156                                         return expr;
    157                                 }
    158                                 return castExpr;
    159                         }
    160 
    161                         static void strip( Expression *& expr ) {
    162                                 PassVisitor<StripCasts_old> stripper;
    163                                 expr = expr->acceptMutator( stripper );
    164                         }
    165                 };
    166 
    167                 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {
    168                         expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
    169                         env.makeSubstitution( *expr->env );
    170                         StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression
    171                 }
    172 
    173                 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {
    174                         if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    175                                 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {
    176                                         // cast is to the same type as its argument, so it's unnecessary -- remove it
    177                                         expr = castExpr->arg;
    178                                         castExpr->arg = nullptr;
    179                                         std::swap( expr->env, castExpr->env );
    180                                         delete castExpr;
    181                                 }
    182                         }
    183                 }
    184         } // namespace
    185 
    186         namespace {
    187                 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
    188                         assertf( untyped, "expected a non-null expression." );
    189 
    190                         // xxx - this isn't thread-safe, but should work until we parallelize the resolver
    191                         static unsigned recursion_level = 0;
    192 
    193                         ++recursion_level;
    194                         TypeEnvironment env;
    195                         AlternativeFinder finder( indexer, env );
    196                         finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
    197                         --recursion_level;
    198 
    199                         #if 0
    200                         if ( finder.get_alternatives().size() != 1 ) {
    201                                 std::cerr << "untyped expr is ";
    202                                 untyped->print( std::cerr );
    203                                 std::cerr << std::endl << "alternatives are:";
    204                                 for ( const Alternative & alt : finder.get_alternatives() ) {
    205                                         alt.print( std::cerr );
    206                                 } // for
    207                         } // if
    208                         #endif
    209 
    210                         // produce filtered list of alternatives
    211                         AltList candidates;
    212                         for ( Alternative & alt : finder.get_alternatives() ) {
    213                                 if ( pred( alt ) ) {
    214                                         candidates.push_back( std::move( alt ) );
    215                                 }
    216                         }
    217 
    218                         // produce invalid error if no candidates
    219                         if ( candidates.empty() ) {
    220                                 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
    221                         }
    222 
    223                         // search for cheapest candidate
    224                         AltList winners;
    225                         bool seen_undeleted = false;
    226                         for ( unsigned i = 0; i < candidates.size(); ++i ) {
    227                                 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );
    228 
    229                                 if ( c > 0 ) continue; // skip more expensive than winner
    230 
    231                                 if ( c < 0 ) {
    232                                         // reset on new cheapest
    233                                         seen_undeleted = ! findDeletedExpr( candidates[i].expr );
    234                                         winners.clear();
    235                                 } else /* if ( c == 0 ) */ {
    236                                         if ( findDeletedExpr( candidates[i].expr ) ) {
    237                                                 // skip deleted expression if already seen one equivalent-cost not
    238                                                 if ( seen_undeleted ) continue;
    239                                         } else if ( ! seen_undeleted ) {
    240                                                 // replace list of equivalent-cost deleted expressions with one non-deleted
    241                                                 winners.clear();
    242                                                 seen_undeleted = true;
    243                                         }
    244                                 }
    245 
    246                                 winners.emplace_back( std::move( candidates[i] ) );
    247                         }
    248 
    249                         // promote alternative.cvtCost to .cost
    250                         // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost
    251                         for ( Alternative& winner : winners ) {
    252                                 winner.cost = winner.cvtCost;
    253                         }
    254 
    255                         // produce ambiguous errors, if applicable
    256                         if ( winners.size() != 1 ) {
    257                                 std::ostringstream stream;
    258                                 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
    259                                 untyped->print( stream );
    260                                 stream << " Alternatives are:\n";
    261                                 printAlts( winners, stream, 1 );
    262                                 SemanticError( untyped->location, stream.str() );
    263                         }
    264 
    265                         // single selected choice
    266                         Alternative& choice = winners.front();
    267 
    268                         // fail on only expression deleted
    269                         if ( ! seen_undeleted ) {
    270                                 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );
    271                         }
    272 
    273                         // xxx - check for ambiguous expressions
    274 
    275                         // output selected choice
    276                         alt = std::move( choice );
    277                 }
    278 
    279                 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
    280                 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {
    281                         if ( ! untyped ) return;
    282                         Alternative choice;
    283                         findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );
    284                         finishExpr( choice.expr, choice.env, untyped->env );
    285                         delete untyped;
    286                         untyped = choice.expr;
    287                         choice.expr = nullptr;
    288                 }
    289 
    290                 bool standardAlternativeFilter( const Alternative & ) {
    291                         // currently don't need to filter, under normal circumstances.
    292                         // in the future, this may be useful for removing deleted expressions
    293                         return true;
    294                 }
    295         } // namespace
    296 
    297         // used in resolveTypeof
    298         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {
    299                 TypeEnvironment env;
    300                 return resolveInVoidContext( expr, indexer, env );
    301         }
    302 
    303         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {
    304                 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
    305                 // interpretations, an exception has already been thrown.
    306                 assertf( expr, "expected a non-null expression." );
    307 
    308                 CastExpr * untyped = new CastExpr( expr ); // cast to void
    309                 untyped->location = expr->location;
    310 
    311                 // set up and resolve expression cast to void
    312                 Alternative choice;
    313                 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    314                 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
    315                 assert( castExpr );
    316                 env = std::move( choice.env );
    317 
    318                 // clean up resolved expression
    319                 Expression * ret = castExpr->arg;
    320                 castExpr->arg = nullptr;
    321 
    322                 // unlink the arg so that it isn't deleted twice at the end of the program
    323                 untyped->arg = nullptr;
    324                 return ret;
    325         }
    326 
    327         void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    328                 resetTyVarRenaming();
    329                 TypeEnvironment env;
    330                 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );
    331                 finishExpr( newExpr, env, untyped->env );
    332                 delete untyped;
    333                 untyped = newExpr;
    334         }
    335 
    336         void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    337                 findKindExpression( untyped, indexer, "", standardAlternativeFilter );
    338         }
    339 
    340         void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {
    341                 assert( untyped && type );
    342                 // transfer location to generated cast for error purposes
    343                 CodeLocation location = untyped->location;
    344                 untyped = new CastExpr( untyped, type );
    345                 untyped->location = location;
    346                 findSingleExpression( untyped, indexer );
    347                 removeExtraneousCast( untyped, indexer );
    348         }
    349 
    350         namespace {
    351                 bool isIntegralType( const Alternative & alt ) {
    352                         Type * type = alt.expr->result;
    353                         if ( dynamic_cast< EnumInstType * >( type ) ) {
    354                                 return true;
    355                         } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {
    356                                 return bt->isInteger();
    357                         } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {
    358                                 return true;
    359                         } else {
    360                                 return false;
    361                         } // if
    362                 }
    363 
    364                 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    365                         findKindExpression( untyped, indexer, "condition", isIntegralType );
    366                 }
    367         }
    368 
    369 
    370         bool isStructOrUnion( const Alternative & alt ) {
    371                 Type * t = alt.expr->result->stripReferences();
    372                 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
    373         }
    374 
    375         void resolveWithExprs( std::list< Declaration * > & translationUnit ) {
    376                 PassVisitor<ResolveWithExprs> resolver;
    377                 acceptAll( translationUnit, resolver );
    378         }
    379 
    380         void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {
    381                 for ( Expression *& expr : withExprs )  {
    382                         // only struct- and union-typed expressions are viable candidates
    383                         findKindExpression( expr, indexer, "with statement", isStructOrUnion );
    384 
    385                         // if with expression might be impure, create a temporary so that it is evaluated once
    386                         if ( Tuples::maybeImpure( expr ) ) {
    387                                 static UniqueName tmpNamer( "_with_tmp_" );
    388                                 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );
    389                                 expr = new VariableExpr( tmp );
    390                                 newStmts.push_back( new DeclStmt( tmp ) );
    391                                 if ( InitTweak::isConstructable( tmp->type ) ) {
    392                                         // generate ctor/dtor and resolve them
    393                                         tmp->init = InitTweak::genCtorInit( tmp );
    394                                         tmp->accept( *visitor );
    395                                 }
    396                         }
    397                 }
    398         }
    399 
    400         void ResolveWithExprs::previsit( WithStmt * withStmt ) {
    401                 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );
    402         }
    403 
    404         void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {
    405                 {
    406                         // resolve with-exprs with parameters in scope and add any newly generated declarations to the
    407                         // front of the function body.
    408                         auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );
    409                         indexer.addFunctionType( functionDecl->type );
    410                         std::list< Statement * > newStmts;
    411                         resolveWithExprs( functionDecl->withExprs, newStmts );
    412                         if ( functionDecl->statements ) {
    413                                 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );
    414                         } else {
    415                                 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );
    416                         }
    417                 }
    418         }
    419 
    420         void Resolver_old::previsit( ObjectDecl * objectDecl ) {
    421                 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
    422                 // class-variable initContext is changed multiple time because the LHS is analysed twice.
    423                 // The second analysis changes initContext because of a function type can contain object
    424                 // declarations in the return and parameter types. So each value of initContext is
    425                 // retained, so the type on the first analysis is preserved and used for selecting the RHS.
    426                 GuardValue( currentObject );
    427                 currentObject = CurrentObject( objectDecl->get_type() );
    428                 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {
    429                         // enumerator initializers should not use the enum type to initialize, since
    430                         // the enum type is still incomplete at this point. Use signed int instead.
    431                         // TODO: BasicType::SignedInt may not longer be true
    432                         currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    433                 }
    434         }
    435 
    436         template< typename PtrType >
    437         void Resolver_old::handlePtrType( PtrType * type ) {
    438                 if ( type->get_dimension() ) {
    439                         findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    440                 }
    441         }
    442 
    443         void Resolver_old::previsit( ArrayType * at ) {
    444                 handlePtrType( at );
    445         }
    446 
    447         void Resolver_old::previsit( PointerType * pt ) {
    448                 handlePtrType( pt );
    449         }
    450 
    451         void Resolver_old::previsit( FunctionDecl * functionDecl ) {
    452 #if 0
    453                 std::cerr << "resolver visiting functiondecl ";
    454                 functionDecl->print( std::cerr );
    455                 std::cerr << std::endl;
    456 #endif
    457                 GuardValue( functionReturn );
    458                 functionReturn = ResolvExpr::extractResultType( functionDecl->type );
    459         }
    460 
    461         void Resolver_old::postvisit( FunctionDecl * functionDecl ) {
    462                 // default value expressions have an environment which shouldn't be there and trips up
    463                 // later passes.
    464                 // xxx - it might be necessary to somehow keep the information from this environment, but I
    465                 // can't currently see how it's useful.
    466                 for ( Declaration * d : functionDecl->type->parameters ) {
    467                         if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {
    468                                 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {
    469                                         delete init->value->env;
    470                                         init->value->env = nullptr;
    471                                 }
    472                         }
    473                 }
    474         }
    475 
    476         void Resolver_old::previsit( EnumDecl * ) {
    477                 // in case we decide to allow nested enums
    478                 GuardValue( inEnumDecl );
    479                 inEnumDecl = true;
    480         }
    481 
    482         void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {
    483                 findIntegralExpression( assertDecl->condition, indexer );
    484         }
    485 
    486         void Resolver_old::previsit( ExprStmt * exprStmt ) {
    487                 visit_children = false;
    488                 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );
    489                 findVoidExpression( exprStmt->expr, indexer );
    490         }
    491 
    492         void Resolver_old::previsit( AsmExpr * asmExpr ) {
    493                 visit_children = false;
    494                 findVoidExpression( asmExpr->operand, indexer );
    495         }
    496 
    497         void Resolver_old::previsit( AsmStmt * asmStmt ) {
    498                 visit_children = false;
    499                 acceptAll( asmStmt->get_input(), *visitor );
    500                 acceptAll( asmStmt->get_output(), *visitor );
    501         }
    502 
    503         void Resolver_old::previsit( IfStmt * ifStmt ) {
    504                 findIntegralExpression( ifStmt->condition, indexer );
    505         }
    506 
    507         void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {
    508                 findIntegralExpression( whileDoStmt->condition, indexer );
    509         }
    510 
    511         void Resolver_old::previsit( ForStmt * forStmt ) {
    512                 if ( forStmt->condition ) {
    513                         findIntegralExpression( forStmt->condition, indexer );
    514                 } // if
    515 
    516                 if ( forStmt->increment ) {
    517                         findVoidExpression( forStmt->increment, indexer );
    518                 } // if
    519         }
    520 
    521         void Resolver_old::previsit( SwitchStmt * switchStmt ) {
    522                 GuardValue( currentObject );
    523                 findIntegralExpression( switchStmt->condition, indexer );
    524 
    525                 currentObject = CurrentObject( switchStmt->condition->result );
    526         }
    527 
    528         void Resolver_old::previsit( CaseStmt * caseStmt ) {
    529                 if ( caseStmt->condition ) {
    530                         std::list< InitAlternative > initAlts = currentObject.getOptions();
    531                         assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );
    532                         // must remove cast from case statement because RangeExpr cannot be cast.
    533                         Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );
    534                         findSingleExpression( newExpr, indexer );
    535                         // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.
    536                         // Ideally we would perform the conversion internally here.
    537                         if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {
    538                                 newExpr = castExpr->arg;
    539                                 castExpr->arg = nullptr;
    540                                 std::swap( newExpr->env, castExpr->env );
    541                                 delete castExpr;
    542                         }
    543                         caseStmt->condition = newExpr;
    544                 }
    545         }
    546 
    547         void Resolver_old::previsit( BranchStmt * branchStmt ) {
    548                 visit_children = false;
    549                 // must resolve the argument for a computed goto
    550                 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement
    551                         if ( branchStmt->computedTarget ) {
    552                                 // computed goto argument is void *
    553                                 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );
    554                         } // if
    555                 } // if
    556         }
    557 
    558         void Resolver_old::previsit( ReturnStmt * returnStmt ) {
    559                 visit_children = false;
    560                 if ( returnStmt->expr ) {
    561                         findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );
    562                 } // if
    563         }
    564 
    565         void Resolver_old::previsit( ThrowStmt * throwStmt ) {
    566                 visit_children = false;
    567                 // TODO: Replace *exception type with &exception type.
    568                 if ( throwStmt->get_expr() ) {
    569                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
    570                         assert( exception_decl );
    571                         Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
    572                         findSingleExpression( throwStmt->expr, exceptType, indexer );
    573                 }
    574         }
    575 
    576         void Resolver_old::previsit( CatchStmt * catchStmt ) {
    577                 // Until we are very sure this invarent (ifs that move between passes have then)
    578                 // holds, check it. This allows a check for when to decode the mangling.
    579                 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
    580                         assert( ifStmt->then );
    581                 }
    582                 // Encode the catchStmt so the condition can see the declaration.
    583                 if ( catchStmt->cond ) {
    584                         IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
    585                         catchStmt->cond = nullptr;
    586                         catchStmt->body = ifStmt;
    587                 }
    588         }
    589 
    590         void Resolver_old::postvisit( CatchStmt * catchStmt ) {
    591                 // Decode the catchStmt so everything is stored properly.
    592                 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
    593                 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
    594                         assert( ifStmt->condition );
    595                         assert( ifStmt->else_ );
    596                         catchStmt->cond = ifStmt->condition;
    597                         catchStmt->body = ifStmt->else_;
    598                         ifStmt->condition = nullptr;
    599                         ifStmt->else_ = nullptr;
    600                         delete ifStmt;
    601                 }
    602         }
    603 
    60453        template< typename iterator_t >
    60554        inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) {
     
    61160        }
    61261
    613         void Resolver_old::previsit( WaitForStmt * stmt ) {
    614                 visit_children = false;
    615 
    616                 // Resolve all clauses first
    617                 for( auto& clause : stmt->clauses ) {
    618 
    619                         TypeEnvironment env;
    620                         AlternativeFinder funcFinder( indexer, env );
    621 
    622                         // Find all alternatives for a function in canonical form
    623                         funcFinder.findWithAdjustment( clause.target.function );
    624 
    625                         if ( funcFinder.get_alternatives().empty() ) {
    626                                 stringstream ss;
    627                                 ss << "Use of undeclared indentifier '";
    628                                 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;
    629                                 ss << "' in call to waitfor";
    630                                 SemanticError( stmt->location, ss.str() );
    631                         }
    632 
    633                         if(clause.target.arguments.empty()) {
    634                                 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");
    635                         }
    636 
    637                         // Find all alternatives for all arguments in canonical form
    638                         std::vector< AlternativeFinder > argAlternatives;
    639                         funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );
    640 
    641                         // List all combinations of arguments
    642                         std::vector< AltList > possibilities;
    643                         combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
    644 
    645                         AltList                func_candidates;
    646                         std::vector< AltList > args_candidates;
    647 
    648                         // For every possible function :
    649                         //      try matching the arguments to the parameters
    650                         //      not the other way around because we have more arguments than parameters
    651                         SemanticErrorException errors;
    652                         for ( Alternative & func : funcFinder.get_alternatives() ) {
    653                                 try {
    654                                         PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );
    655                                         if( !pointer ) {
    656                                                 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );
    657                                         }
    658 
    659                                         FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );
    660                                         if( !function ) {
    661                                                 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );
    662                                         }
    663 
    664 
    665                                         {
    666                                                 auto param     = function->parameters.begin();
    667                                                 auto param_end = function->parameters.end();
    668 
    669                                                 if( !advance_to_mutex( param, param_end ) ) {
    670                                                         SemanticError(function, "candidate function not viable: no mutex parameters\n");
    671                                                 }
    672                                         }
    673 
    674                                         Alternative newFunc( func );
    675                                         // Strip reference from function
    676                                         referenceToRvalueConversion( newFunc.expr, newFunc.cost );
    677 
    678                                         // For all the set of arguments we have try to match it with the parameter of the current function alternative
    679                                         for ( auto & argsList : possibilities ) {
    680 
    681                                                 try {
    682                                                         // Declare data structures need for resolution
    683                                                         OpenVarSet openVars;
    684                                                         AssertionSet resultNeed, resultHave;
    685                                                         TypeEnvironment resultEnv( func.env );
    686                                                         makeUnifiableVars( function, openVars, resultNeed );
    687                                                         // add all type variables as open variables now so that those not used in the parameter
    688                                                         // list are still considered open.
    689                                                         resultEnv.add( function->forall );
    690 
    691                                                         // Load type variables from arguemnts into one shared space
    692                                                         simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );
    693 
    694                                                         // Make sure we don't widen any existing bindings
    695                                                         resultEnv.forbidWidening();
    696 
    697                                                         // Find any unbound type variables
    698                                                         resultEnv.extractOpenVars( openVars );
    699 
    700                                                         auto param     = function->parameters.begin();
    701                                                         auto param_end = function->parameters.end();
    702 
    703                                                         int n_mutex_param = 0;
    704 
    705                                                         // For every arguments of its set, check if it matches one of the parameter
    706                                                         // The order is important
    707                                                         for( auto & arg : argsList ) {
    708 
    709                                                                 // Ignore non-mutex arguments
    710                                                                 if( !advance_to_mutex( param, param_end ) ) {
    711                                                                         // We ran out of parameters but still have arguments
    712                                                                         // this function doesn't match
    713                                                                         SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));
    714                                                                 }
    715 
    716                                                                 n_mutex_param++;
    717 
    718                                                                 // Check if the argument matches the parameter type in the current scope
    719                                                                 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {
    720                                                                         // Type doesn't match
    721                                                                         stringstream ss;
    722                                                                         ss << "candidate function not viable: no known convertion from '";
    723                                                                         (*param)->get_type()->print( ss );
    724                                                                         ss << "' to '";
    725                                                                         arg.expr->get_result()->print( ss );
    726                                                                         ss << "' with env '";
    727                                                                         resultEnv.print(ss);
    728                                                                         ss << "'\n";
    729                                                                         SemanticError( function, ss.str() );
    730                                                                 }
    731 
    732                                                                 param++;
    733                                                         }
    734 
    735                                                         // All arguments match !
    736 
    737                                                         // Check if parameters are missing
    738                                                         if( advance_to_mutex( param, param_end ) ) {
    739                                                                 do {
    740                                                                         n_mutex_param++;
    741                                                                         param++;
    742                                                                 } while( advance_to_mutex( param, param_end ) );
    743 
    744                                                                 // We ran out of arguments but still have parameters left
    745                                                                 // this function doesn't match
    746                                                                 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));
    747                                                         }
    748 
    749                                                         // All parameters match !
    750 
    751                                                         // Finish the expressions to tie in the proper environments
    752                                                         finishExpr( newFunc.expr, resultEnv );
    753                                                         for( Alternative & alt : argsList ) {
    754                                                                 finishExpr( alt.expr, resultEnv );
    755                                                         }
    756 
    757                                                         // This is a match store it and save it for later
    758                                                         func_candidates.push_back( newFunc );
    759                                                         args_candidates.push_back( argsList );
    760 
    761                                                 }
    762                                                 catch( SemanticErrorException & e ) {
    763                                                         errors.append( e );
    764                                                 }
    765                                         }
    766                                 }
    767                                 catch( SemanticErrorException & e ) {
    768                                         errors.append( e );
    769                                 }
    770                         }
    771 
    772                         // Make sure we got the right number of arguments
    773                         if( func_candidates.empty() )    { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor"  ); top.append( errors ); throw top; }
    774                         if( args_candidates.empty() )    { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }
    775                         if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor"            ); top.append( errors ); throw top; }
    776                         if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor"           ); top.append( errors ); throw top; }
    777                         // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
    778 
    779                         // Swap the results from the alternative with the unresolved values.
    780                         // Alternatives will handle deletion on destruction
    781                         std::swap( clause.target.function, func_candidates.front().expr );
    782                         for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {
    783                                 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );
    784                         }
    785 
    786                         // Resolve the conditions as if it were an IfStmt
    787                         // Resolve the statments normally
    788                         findSingleExpression( clause.condition, this->indexer );
    789                         clause.statement->accept( *visitor );
    790                 }
    791 
    792 
    793                 if( stmt->timeout.statement ) {
    794                         // Resolve the timeout as an size_t for now
    795                         // Resolve the conditions as if it were an IfStmt
    796                         // Resolve the statments normally
    797                         findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );
    798                         findSingleExpression( stmt->timeout.condition, this->indexer );
    799                         stmt->timeout.statement->accept( *visitor );
    800                 }
    801 
    802                 if( stmt->orelse.statement ) {
    803                         // Resolve the conditions as if it were an IfStmt
    804                         // Resolve the statments normally
    805                         findSingleExpression( stmt->orelse.condition, this->indexer );
    806                         stmt->orelse.statement->accept( *visitor );
    807                 }
    808         }
    809 
    810         bool isCharType( Type * t ) {
    811                 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {
    812                         return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||
    813                                 bt->get_kind() == BasicType::UnsignedChar;
    814                 }
    815                 return false;
    816         }
    817 
    818         void Resolver_old::previsit( SingleInit * singleInit ) {
    819                 visit_children = false;
    820                 // resolve initialization using the possibilities as determined by the currentObject cursor
    821                 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );
    822                 findSingleExpression( newExpr, indexer );
    823                 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );
    824 
    825                 // move cursor to the object that is actually initialized
    826                 currentObject.setNext( initExpr->get_designation() );
    827 
    828                 // discard InitExpr wrapper and retain relevant pieces
    829                 newExpr = initExpr->expr;
    830                 initExpr->expr = nullptr;
    831                 std::swap( initExpr->env, newExpr->env );
    832                 // InitExpr may have inferParams in the case where the expression specializes a function
    833                 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
    834                 // sufficient.
    835                 newExpr->spliceInferParams( initExpr );
    836                 delete initExpr;
    837 
    838                 // get the actual object's type (may not exactly match what comes back from the resolver
    839                 // due to conversions)
    840                 Type * initContext = currentObject.getCurrentType();
    841 
    842                 removeExtraneousCast( newExpr, indexer );
    843 
    844                 // check if actual object's type is char[]
    845                 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {
    846                         if ( isCharType( at->get_base() ) ) {
    847                                 // check if the resolved type is char *
    848                                 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
    849                                         if ( isCharType( pt->get_base() ) ) {
    850                                                 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    851                                                         // strip cast if we're initializing a char[] with a char *,
    852                                                         // e.g.  char x[] = "hello";
    853                                                         newExpr = ce->get_arg();
    854                                                         ce->set_arg( nullptr );
    855                                                         std::swap( ce->env, newExpr->env );
    856                                                         delete ce;
    857                                                 }
    858                                         }
    859                                 }
    860                         }
    861                 }
    862 
    863                 // set initializer expr to resolved express
    864                 singleInit->value = newExpr;
    865 
    866                 // move cursor to next object in preparation for next initializer
    867                 currentObject.increment();
    868         }
    869 
    870         void Resolver_old::previsit( ListInit * listInit ) {
    871                 visit_children = false;
    872                 // move cursor into brace-enclosed initializer-list
    873                 currentObject.enterListInit();
    874                 // xxx - fix this so that the list isn't copied, iterator should be used to change current
    875                 // element
    876                 std::list<Designation *> newDesignations;
    877                 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
    878                         // iterate designations and initializers in pairs, moving the cursor to the current
    879                         // designated object and resolving the initializer against that object.
    880                         Designation * des = std::get<0>(p);
    881                         Initializer * init = std::get<1>(p);
    882                         newDesignations.push_back( currentObject.findNext( des ) );
    883                         init->accept( *visitor );
    884                 }
    885                 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list
    886                 listInit->get_designations() = newDesignations; // xxx - memory management
    887                 currentObject.exitListInit();
    888 
    889                 // xxx - this part has not be folded into CurrentObject yet
    890                 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {
    891                 //      Type * base = tt->get_baseType()->get_base();
    892                 //      if ( base ) {
    893                 //              // know the implementation type, so try using that as the initContext
    894                 //              ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );
    895                 //              currentObject = &tmpObj;
    896                 //              visit( listInit );
    897                 //      } else {
    898                 //              // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context
    899                 //              Parent::visit( listInit );
    900                 //      }
    901                 // } else {
    902         }
    903 
    904         // ConstructorInit - fall back on C-style initializer
    905         void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {
    906                 // could not find valid constructor, or found an intrinsic constructor
    907                 // fall back on C-style initializer
    908                 delete ctorInit->get_ctor();
    909                 ctorInit->set_ctor( nullptr );
    910                 delete ctorInit->get_dtor();
    911                 ctorInit->set_dtor( nullptr );
    912                 maybeAccept( ctorInit->get_init(), *visitor );
    913         }
    914 
    915         // needs to be callable from outside the resolver, so this is a standalone function
    916         void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {
    917                 assert( ctorInit );
    918                 PassVisitor<Resolver_old> resolver( indexer );
    919                 ctorInit->accept( resolver );
    920         }
    921 
    922         void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {
    923                 assert( stmtExpr );
    924                 PassVisitor<Resolver_old> resolver( indexer );
    925                 stmtExpr->accept( resolver );
    926                 stmtExpr->computeResult();
    927                 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?
    928         }
    929 
    930         void Resolver_old::previsit( ConstructorInit * ctorInit ) {
    931                 visit_children = false;
    932                 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit
    933                 maybeAccept( ctorInit->ctor, *visitor );
    934                 maybeAccept( ctorInit->dtor, *visitor );
    935 
    936                 // found a constructor - can get rid of C-style initializer
    937                 delete ctorInit->init;
    938                 ctorInit->init = nullptr;
    939 
    940                 // intrinsic single parameter constructors and destructors do nothing. Since this was
    941                 // implicitly generated, there's no way for it to have side effects, so get rid of it
    942                 // to clean up generated code.
    943                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
    944                         delete ctorInit->ctor;
    945                         ctorInit->ctor = nullptr;
    946                 }
    947 
    948                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
    949                         delete ctorInit->dtor;
    950                         ctorInit->dtor = nullptr;
    951                 }
    952 
    953                 // xxx - todo -- what about arrays?
    954                 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
    955                 //      // can reduce the constructor down to a SingleInit using the
    956                 //      // second argument from the ctor call, since
    957                 //      delete ctorInit->get_ctor();
    958                 //      ctorInit->set_ctor( nullptr );
    959 
    960                 //      Expression * arg =
    961                 //      ctorInit->set_init( new SingleInit( arg ) );
    962                 // }
    963         }
    964 
    965         ///////////////////////////////////////////////////////////////////////////
    966         //
    967         // *** NEW RESOLVER ***
    968         //
    969         ///////////////////////////////////////////////////////////////////////////
    970 
    97162        namespace {
    97263                /// Finds deleted expressions in an expression tree
    973                 struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> {
     64                struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
    97465                        const ast::DeletedExpr * result = nullptr;
    97566
     
    98980                };
    99081
    991                 struct ResolveDesignators_new final : public ast::WithShortCircuiting {
     82                struct ResolveDesignators final : public ast::WithShortCircuiting {
    99283                        ResolveContext& context;
    99384                        bool result = false;
    99485
    995                         ResolveDesignators_new( ResolveContext& _context ): context{_context} {};
     86                        ResolveDesignators( ResolveContext& _context ): context{_context} {};
    99687
    99788                        void previsit( const ast::Node * ) {
     
    1022113        /// Check if this expression is or includes a deleted expression
    1023114        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
    1024                 return ast::Pass<DeleteFinder_new>::read( expr );
     115                return ast::Pass<DeleteFinder>::read( expr );
    1025116        }
    1026117
     
    1112203
    1113204                /// Strips extraneous casts out of an expression
    1114                 struct StripCasts_new final {
     205                struct StripCasts final {
    1115206                        const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
    1116207                                if (
     
    1126217
    1127218                        static void strip( ast::ptr< ast::Expr > & expr ) {
    1128                                 ast::Pass< StripCasts_new > stripper;
     219                                ast::Pass< StripCasts > stripper;
    1129220                                expr = expr->accept( stripper );
    1130221                        }
     
    1160251                        expr.get_and_mutate()->env = std::move( newenv );
    1161252                        // remove unncecessary casts
    1162                         StripCasts_new::strip( expr );
     253                        StripCasts::strip( expr );
    1163254                }
    1164255
     
    1277368        }
    1278369
    1279         class Resolver_new final
     370        class Resolver final
    1280371        : public ast::WithSymbolTable, public ast::WithGuards,
    1281           public ast::WithVisitorRef<Resolver_new>, public ast::WithShortCircuiting,
     372          public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
    1282373          public ast::WithStmtsToAdd<> {
    1283374
     
    1285376                ast::CurrentObject currentObject;
    1286377                // for work previously in GenInit
    1287                 static InitTweak::ManagedTypes_new managedTypes;
     378                static InitTweak::ManagedTypes managedTypes;
    1288379                ResolveContext context;
    1289380
     
    1292383        public:
    1293384                static size_t traceId;
    1294                 Resolver_new( const ast::TranslationGlobal & global ) :
     385                Resolver( const ast::TranslationGlobal & global ) :
    1295386                        ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
    1296387                        context{ symtab, global } {}
    1297                 Resolver_new( const ResolveContext & context ) :
     388                Resolver( const ResolveContext & context ) :
    1298389                        ast::WithSymbolTable{ context.symtab },
    1299390                        context{ symtab, context.global } {}
     
    1336427                bool on_error(ast::ptr<ast::Decl> & decl);
    1337428        };
    1338         // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
    1339 
    1340         InitTweak::ManagedTypes_new Resolver_new::managedTypes;
     429        // size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
     430
     431        InitTweak::ManagedTypes Resolver::managedTypes;
    1341432
    1342433        void resolve( ast::TranslationUnit& translationUnit ) {
    1343                 ast::Pass< Resolver_new >::run( translationUnit, translationUnit.global );
     434                ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
    1344435        }
    1345436
     
    1348439        ) {
    1349440                assert( ctorInit );
    1350                 ast::Pass< Resolver_new > resolver( context );
     441                ast::Pass< Resolver > resolver( context );
    1351442                return ctorInit->accept( resolver );
    1352443        }
     
    1356447        ) {
    1357448                assert( stmtExpr );
    1358                 ast::Pass< Resolver_new > resolver( context );
     449                ast::Pass< Resolver > resolver( context );
    1359450                auto ret = mutate(stmtExpr->accept(resolver));
    1360451                strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
     
    1398489        }
    1399490
    1400         const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
     491        const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
    1401492                GuardValue( functionReturn );
    1402493
     
    1472563        }
    1473564
    1474         const ast::FunctionDecl * Resolver_new::postvisit( const ast::FunctionDecl * functionDecl ) {
     565        const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
    1475566                // default value expressions have an environment which shouldn't be there and trips up
    1476567                // later passes.
     
    1500591        }
    1501592
    1502         const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
     593        const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
    1503594                // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
    1504595                // class-variable `initContext` is changed multiple times because the LHS is analyzed
     
    1539630                                        // constructed objects cannot be designated
    1540631                                        if ( InitTweak::isDesignated( mutDecl->init ) ) {
    1541                                                 ast::Pass<ResolveDesignators_new> res( context );
     632                                                ast::Pass<ResolveDesignators> res( context );
    1542633                                                maybe_accept( mutDecl->init.get(), res );
    1543634                                                if ( !res.core.result ) {
     
    1559650        }
    1560651
    1561         void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) {
     652        void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
    1562653                auto aggDecl = mutate(_aggDecl);
    1563654                assertf(aggDecl == _aggDecl, "type declarations must be unique");
     
    1571662        }
    1572663
    1573         void Resolver_new::previsit( const ast::StructDecl * structDecl ) {
     664        void Resolver::previsit( const ast::StructDecl * structDecl ) {
    1574665                previsit(static_cast<const ast::AggregateDecl *>(structDecl));
    1575666                managedTypes.handleStruct(structDecl);
    1576667        }
    1577668
    1578         void Resolver_new::previsit( const ast::EnumDecl * ) {
     669        void Resolver::previsit( const ast::EnumDecl * ) {
    1579670                // in case we decide to allow nested enums
    1580671                GuardValue( inEnumDecl );
     
    1583674        }
    1584675
    1585         const ast::StaticAssertDecl * Resolver_new::previsit(
     676        const ast::StaticAssertDecl * Resolver::previsit(
    1586677                const ast::StaticAssertDecl * assertDecl
    1587678        ) {
     
    1603694        }
    1604695
    1605         const ast::ArrayType * Resolver_new::previsit( const ast::ArrayType * at ) {
     696        const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
    1606697                return handlePtrType( at, context );
    1607698        }
    1608699
    1609         const ast::PointerType * Resolver_new::previsit( const ast::PointerType * pt ) {
     700        const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
    1610701                return handlePtrType( pt, context );
    1611702        }
    1612703
    1613         const ast::ExprStmt * Resolver_new::previsit( const ast::ExprStmt * exprStmt ) {
     704        const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
    1614705                visit_children = false;
    1615706                assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
     
    1619710        }
    1620711
    1621         const ast::AsmExpr * Resolver_new::previsit( const ast::AsmExpr * asmExpr ) {
     712        const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
    1622713                visit_children = false;
    1623714
     
    1628719        }
    1629720
    1630         const ast::AsmStmt * Resolver_new::previsit( const ast::AsmStmt * asmStmt ) {
     721        const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
    1631722                visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
    1632723                visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
     
    1635726        }
    1636727
    1637         const ast::IfStmt * Resolver_new::previsit( const ast::IfStmt * ifStmt ) {
     728        const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
    1638729                return ast::mutate_field(
    1639730                        ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
    1640731        }
    1641732
    1642         const ast::WhileDoStmt * Resolver_new::previsit( const ast::WhileDoStmt * whileDoStmt ) {
     733        const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
    1643734                return ast::mutate_field(
    1644735                        whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
    1645736        }
    1646737
    1647         const ast::ForStmt * Resolver_new::previsit( const ast::ForStmt * forStmt ) {
     738        const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
    1648739                if ( forStmt->cond ) {
    1649740                        forStmt = ast::mutate_field(
     
    1659750        }
    1660751
    1661         const ast::SwitchStmt * Resolver_new::previsit( const ast::SwitchStmt * switchStmt ) {
     752        const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
    1662753                GuardValue( currentObject );
    1663754                switchStmt = ast::mutate_field(
     
    1668759        }
    1669760
    1670         const ast::CaseClause * Resolver_new::previsit( const ast::CaseClause * caseStmt ) {
     761        const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
    1671762                if ( caseStmt->cond ) {
    1672763                        std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
     
    1689780        }
    1690781
    1691         const ast::BranchStmt * Resolver_new::previsit( const ast::BranchStmt * branchStmt ) {
     782        const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
    1692783                visit_children = false;
    1693784                // must resolve the argument of a computed goto
     
    1702793        }
    1703794
    1704         const ast::ReturnStmt * Resolver_new::previsit( const ast::ReturnStmt * returnStmt ) {
     795        const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
    1705796                visit_children = false;
    1706797                if ( returnStmt->expr ) {
     
    1712803        }
    1713804
    1714         const ast::ThrowStmt * Resolver_new::previsit( const ast::ThrowStmt * throwStmt ) {
     805        const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
    1715806                visit_children = false;
    1716807                if ( throwStmt->expr ) {
     
    1727818        }
    1728819
    1729         const ast::CatchClause * Resolver_new::previsit( const ast::CatchClause * catchClause ) {
     820        const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
    1730821                // Until we are very sure this invarent (ifs that move between passes have then)
    1731822                // holds, check it. This allows a check for when to decode the mangling.
     
    1743834        }
    1744835
    1745         const ast::CatchClause * Resolver_new::postvisit( const ast::CatchClause * catchClause ) {
     836        const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
    1746837                // Decode the catchStmt so everything is stored properly.
    1747838                const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
     
    1758849        }
    1759850
    1760         const ast::WaitForStmt * Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
     851        const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
    1761852                visit_children = false;
    1762853
     
    20231114        }
    20241115
    2025         const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) {
     1116        const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
    20261117                auto mutStmt = mutate(withStmt);
    20271118                resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
     
    20291120        }
    20301121
    2031         void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
     1122        void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
    20321123                for (auto & expr : exprs) {
    20331124                        // only struct- and union-typed expressions are viable candidates
     
    20551146
    20561147
    2057         const ast::SingleInit * Resolver_new::previsit( const ast::SingleInit * singleInit ) {
     1148        const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
    20581149                visit_children = false;
    20591150                // resolve initialization using the possibilities as determined by the `currentObject`
     
    21041195        }
    21051196
    2106         const ast::ListInit * Resolver_new::previsit( const ast::ListInit * listInit ) {
     1197        const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
    21071198                // move cursor into brace-enclosed initializer-list
    21081199                currentObject.enterListInit( listInit->location );
     
    21271218        }
    21281219
    2129         const ast::ConstructorInit * Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
     1220        const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
    21301221                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
    21311222                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
     
    21491240
    21501241        // suppress error on autogen functions and mark invalid autogen as deleted.
    2151         bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) {
     1242        bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
    21521243                if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
    21531244                        // xxx - can intrinsic gen ever fail?
  • src/ResolvExpr/Resolver.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 #include <list>          // for list
    19 
    2018#include "AST/Node.hpp"  // for ptr
    21 
    22 class ConstructorInit;
    23 class Declaration;
    24 class Expression;
    25 class DeletedExpr;
    26 class StmtExpr;
    27 class Type;
    28 namespace SymTab {
    29         class Indexer;
    30 } // namespace SymTab
    3119
    3220namespace ast {
     
    4533
    4634namespace ResolvExpr {
    47         /// Checks types and binds syntactic constructs to typed representations
    48         void resolve( std::list< Declaration * > translationUnit );
    49         void resolveDecl( Declaration *, const SymTab::Indexer & indexer );
    50         Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer );
    51         void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer );
    52         void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer );
    53         void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer );
    54         void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer );
    55         void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer );
    56         /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
    57         DeletedExpr * findDeletedExpr( Expression * expr );
    58         /// Resolves with-stmts and with-clauses on functions
    59         void resolveWithExprs( std::list< Declaration * > & translationUnit );
    6035
    6136        /// Helper Type: Passes around information between various sub-calls.
  • src/ResolvExpr/SatisfyAssertions.cpp

    rdf8ba61a r8d182b1  
    4646#include "SymTab/Mangler.h"
    4747
    48 
    49 
    5048namespace ResolvExpr {
    5149
  • src/ResolvExpr/SpecCost.cc

    rdf8ba61a r8d182b1  
    1616#include <cassert>
    1717#include <limits>
    18 #include <list>
    1918#include <type_traits>
    2019
    2120#include "AST/Pass.hpp"
    2221#include "AST/Type.hpp"
    23 #include "Common/PassVisitor.h"
    24 #include "SynTree/Declaration.h"
    25 #include "SynTree/Expression.h"
    26 #include "SynTree/Type.h"
    2722
    2823namespace ResolvExpr {
    2924
    30         /// Counts specializations in a type
    31         class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {
    32                 int count = -1;  ///< specialization count (-1 for none)
     25namespace {
    3326
    34         public:
    35                 int get_count() const { return count >= 0 ? count : 0; }
     27const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) {
     28        return expr->result.get();
     29}
    3630
    37                 // mark specialization of base type
    38                 void postvisit(PointerType*) { if ( count >= 0 ) ++count; }
     31const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) {
     32        return type.get();
     33}
    3934
    40                 // mark specialization of base type
    41                 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }
    42 
    43                 // mark specialization of base type
    44                 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }
    45 
    46                 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }
    47                 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }
    48 
    49         private:
    50                 // takes minimum non-negative count over parameter/return list
    51                 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
    52                         for ( DeclarationWithType* dwt : dwts ) {
    53                                 count = -1;
    54                                 maybeAccept( dwt->get_type(), *visitor );
    55                                 if ( count != -1 && count < mincount ) mincount = count;
    56                         }
    57                 }
    58 
    59         public:
    60                 // take minimal specialization value over ->returnVals and ->parameters
    61                 void previsit(FunctionType* fty) {
    62                         int mincount = std::numeric_limits<int>::max();
    63                         takeminover( mincount, fty->parameters );
    64                         takeminover( mincount, fty->returnVals );
    65                         // add another level to mincount if set
    66                         count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    67                         // already visited children
    68                         visit_children = false;
    69                 }
    70 
    71         private:
    72                 // returns minimum non-negative count + 1 over type parameters (-1 if none such)
    73                 int minover( std::list<Expression*>& parms ) {
    74                         int mincount = std::numeric_limits<int>::max();
    75                         for ( Expression* parm : parms ) {
    76                                 count = -1;
    77                                 maybeAccept( parm->result, *visitor );
    78                                 if ( count != -1 && count < mincount ) mincount = count;
    79                         }
    80                         return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    81                 }
    82 
    83         public:
    84                 // look for polymorphic parameters
    85                 void previsit(StructInstType* sty) {
    86                         count = minover( sty->parameters );
    87                 }
    88 
    89                 // look for polymorphic parameters
    90                 void previsit(UnionInstType* uty) {
    91                         count = minover( uty->parameters );
    92                 }
    93 
    94                 // note polymorphic type (which may be specialized)
    95                 // xxx - maybe account for open/closed type variables
    96                 void postvisit(TypeInstType*) { count = 0; }
    97 
    98                 // take minimal specialization over elements
    99                 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
    100                 void previsit(TupleType* tty) {
    101                         int mincount = std::numeric_limits<int>::max();
    102                         for ( Type* ty : tty->types ) {
    103                                 count = -1;
    104                                 maybeAccept( ty, *visitor );
    105                                 if ( count != -1 && count < mincount ) mincount = count;
    106                         }
    107                         count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    108                         visit_children = false;
    109                 }
    110         };
    111 
    112         /// Returns the (negated) specialization cost for a given type
    113         int specCost( Type* ty ) {
    114                 PassVisitor<CountSpecs> counter;
    115                 maybeAccept( ty, *counter.pass.visitor );
    116                 return counter.pass.get_count();
    117         }
    118 
    119 namespace {
    12035        /// The specialization counter inner class.
    12136        class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
     
    13146                        typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
    13247
    133                 #warning Should use a standard maybe_accept
    134                 void maybe_accept( ast::Type const * type ) {
    135                         if ( type ) {
    136                                 auto node = type->accept( *visitor );
    137                                 assert( node == nullptr || node == type );
    138                         }
    139                 }
    140 
    14148                // Update the minimum to the new lowest non-none value.
    14249                template<typename T>
     
    14451                        for ( const auto & node : list ) {
    14552                                count = -1;
    146                                 maybe_accept( mapper( node ) );
     53
     54                                if ( ast::Type const * type = mapper( node ) ) {
     55                                        ast::Type const * newType = type->accept( *visitor );
     56                                        assert( newType == nullptr || newType == type );
     57                                }
     58
    14759                                if ( count != -1 && count < minimum ) minimum = count;
    14860                        }
     
    15769                }
    15870
    159                 // The three mappers:
    160                 static const ast::Type * decl_type( const ast::ptr< ast::DeclWithType > & decl ) {
    161                         return decl->get_type();
    162                 }
    163                 static const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) {
    164                         return expr->result;
    165                 }
    166                 static const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) {
    167                         return type.get();
    168                 }
    169 
    17071        public:
    171                 int get_count() const { return 0 <= count ? count : 0; }
     72                int result() const { return 0 <= count ? count : 0; }
    17273
    17374                // Mark specialization of base type.
     
    215116
    216117int specCost( const ast::Type * type ) {
    217         if ( nullptr == type ) {
    218                 return 0;
    219         }
    220         ast::Pass<SpecCounter> counter;
    221         type->accept( counter );
    222         return counter.core.get_count();
     118        return ( nullptr == type ) ? 0 : ast::Pass<SpecCounter>::read( type );
    223119}
    224120
  • src/ResolvExpr/Unify.cc

    rdf8ba61a r8d182b1  
    3333#include "AST/TypeEnvironment.hpp"
    3434#include "Common/Eval.h"            // for eval
    35 #include "Common/PassVisitor.h"     // for PassVisitor
    3635#include "CommonType.hpp"           // for commonType
    3736#include "FindOpenVars.h"           // for findOpenVars
    3837#include "SpecCost.hpp"             // for SpecCost
    39 #include "SynTree/LinkageSpec.h"    // for C
    40 #include "SynTree/Constant.h"       // for Constant
    41 #include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
    42 #include "SynTree/Expression.h"     // for TypeExpr, Expression, ConstantExpr
    43 #include "SynTree/Mutator.h"        // for Mutator
    44 #include "SynTree/Type.h"           // for Type, TypeInstType, FunctionType
    45 #include "SynTree/Visitor.h"        // for Visitor
    4638#include "Tuples/Tuples.h"          // for isTtype
    47 #include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
    4839#include "typeops.h"                // for flatten, occurs
    4940
     
    5243}
    5344
    54 namespace SymTab {
    55         class Indexer;
    56 }  // namespace SymTab
    57 
    5845// #define DEBUG
    5946
    6047namespace ResolvExpr {
    61 
    62 // Template Helpers:
    63 template< typename Iterator1, typename Iterator2 >
    64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
    65         for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    66                 Type *commonType = 0;
    67                 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    68                         return false;
    69                 } // if
    70                 commonTypes.push_back( commonType );
    71         } // for
    72         return ( list1Begin == list1End && list2Begin == list2End );
    73 }
    74 
    75 template< typename Iterator1, typename Iterator2 >
    76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    77         std::list< Type* > commonTypes;
    78         if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions,  openVars, indexer, commonTypes ) ) {
    79                 deleteAll( commonTypes );
    80                 return true;
    81         } else {
    82                 return false;
    83         } // if
    84 }
    85 
    86         struct Unify_old : public WithShortCircuiting {
    87                 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    88 
    89                 bool get_result() const { return result; }
    90 
    91                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
    92 
    93                 void postvisit( VoidType * voidType );
    94                 void postvisit( BasicType * basicType );
    95                 void postvisit( PointerType * pointerType );
    96                 void postvisit( ArrayType * arrayType );
    97                 void postvisit( ReferenceType * refType );
    98                 void postvisit( FunctionType * functionType );
    99                 void postvisit( StructInstType * aggregateUseType );
    100                 void postvisit( UnionInstType * aggregateUseType );
    101                 void postvisit( EnumInstType * aggregateUseType );
    102                 void postvisit( TraitInstType * aggregateUseType );
    103                 void postvisit( TypeInstType * aggregateUseType );
    104                 void postvisit( TupleType * tupleType );
    105                 void postvisit( VarArgsType * varArgsType );
    106                 void postvisit( ZeroType * zeroType );
    107                 void postvisit( OneType * oneType );
    108 
    109           private:
    110                 template< typename RefType > void handleRefType( RefType *inst, Type *other );
    111                 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
    112 
    113                 bool result;
    114                 Type *type2;                            // inherited
    115                 TypeEnvironment &env;
    116                 AssertionSet &needAssertions;
    117                 AssertionSet &haveAssertions;
    118                 const OpenVarSet &openVars;
    119                 WidenMode widen;
    120                 const SymTab::Indexer &indexer;
    121         };
    122 
    123         /// Attempts an inexact unification of type1 and type2.
    124         /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)
    125         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    126         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    127 
    128         bool unifyExact(
    129                 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    130                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    131                 WidenMode widen );
    132 
    133         bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    134                 TypeEnvironment newEnv;
    135                 OpenVarSet openVars, closedVars; // added closedVars
    136                 AssertionSet needAssertions, haveAssertions;
    137                 Type * newFirst = first->clone(), * newSecond = second->clone();
    138                 env.apply( newFirst );
    139                 env.apply( newSecond );
    140 
    141                 // do we need to do this? Seems like we do, types should be able to be compatible if they
    142                 // have free variables that can unify
    143                 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );
    144                 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );
    145 
    146                 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    147                 delete newFirst;
    148                 delete newSecond;
    149                 return result;
    150         }
    15148
    15249        bool typesCompatible(
     
    16562
    16663                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
    167         }
    168 
    169         bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    170                 TypeEnvironment newEnv;
    171                 OpenVarSet openVars;
    172                 AssertionSet needAssertions, haveAssertions;
    173                 Type *newFirst = first->clone(), *newSecond = second->clone();
    174                 env.apply( newFirst );
    175                 env.apply( newSecond );
    176                 newFirst->get_qualifiers() = Type::Qualifiers();
    177                 newSecond->get_qualifiers() = Type::Qualifiers();
    178 
    179                 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    180                 delete newFirst;
    181                 delete newSecond;
    182                 return result;
    18364        }
    18465
     
    220101        }
    221102
    222         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    223                 OpenVarSet closedVars;
    224                 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
    225                 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
    226                 Type *commonType = 0;
    227                 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
    228                         if ( commonType ) {
    229                                 delete commonType;
    230                         } // if
    231                         return true;
    232                 } else {
    233                         return false;
    234                 } // if
    235         }
    236 
    237         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {
    238                 OpenVarSet closedVars;
    239                 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
    240                 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
    241                 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );
    242         }
    243 
    244         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
    245 #ifdef DEBUG
    246                 TypeEnvironment debugEnv( env );
    247 #endif
    248                 if ( type1->get_qualifiers() != type2->get_qualifiers() ) {
    249                         return false;
    250                 }
    251 
    252                 bool result;
    253                 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );
    254                 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );
    255                 OpenVarSet::const_iterator entry1, entry2;
    256                 if ( var1 ) {
    257                         entry1 = openVars.find( var1->get_name() );
    258                 } // if
    259                 if ( var2 ) {
    260                         entry2 = openVars.find( var2->get_name() );
    261                 } // if
    262                 bool isopen1 = var1 && ( entry1 != openVars.end() );
    263                 bool isopen2 = var2 && ( entry2 != openVars.end() );
    264 
    265                 if ( isopen1 && isopen2 ) {
    266                         if ( entry1->second.kind != entry2->second.kind ) {
    267                                 result = false;
    268                         } else {
    269                                 result = env.bindVarToVar(
    270                                         var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
    271                                         haveAssertions, openVars, widen, indexer );
    272                         }
    273                 } else if ( isopen1 ) {
    274                         result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );
    275                 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?
    276                         result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );
    277                 } else {
    278                         PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );
    279                         type1->accept( comparator );
    280                         result = comparator.pass.get_result();
    281                 } // if
    282 #ifdef DEBUG
    283                 std::cerr << "============ unifyExact" << std::endl;
    284                 std::cerr << "type1 is ";
    285                 type1->print( std::cerr );
    286                 std::cerr << std::endl << "type2 is ";
    287                 type2->print( std::cerr );
    288                 std::cerr << std::endl << "openVars are ";
    289                 printOpenVarSet( openVars, std::cerr, 8 );
    290                 std::cerr << std::endl << "input env is " << std::endl;
    291                 debugEnv.print( std::cerr, 8 );
    292                 std::cerr << std::endl << "result env is " << std::endl;
    293                 env.print( std::cerr, 8 );
    294                 std::cerr << "result is " << result << std::endl;
    295 #endif
    296                 return result;
    297         }
    298 
    299         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    300                 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    301         }
    302 
    303         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {
    304                 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
    305                 type1->get_qualifiers() = Type::Qualifiers();
    306                 type2->get_qualifiers() = Type::Qualifiers();
    307                 bool result;
    308 #ifdef DEBUG
    309                 std::cerr << "unifyInexact type 1 is ";
    310                 type1->print( std::cerr );
    311                 std::cerr << " type 2 is ";
    312                 type2->print( std::cerr );
    313                 std::cerr << std::endl;
    314 #endif
    315                 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {
    316 #ifdef DEBUG
    317                         std::cerr << "unifyInexact: no exact unification found" << std::endl;
    318 #endif
    319                         if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {
    320                                 common->tq = tq1.unify( tq2 );
    321 #ifdef DEBUG
    322                                 std::cerr << "unifyInexact: common type is ";
    323                                 common->print( std::cerr );
    324                                 std::cerr << std::endl;
    325 #endif
    326                                 result = true;
    327                         } else {
    328 #ifdef DEBUG
    329                                 std::cerr << "unifyInexact: no common type found" << std::endl;
    330 #endif
    331                                 result = false;
    332                         } // if
    333                 } else {
    334                         if ( tq1 != tq2 ) {
    335                                 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {
    336                                         common = type1->clone();
    337                                         common->tq = tq1.unify( tq2 );
    338                                         result = true;
    339                                 } else {
    340                                         result = false;
    341                                 } // if
    342                         } else {
    343                                 common = type1->clone();
    344                                 common->tq = tq1.unify( tq2 );
    345                                 result = true;
    346                         } // if
    347                 } // if
    348                 type1->get_qualifiers() = tq1;
    349                 type2->get_qualifiers() = tq2;
    350                 return result;
    351         }
    352 
    353         Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )
    354                 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {
    355         }
    356 
    357         void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {
    358                 result = dynamic_cast< VoidType* >( type2 );
    359         }
    360 
    361         void Unify_old::postvisit(BasicType *basicType) {
    362                 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    363                         result = basicType->get_kind() == otherBasic->get_kind();
    364                 } // if
    365         }
    366 
    367         void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
    368                 AssertionSet::iterator i = assertions.find( assert );
    369                 if ( i != assertions.end() ) {
    370                         i->second.isUsed = true;
    371                 } // if
    372         }
    373 
    374         void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {
    375                 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
    376                         for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
    377                                 markAssertionSet( assertion1, *assert );
    378                                 markAssertionSet( assertion2, *assert );
    379                         } // for
    380                 } // for
    381         }
    382 
    383         void Unify_old::postvisit(PointerType *pointerType) {
    384                 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
    385                         result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    386                         markAssertions( haveAssertions, needAssertions, pointerType );
    387                         markAssertions( haveAssertions, needAssertions, otherPointer );
    388                 } // if
    389         }
    390 
    391         void Unify_old::postvisit(ReferenceType *refType) {
    392                 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
    393                         result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    394                         markAssertions( haveAssertions, needAssertions, refType );
    395                         markAssertions( haveAssertions, needAssertions, otherRef );
    396                 } // if
    397         }
    398 
    399         void Unify_old::postvisit(ArrayType *arrayType) {
    400                 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
    401                 // to unify, array types must both be VLA or both not VLA
    402                 // and must both have a dimension expression or not have a dimension
    403                 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {
    404 
    405                         if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&
    406                                 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {
    407                                 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );
    408                                 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );
    409                                 // see C11 Reference Manual 6.7.6.2.6
    410                                 // two array types with size specifiers that are integer constant expressions are
    411                                 // compatible if both size specifiers have the same constant value
    412                                 if ( ce1 && ce2 ) {
    413                                         Constant * c1 = ce1->get_constant();
    414                                         Constant * c2 = ce2->get_constant();
    415 
    416                                         if ( c1->get_value() != c2->get_value() ) {
    417                                                 // does not unify if the dimension is different
    418                                                 return;
    419                                         }
    420                                 }
    421                         }
    422 
    423                         result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    424                 } // if
    425         }
    426 
    427         template< typename Iterator, typename Func >
    428         std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {
    429                 std::list< Type * > types;
    430                 for ( ; begin != end; ++begin ) {
    431                         // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
    432                         flatten( toType( *begin ), back_inserter( types ) );
    433                 }
    434                 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
    435         }
    436 
    437         template< typename Iterator1, typename Iterator2 >
    438         bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    439                 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
    440                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    441                         Type * t1 = (*list1Begin)->get_type();
    442                         Type * t2 = (*list2Begin)->get_type();
    443                         bool isTtype1 = Tuples::isTtype( t1 );
    444                         bool isTtype2 = Tuples::isTtype( t2 );
    445                         // xxx - assumes ttype must be last parameter
    446                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    447                         if ( isTtype1 && ! isTtype2 ) {
    448                                 // combine all of the things in list2, then unify
    449                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    450                         } else if ( isTtype2 && ! isTtype1 ) {
    451                                 // combine all of the things in list1, then unify
    452                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    453                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    454                                 return false;
    455                         } // if
    456                 } // for
    457                 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype
    458                 if ( list1Begin != list1End ) {
    459                         // try unifying empty tuple type with ttype
    460                         Type * t1 = (*list1Begin)->get_type();
    461                         if ( Tuples::isTtype( t1 ) ) {
    462                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    463                         } else return false;
    464                 } else if ( list2Begin != list2End ) {
    465                         // try unifying empty tuple type with ttype
    466                         Type * t2 = (*list2Begin)->get_type();
    467                         if ( Tuples::isTtype( t2 ) ) {
    468                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    469                         } else return false;
    470                 } else {
    471                         return true;
    472                 } // if
    473         }
    474 
    475         /// Finds ttypes and replaces them with their expansion, if known.
    476         /// This needs to be done so that satisfying ttype assertions is easier.
    477         /// If this isn't done then argument lists can have wildly different
    478         /// size and structure, when they should be compatible.
    479         struct TtypeExpander_old : public WithShortCircuiting {
    480                 TypeEnvironment & tenv;
    481                 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}
    482                 void premutate( TypeInstType * ) { visit_children = false; }
    483                 Type * postmutate( TypeInstType * typeInst ) {
    484                         if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
    485                                 // expand ttype parameter into its actual type
    486                                 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {
    487                                         delete typeInst;
    488                                         return eqvClass->type->clone();
    489                                 }
    490                         }
    491                         return typeInst;
    492                 }
    493         };
    494 
    495         /// flattens a list of declarations, so that each tuple type has a single declaration.
    496         /// makes use of TtypeExpander to ensure ttypes are flat as well.
    497         void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
    498                 dst.clear();
    499                 for ( DeclarationWithType * dcl : src ) {
    500                         PassVisitor<TtypeExpander_old> expander( env );
    501                         dcl->acceptMutator( expander );
    502                         std::list< Type * > types;
    503                         flatten( dcl->get_type(), back_inserter( types ) );
    504                         for ( Type * t : types ) {
    505                                 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.
    506                                 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.
    507                                 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);
    508 
    509                                 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );
    510                         }
    511                         delete dcl;
    512                 }
    513         }
    514 
    515         void Unify_old::postvisit(FunctionType *functionType) {
    516                 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
    517                 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
    518                         // flatten the parameter lists for both functions so that tuple structure
    519                         // doesn't affect unification. Must be a clone so that the types don't change.
    520                         std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
    521                         std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
    522                         flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
    523                         flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
    524 
    525                         // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
    526                         if (
    527                                         (flatFunc->parameters.size() == flatOther->parameters.size() &&
    528                                                 flatFunc->returnVals.size() == flatOther->returnVals.size())
    529                                         || flatFunc->isTtype()
    530                                         || flatOther->isTtype()
    531                         ) {
    532                                 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    533                                         if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    534 
    535                                                 // the original types must be used in mark assertions, since pointer comparisons are used
    536                                                 markAssertions( haveAssertions, needAssertions, functionType );
    537                                                 markAssertions( haveAssertions, needAssertions, otherFunction );
    538 
    539                                                 result = true;
    540                                         } // if
    541                                 } // if
    542                         } // if
    543                 } // if
    544         }
    545 
    546         template< typename RefType >
    547         void Unify_old::handleRefType( RefType *inst, Type *other ) {
    548                 // check that other type is compatible and named the same
    549                 RefType *otherStruct = dynamic_cast< RefType* >( other );
    550                 result = otherStruct && inst->name == otherStruct->name;
    551         }
    552 
    553         template< typename RefType >
    554         void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {
    555                 // Check that other type is compatible and named the same
    556                 handleRefType( inst, other );
    557                 if ( ! result ) return;
    558                 // Check that parameters of types unify, if any
    559                 std::list< Expression* > params = inst->parameters;
    560                 std::list< Expression* > otherParams = ((RefType*)other)->parameters;
    561 
    562                 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();
    563                 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {
    564                         TypeExpr *param = dynamic_cast< TypeExpr* >(*it);
    565                         assertf(param, "Aggregate parameters should be type expressions");
    566                         TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);
    567                         assertf(otherParam, "Aggregate parameters should be type expressions");
    568 
    569                         Type* paramTy = param->get_type();
    570                         Type* otherParamTy = otherParam->get_type();
    571 
    572                         bool tupleParam = Tuples::isTtype( paramTy );
    573                         bool otherTupleParam = Tuples::isTtype( otherParamTy );
    574 
    575                         if ( tupleParam && otherTupleParam ) {
    576                                 ++it; ++jt;  // skip ttype parameters for break
    577                         } else if ( tupleParam ) {
    578                                 // bundle other parameters into tuple to match
    579                                 std::list< Type * > binderTypes;
    580 
    581                                 do {
    582                                         binderTypes.push_back( otherParam->get_type()->clone() );
    583                                         ++jt;
    584 
    585                                         if ( jt == otherParams.end() ) break;
    586 
    587                                         otherParam = dynamic_cast< TypeExpr* >(*jt);
    588                                         assertf(otherParam, "Aggregate parameters should be type expressions");
    589                                 } while (true);
    590 
    591                                 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };
    592                                 ++it;  // skip ttype parameter for break
    593                         } else if ( otherTupleParam ) {
    594                                 // bundle parameters into tuple to match other
    595                                 std::list< Type * > binderTypes;
    596 
    597                                 do {
    598                                         binderTypes.push_back( param->get_type()->clone() );
    599                                         ++it;
    600 
    601                                         if ( it == params.end() ) break;
    602 
    603                                         param = dynamic_cast< TypeExpr* >(*it);
    604                                         assertf(param, "Aggregate parameters should be type expressions");
    605                                 } while (true);
    606 
    607                                 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };
    608                                 ++jt;  // skip ttype parameter for break
    609                         }
    610 
    611                         if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
    612                                 result = false;
    613                                 return;
    614                         }
    615 
    616                         // ttype parameter should be last
    617                         if ( tupleParam || otherTupleParam ) break;
    618                 }
    619                 result = ( it == params.end() && jt == otherParams.end() );
    620         }
    621 
    622         void Unify_old::postvisit(StructInstType *structInst) {
    623                 handleGenericRefType( structInst, type2 );
    624         }
    625 
    626         void Unify_old::postvisit(UnionInstType *unionInst) {
    627                 handleGenericRefType( unionInst, type2 );
    628         }
    629 
    630         void Unify_old::postvisit(EnumInstType *enumInst) {
    631                 handleRefType( enumInst, type2 );
    632         }
    633 
    634         void Unify_old::postvisit(TraitInstType *contextInst) {
    635                 handleRefType( contextInst, type2 );
    636         }
    637 
    638         void Unify_old::postvisit(TypeInstType *typeInst) {
    639                 assert( openVars.find( typeInst->get_name() ) == openVars.end() );
    640                 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
    641                 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {
    642                         result = true;
    643 ///   } else {
    644 ///     NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );
    645 ///     if ( nt ) {
    646 ///       TypeDecl *type = dynamic_cast< TypeDecl* >( nt );
    647 ///       assert( type );
    648 ///       if ( type->get_base() ) {
    649 ///         result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    650 ///       }
    651 ///     }
    652                 } // if
    653         }
    654 
    655         template< typename Iterator1, typename Iterator2 >
    656         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    657                 auto get_type = [](Type * t) { return t; };
    658                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    659                         Type * t1 = *list1Begin;
    660                         Type * t2 = *list2Begin;
    661                         bool isTtype1 = Tuples::isTtype( t1 );
    662                         bool isTtype2 = Tuples::isTtype( t2 );
    663                         // xxx - assumes ttype must be last parameter
    664                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    665                         if ( isTtype1 && ! isTtype2 ) {
    666                                 // combine all of the things in list2, then unify
    667                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    668                         } else if ( isTtype2 && ! isTtype1 ) {
    669                                 // combine all of the things in list1, then unify
    670                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    671                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    672                                 return false;
    673                         } // if
    674 
    675                 } // for
    676                 if ( list1Begin != list1End ) {
    677                         // try unifying empty tuple type with ttype
    678                         Type * t1 = *list1Begin;
    679                         if ( Tuples::isTtype( t1 ) ) {
    680                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    681                         } else return false;
    682                 } else if ( list2Begin != list2End ) {
    683                         // try unifying empty tuple type with ttype
    684                         Type * t2 = *list2Begin;
    685                         if ( Tuples::isTtype( t2 ) ) {
    686                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    687                         } else return false;
    688                 } else {
    689                         return true;
    690                 } // if
    691         }
    692 
    693         void Unify_old::postvisit(TupleType *tupleType) {
    694                 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
    695                         std::unique_ptr<TupleType> flat1( tupleType->clone() );
    696                         std::unique_ptr<TupleType> flat2( otherTuple->clone() );
    697                         std::list<Type *> types1, types2;
    698 
    699                         PassVisitor<TtypeExpander_old> expander( env );
    700                         flat1->acceptMutator( expander );
    701                         flat2->acceptMutator( expander );
    702 
    703                         flatten( flat1.get(), back_inserter( types1 ) );
    704                         flatten( flat2.get(), back_inserter( types2 ) );
    705 
    706                         result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
    707                 } // if
    708         }
    709 
    710         void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
    711                 result = dynamic_cast< VarArgsType* >( type2 );
    712         }
    713 
    714         void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
    715                 result = dynamic_cast< ZeroType* >( type2 );
    716         }
    717 
    718         void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {
    719                 result = dynamic_cast< OneType* >( type2 );
    720         }
    721 
    722         Type * extractResultType( FunctionType * function ) {
    723                 if ( function->get_returnVals().size() == 0 ) {
    724                         return new VoidType( Type::Qualifiers() );
    725                 } else if ( function->get_returnVals().size() == 1 ) {
    726                         return function->get_returnVals().front()->get_type()->clone();
    727                 } else {
    728                         std::list< Type * > types;
    729                         for ( DeclarationWithType * decl : function->get_returnVals() ) {
    730                                 types.push_back( decl->get_type()->clone() );
    731                         } // for
    732                         return new TupleType( Type::Qualifiers(), types );
    733                 }
    734         }
    735 
    736103        namespace {
    737104                                /// Replaces ttype variables with their bound types.
    738105                /// If this isn't done when satifying ttype assertions, then argument lists can have
    739106                /// different size and structure when they should be compatible.
    740                 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {
     107                struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
    741108                        ast::TypeEnvironment & tenv;
    742109
    743                         TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {}
     110                        TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
    744111
    745112                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
     
    761128                dst.reserve( src.size() );
    762129                for ( const auto & d : src ) {
    763                         ast::Pass<TtypeExpander_new> expander{ env };
     130                        ast::Pass<TtypeExpander> expander{ env };
    764131                        // TtypeExpander pass is impure (may mutate nodes in place)
    765132                        // need to make nodes shared to prevent accidental mutation
     
    901268        }
    902269
    903         class Unify_new final : public ast::WithShortCircuiting {
     270        class Unify final : public ast::WithShortCircuiting {
    904271                const ast::Type * type2;
    905272                ast::TypeEnvironment & tenv;
     
    912279                bool result;
    913280
    914                 Unify_new(
     281                Unify(
    915282                        const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
    916283                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
     
    1239606                        if ( ! tuple2 ) return;
    1240607
    1241                         ast::Pass<TtypeExpander_new> expander{ tenv };
     608                        ast::Pass<TtypeExpander> expander{ tenv };
    1242609
    1243610                        const ast::Type * flat = tuple->accept( expander );
     
    1267634        };
    1268635
    1269         // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
     636        // size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
     637
    1270638        bool unify(
    1271639                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     
    1311679                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
    1312680                } else {
    1313                         return ast::Pass<Unify_new>::read(
     681                        return ast::Pass<Unify>::read(
    1314682                                type1, type2, env, need, have, open, widen );
    1315683                }
  • src/ResolvExpr/Unify.h

    rdf8ba61a r8d182b1  
    2020#include "AST/Node.hpp"             // for ptr
    2121#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment, AssertionSet, OpenVarSet
    22 #include "Common/utility.h"       // for deleteAll
    23 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Data
    24 #include "TypeEnvironment.h"      // for AssertionSet, OpenVarSet
    2522#include "WidenMode.h"              // for WidenMode
    26 
    27 class Type;
    28 class TypeInstType;
    29 namespace SymTab {
    30         class Indexer;
    31 }
    3223
    3324namespace ast {
     
    3728
    3829namespace ResolvExpr {
    39 
    40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
    42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    44 
    45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    47 
    48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    49         TypeEnvironment env;
    50         return typesCompatible( t1, t2, indexer, env );
    51 }
    52 
    53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    54         TypeEnvironment env;
    55         return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
    56 }
    5730
    5831bool unify(
     
    8558        const ast::TypeEnvironment & env = {} );
    8659
    87 /// Creates the type represented by the list of returnVals in a FunctionType.
    88 /// The caller owns the return value.
    89 Type * extractResultType( FunctionType * functionType );
    9060/// Creates or extracts the type represented by returns in a `FunctionType`.
    9161ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
  • src/ResolvExpr/module.mk

    rdf8ba61a r8d182b1  
    1818      ResolvExpr/AdjustExprType.cc \
    1919      ResolvExpr/AdjustExprType.hpp \
    20       ResolvExpr/Alternative.cc \
    21       ResolvExpr/AlternativeFinder.cc \
    22       ResolvExpr/AlternativeFinder.h \
    23       ResolvExpr/Alternative.h \
    2420      ResolvExpr/Candidate.cpp \
    2521      ResolvExpr/CandidateFinder.cpp \
     
    3531      ResolvExpr/CurrentObject.cc \
    3632      ResolvExpr/CurrentObject.h \
    37       ResolvExpr/ExplodedActual.cc \
    38       ResolvExpr/ExplodedActual.h \
    3933      ResolvExpr/ExplodedArg.cpp \
    4034      ResolvExpr/ExplodedArg.hpp \
    4135      ResolvExpr/FindOpenVars.cc \
    4236      ResolvExpr/FindOpenVars.h \
    43       ResolvExpr/Occurs.cc \
    4437      ResolvExpr/PolyCost.cc \
    4538      ResolvExpr/PolyCost.hpp \
     
    5043      ResolvExpr/RenameVars.cc \
    5144      ResolvExpr/RenameVars.h \
    52       ResolvExpr/ResolveAssertions.cc \
    53       ResolvExpr/ResolveAssertions.h \
    5445      ResolvExpr/Resolver.cc \
    5546      ResolvExpr/Resolver.h \
     
    6152      ResolvExpr/SpecCost.cc \
    6253      ResolvExpr/SpecCost.hpp \
    63       ResolvExpr/TypeEnvironment.cc \
    64       ResolvExpr/TypeEnvironment.h \
    6554      ResolvExpr/typeops.h \
    6655      ResolvExpr/Unify.cc \
     
    6958
    7059SRC += $(SRC_RESOLVEXPR) \
    71         ResolvExpr/AlternativePrinter.cc \
    72         ResolvExpr/AlternativePrinter.h \
    7360        ResolvExpr/CandidatePrinter.cpp \
    7461        ResolvExpr/CandidatePrinter.hpp \
  • src/ResolvExpr/typeops.h

    rdf8ba61a r8d182b1  
    1919
    2020#include "AST/Type.hpp"
    21 #include "SynTree/Type.h"
    22 
    23 namespace SymTab {
    24         class Indexer;
    25 }
    2621
    2722namespace ResolvExpr {
     
    5247                        std::copy( i.begin(), i.end(), inserter );
    5348                        *out++ = result;
    54                 }
    55         }
    56 
    57         // in Occurs.cc
    58         bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );
    59         // new AST version in TypeEnvironment.cpp (only place it was used in old AST)
    60 
    61         template<typename Iter>
    62         bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {
    63                 while ( begin != end ) {
    64                         if ( occurs( ty, *begin, env ) ) return true;
    65                         ++begin;
    66                 }
    67                 return false;
    68         }
    69 
    70         /// flatten tuple type into list of types
    71         template< typename OutputIterator >
    72         void flatten( Type * type, OutputIterator out ) {
    73                 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {
    74                         for ( Type * t : tupleType->get_types() ) {
    75                                 flatten( t, out );
    76                         }
    77                 } else {
    78                         *out++ = type->clone();
    7949                }
    8050        }
     
    12090                return tupleFromTypes( tys.begin(), tys.end() );
    12191        }
    122 
    123         // in TypeEnvironment.cc
    124         bool isFtype( const Type * type );
    12592} // namespace ResolvExpr
    12693
  • src/SymTab/Demangle.cc

    rdf8ba61a r8d182b1  
    1717#include <sstream>
    1818
     19#include "AST/Pass.hpp"
     20#include "AST/Type.hpp"
    1921#include "CodeGen/GenType.h"
    2022#include "CodeGen/OperatorTable.h"
    21 #include "Common/PassVisitor.h"
    2223#include "Common/utility.h"                                                             // isPrefix
    2324#include "Mangler.h"
    24 #include "SynTree/Type.h"
    25 #include "SynTree/Declaration.h"
    2625
    2726#define DEBUG
     
    3231#endif
    3332
     33namespace Mangle {
     34
    3435namespace {
    35         struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    36                 std::string typeString;
    37                 GenType( const std::string &typeString );
    38 
    39                 void previsit( BaseSyntaxNode * );
    40                 void postvisit( BaseSyntaxNode * );
    41 
    42                 void postvisit( FunctionType * funcType );
    43                 void postvisit( VoidType * voidType );
    44                 void postvisit( BasicType * basicType );
    45                 void postvisit( PointerType * pointerType );
    46                 void postvisit( ArrayType * arrayType );
    47                 void postvisit( ReferenceType * refType );
    48                 void postvisit( StructInstType * structInst );
    49                 void postvisit( UnionInstType * unionInst );
    50                 void postvisit( EnumInstType * enumInst );
    51                 void postvisit( TypeInstType * typeInst );
    52                 void postvisit( TupleType  * tupleType );
    53                 void postvisit( VarArgsType * varArgsType );
    54                 void postvisit( ZeroType * zeroType );
    55                 void postvisit( OneType * oneType );
    56                 void postvisit( GlobalScopeType * globalType );
    57                 void postvisit( QualifiedType * qualType );
    58 
    59           private:
    60                 void handleQualifiers( Type *type );
    61                 std::string handleGeneric( ReferenceToType * refType );
    62                 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    63         };
    64 
    65   std::string genDemangleType( Type * type, const std::string & baseString ) {
    66                 PassVisitor<GenType> gt( baseString );
    67                 assert( type );
    68                 type->accept( gt );
    69                 return gt.pass.typeString;
    70   }
    71 
    72         GenType::GenType( const std::string &typeString ) : typeString( typeString ) {}
    73 
    74         // *** BaseSyntaxNode
    75         void GenType::previsit( BaseSyntaxNode * ) {
    76                 // turn off automatic recursion for all nodes, to allow each visitor to
    77                 // precisely control the order in which its children are visited.
    78                 visit_children = false;
    79         }
    80 
    81         void GenType::postvisit( BaseSyntaxNode * node ) {
    82                 std::stringstream ss;
    83                 node->print( ss );
    84                 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
    85         }
    86 
    87         void GenType::postvisit( VoidType * voidType ) {
    88                 typeString = "void " + typeString;
    89                 handleQualifiers( voidType );
    90         }
    91 
    92         void GenType::postvisit( BasicType * basicType ) {
    93                 BasicType::Kind kind = basicType->kind;
    94                 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
    95                 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
    96                 handleQualifiers( basicType );
    97         }
    98 
    99         void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) {
    100                 std::ostringstream os;
    101                 if ( typeString != "" ) {
    102                         if ( typeString[ 0 ] == '*' ) {
    103                                 os << "(" << typeString << ")";
    104                         } else {
    105                                 os << typeString;
    106                         } // if
    107                 } // if
    108                 os << "[";
    109 
    110                 if ( qualifiers.is_const ) {
    111                         os << "const ";
    112                 } // if
    113                 if ( qualifiers.is_volatile ) {
    114                         os << "volatile ";
    115                 } // if
    116                 if ( qualifiers.is_restrict ) {
    117                         os << "__restrict ";
    118                 } // if
    119                 if ( qualifiers.is_atomic ) {
    120                         os << "_Atomic ";
    121                 } // if
    122                 if ( dimension != 0 ) {
    123                         // TODO: ???
    124                         // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    125                         // dimension->accept( cg );
    126                 } else if ( isVarLen ) {
    127                         // no dimension expression on a VLA means it came in with the * token
    128                         os << "*";
    129                 } // if
    130                 os << "]";
    131 
    132                 typeString = os.str();
    133 
    134                 base->accept( *visitor );
    135         }
    136 
    137         void GenType::postvisit( PointerType * pointerType ) {
    138                 assert( pointerType->base != 0);
    139                 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
    140                         assert(false);
    141                         genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
    142                 } else {
    143                         handleQualifiers( pointerType );
    144                         if ( typeString[ 0 ] == '?' ) {
    145                                 typeString = "* " + typeString;
    146                         } else {
    147                                 typeString = "*" + typeString;
    148                         } // if
    149                         pointerType->base->accept( *visitor );
    150                 } // if
    151         }
    152 
    153         void GenType::postvisit( ArrayType * arrayType ) {
    154                 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
    155         }
    156 
    157         void GenType::postvisit( ReferenceType * refType ) {
    158                 assert( false );
    159                 assert( refType->base != 0);
    160                 handleQualifiers( refType );
    161                 typeString = "&" + typeString;
    162                 refType->base->accept( *visitor );
    163         }
    164 
    165         void GenType::postvisit( FunctionType * funcType ) {
    166                 std::ostringstream os;
    167 
    168                 if ( typeString != "" ) {
    169                         if ( typeString[0] == '*' ) {
    170                                 os << "(" << typeString << ")";
    171                         } else {
    172                                 os << typeString;
    173                         } // if
    174                 } // if
    175 
    176                 /************* parameters ***************/
    177                 const std::list<DeclarationWithType *> &pars = funcType->parameters;
    178 
    179                 if ( pars.empty() ) {
    180                         if ( funcType->get_isVarArgs() ) {
    181                                 os << "()";
    182                         } else {
    183                                 os << "(void)";
    184                         } // if
    185                 } else {
    186                         os << "(" ;
    187 
    188                         unsigned int i = 0;
    189                         for (DeclarationWithType * p : pars) {
    190                                 os << genDemangleType( p->get_type(), "" );
    191                                 if (++i != pars.size()) os << ", ";
    192                         }
    193 
    194                         if ( funcType->get_isVarArgs() ) {
    195                                 os << ", ...";
    196                         } // if
    197                         os << ")";
    198                 } // if
    199 
    200                 typeString = os.str();
    201 
    202                 if ( funcType->returnVals.size() == 0 ) {
    203                         typeString += ": void";
    204                 } else {
    205                         typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), "");
    206                 } // if
    207 
    208                 // add forall
    209                 if( ! funcType->forall.empty() ) {
    210                         std::ostringstream os;
    211                         os << "forall(";
    212                         unsigned int i = 0;
    213                         for ( auto td : funcType->forall ) {
    214                                 os << td->typeString() << " " << td->name;
    215                                 if (! td->assertions.empty()) {
    216                                         os << " | { ";
    217                                         unsigned int j = 0;
    218                                         for (DeclarationWithType * assert : td->assertions) {
    219                                                 os << genDemangleType(assert->get_type(), assert->name);
    220                                                 if (++j != td->assertions.size()) os << ", ";
    221                                         }
    222                                         os << "}";
    223                                 }
    224                                 if (++i != funcType->forall.size()) os << ", ";
    225                         }
    226                         os << ")";
    227                         typeString = typeString + " -> " + os.str();
     36
     37struct Demangler {
     38private:
     39        std::string str;
     40        size_t index = 0;
     41        using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>;
     42        std::vector<std::pair<std::string, Parser>> parsers;
     43public:
     44        Demangler( const std::string & str );
     45
     46        bool done() const { return str.size() <= index; }
     47        char cur() const { assert( !done() ); return str[index]; }
     48        bool expect( char ch ) { return str[index++] == ch; }
     49
     50        bool isPrefix( const std::string & pref );
     51        bool extractNumber( size_t & out );
     52        bool extractName( std::string & out );
     53        bool stripMangleName( std::string & name );
     54
     55        ast::Type * parseFunction( ast::CV::Qualifiers tq );
     56        ast::Type * parseTuple( ast::CV::Qualifiers tq );
     57        ast::Type * parsePointer( ast::CV::Qualifiers tq );
     58        ast::Type * parseArray( ast::CV::Qualifiers tq );
     59        ast::Type * parseStruct( ast::CV::Qualifiers tq );
     60        ast::Type * parseUnion( ast::CV::Qualifiers tq );
     61        ast::Type * parseEnum( ast::CV::Qualifiers tq );
     62        ast::Type * parseType( ast::CV::Qualifiers tq );
     63        ast::Type * parseZero( ast::CV::Qualifiers tq );
     64        ast::Type * parseOne( ast::CV::Qualifiers tq );
     65
     66        ast::Type * parseType();
     67        bool parse( std::string & name, ast::Type *& type );
     68};
     69
     70Demangler::Demangler(const std::string & str) : str(str) {
     71        for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
     72                parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) {
     73                        PRINT( std::cerr << "basic type: " << k << std::endl; )
     74                        return new ast::BasicType( (ast::BasicType::Kind)k, tq );
     75                });
     76        }
     77
     78        for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) {
     79                static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
     80                static_assert(
     81                        sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
     82                        "Each type variable kind should have a demangle name prefix"
     83                );
     84                parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * {
     85                        PRINT( std::cerr << "type variable type: " << k << std::endl; )
     86                        size_t N;
     87                        if (!extractNumber(N)) return nullptr;
     88                        return new ast::TypeInstType(
     89                                toString(typeVariableNames[k], N),
     90                                (ast::TypeDecl::Kind)k,
     91                                tq );
     92                });
     93        }
     94
     95        parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); });
     96        parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); });
     97        parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); });
     98        parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); });
     99        parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); });
     100        parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); });
     101        parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); });
     102        parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); });
     103        parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); });
     104        parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); });
     105        parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); });
     106}
     107
     108bool Demangler::extractNumber( size_t & out ) {
     109        std::stringstream numss;
     110        if ( str.size() <= index ) return false;
     111        while ( isdigit( str[index] ) ) {
     112                numss << str[index];
     113                ++index;
     114                if ( str.size() == index ) break;
     115        }
     116        if ( !(numss >> out) ) return false;
     117        PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
     118        return true;
     119}
     120
     121bool Demangler::extractName( std::string & out ) {
     122        size_t len;
     123        if ( !extractNumber(len) ) return false;
     124        if ( str.size() < index + len ) return false;
     125        out = str.substr( index, len );
     126        index += len;
     127        PRINT( std::cerr << "extractName success: " << out << std::endl; )
     128        return true;
     129}
     130
     131bool Demangler::isPrefix( const std::string & pref ) {
     132        // Wraps the utility isPrefix function.
     133        if ( ::isPrefix( str, pref, index ) ) {
     134                index += pref.size();
     135                return true;
     136        }
     137        return false;
     138}
     139
     140// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
     141bool Demangler::stripMangleName( std::string & name ) {
     142        PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
     143        if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
     144        if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false;
     145
     146        if (!extractName(name)) return false;
     147
     148        // Find bounds for type.
     149        PRINT( std::cerr << index << " " << str.size() << std::endl; )
     150        PRINT( std::cerr << "[");
     151        while (isdigit(str.back())) {
     152                PRINT(std::cerr << ".");
     153                str.pop_back();
     154                if (str.size() <= index) return false;
     155        }
     156        PRINT( std::cerr << "]" << std::endl );
     157        if (str.back() != '_') return false;
     158        str.pop_back();
     159        PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; )
     160        return index < str.size();
     161}
     162
     163ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) {
     164        PRINT( std::cerr << "function..." << std::endl; )
     165        if ( done() ) return nullptr;
     166        ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq );
     167        std::unique_ptr<ast::Type> manager( ftype );
     168        ast::Type * retVal = parseType();
     169        if ( !retVal ) return nullptr;
     170        PRINT( std::cerr << "with return type: " << retVal << std::endl; )
     171        ftype->returns.emplace_back( retVal );
     172        if ( done() || !expect('_') ) return nullptr;
     173        while ( !done() ) {
     174                PRINT( std::cerr << "got ch: " << cur() << std::endl; )
     175                if ( cur() == '_' ) return manager.release();
     176                ast::Type * param = parseType();
     177                if ( !param ) return nullptr;
     178                PRINT( std::cerr << "with parameter : " << param << std::endl; )
     179                ftype->params.emplace_back( param );
     180        }
     181        return nullptr;
     182}
     183
     184ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) {
     185        PRINT( std::cerr << "tuple..." << std::endl; )
     186        std::vector<ast::ptr<ast::Type>> types;
     187        size_t ncomponents;
     188        if ( !extractNumber(ncomponents) ) return nullptr;
     189        for ( size_t i = 0; i < ncomponents; ++i ) {
     190                if ( done() ) return nullptr;
     191                PRINT( std::cerr << "got ch: " << cur() << std::endl; )
     192                ast::Type * t = parseType();
     193                if ( !t ) return nullptr;
     194                PRINT( std::cerr << "with type : " << t << std::endl; )
     195                types.push_back( t );
     196        }
     197        return new ast::TupleType( std::move( types ), tq );
     198}
     199
     200ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) {
     201        PRINT( std::cerr << "pointer..." << std::endl; )
     202        ast::Type * t = parseType();
     203        if ( !t ) return nullptr;
     204        return new ast::PointerType( t, tq );
     205}
     206
     207ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) {
     208        PRINT( std::cerr << "array..." << std::endl; )
     209        size_t length;
     210        if ( !extractNumber(length) ) return nullptr;
     211        ast::Type * t = parseType();
     212        if ( !t ) return nullptr;
     213        return new ast::ArrayType(
     214                t,
     215                ast::ConstantExpr::from_ulong( CodeLocation(), length ),
     216                ast::FixedLen,
     217                ast::DynamicDim,
     218                tq );
     219}
     220
     221ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) {
     222        PRINT( std::cerr << "struct..." << std::endl; )
     223        std::string name;
     224        if ( !extractName(name) ) return nullptr;
     225        return new ast::StructInstType( name, tq );
     226}
     227
     228ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) {
     229        PRINT( std::cerr << "union..." << std::endl; )
     230        std::string name;
     231        if ( !extractName(name) ) return nullptr;
     232        return new ast::UnionInstType( name, tq );
     233}
     234
     235ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) {
     236        PRINT( std::cerr << "enum..." << std::endl; )
     237        std::string name;
     238        if ( !extractName(name) ) return nullptr;
     239        return new ast::EnumInstType( name, tq );
     240}
     241
     242ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) {
     243        PRINT( std::cerr << "type..." << std::endl; )
     244        std::string name;
     245        if ( !extractName(name) ) return nullptr;
     246        PRINT( std::cerr << "typename..." << name << std::endl; )
     247        return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq );
     248}
     249
     250ast::Type * Demangler::parseType() {
     251        if (done()) return nullptr;
     252
     253        if (isPrefix(Encoding::forall)) {
     254                PRINT( std::cerr << "polymorphic with..." << std::endl; )
     255                size_t dcount, fcount, vcount, acount;
     256                if ( !extractNumber(dcount) ) return nullptr;
     257                PRINT( std::cerr << dcount << " dtypes" << std::endl; )
     258                if ( !expect('_') ) return nullptr;
     259                if ( !extractNumber(fcount) ) return nullptr;
     260                PRINT( std::cerr << fcount << " ftypes" << std::endl; )
     261                if ( !expect('_')) return nullptr;
     262                if ( !extractNumber(vcount)) return nullptr;
     263                PRINT( std::cerr << vcount << " ttypes" << std::endl; )
     264                if ( !expect('_') ) return nullptr;
     265                if ( !extractNumber(acount) ) return nullptr;
     266                PRINT( std::cerr << acount << " assertions" << std::endl; )
     267                if ( !expect('_') ) return nullptr;
     268                for ( size_t i = 0 ; i < acount ; ++i ) {
     269                        // TODO: need to recursively parse assertions, but for now just return nullptr so that
     270                        // demangler does not crash if there are assertions
     271                        return nullptr;
    228272                }
    229         }
    230 
    231         std::string GenType::handleGeneric( ReferenceToType * refType ) {
    232                 if ( ! refType->parameters.empty() ) {
    233                         std::ostringstream os;
    234                         // TODO: ???
    235                         // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    236                         os << "(";
    237                         // cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
    238                         os << ") ";
    239                         return os.str();
    240                 }
    241                 return "";
    242         }
    243 
    244         void GenType::postvisit( StructInstType * structInst )  {
    245                 typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString;
    246                 handleQualifiers( structInst );
    247         }
    248 
    249         void GenType::postvisit( UnionInstType * unionInst ) {
    250                 typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    251                 handleQualifiers( unionInst );
    252         }
    253 
    254         void GenType::postvisit( EnumInstType * enumInst ) {
    255                 typeString = "enum " + enumInst->name + " " + typeString;
    256                 handleQualifiers( enumInst );
    257         }
    258 
    259         void GenType::postvisit( TypeInstType * typeInst ) {
    260                 typeString = typeInst->name + " " + typeString;
    261                 handleQualifiers( typeInst );
    262         }
    263 
    264         void GenType::postvisit( TupleType * tupleType ) {
    265                 unsigned int i = 0;
    266                 std::ostringstream os;
    267                 os << "[";
    268                 for ( Type * t : *tupleType ) {
    269                         i++;
    270                         os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", ");
    271                 }
    272                 os << "] ";
    273                 typeString = os.str() + typeString;
    274         }
    275 
    276         void GenType::postvisit( VarArgsType * varArgsType ) {
    277                 typeString = "__builtin_va_list " + typeString;
    278                 handleQualifiers( varArgsType );
    279         }
    280 
    281         void GenType::postvisit( ZeroType * zeroType ) {
    282                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    283                 typeString = "zero_t " + typeString;
    284                 handleQualifiers( zeroType );
    285         }
    286 
    287         void GenType::postvisit( OneType * oneType ) {
    288                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    289                 typeString = "one_t " + typeString;
    290                 handleQualifiers( oneType );
    291         }
    292 
    293         void GenType::postvisit( GlobalScopeType * globalType ) {
    294                 handleQualifiers( globalType );
    295         }
    296 
    297         void GenType::postvisit( QualifiedType * qualType ) {
    298                 std::ostringstream os;
    299                 os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString;
    300                 typeString = os.str();
    301                 handleQualifiers( qualType );
    302         }
    303 
    304         void GenType::handleQualifiers( Type * type ) {
    305                 if ( type->get_const() ) {
    306                         typeString = "const " + typeString;
    307                 } // if
    308                 if ( type->get_volatile() ) {
    309                         typeString = "volatile " + typeString;
    310                 } // if
    311                 if ( type->get_restrict() ) {
    312                         typeString = "__restrict " + typeString;
    313                 } // if
    314                 if ( type->get_atomic() ) {
    315                         typeString = "_Atomic " + typeString;
    316                 } // if
    317         }
    318 }
    319 
    320 
    321 namespace SymTab {
    322         namespace Mangler {
    323                 namespace {
    324                         struct StringView {
    325                         private:
    326                                 std::string str;
    327                                 size_t idx = 0;
    328                                 // typedef Type * (StringView::*parser)(Type::Qualifiers);
    329                                 typedef std::function<Type * (Type::Qualifiers)> parser;
    330                                 std::vector<std::pair<std::string, parser>> parsers;
    331                         public:
    332                                 StringView(const std::string & str);
    333 
    334                                 bool done() const { return idx >= str.size(); }
    335                                 char cur() const { assert(! done()); return str[idx]; }
    336 
    337                                 bool expect(char ch) { return str[idx++] == ch; }
    338                                 void next(size_t inc = 1) { idx += inc; }
    339 
    340                                 /// determines if `pref` is a prefix of `str`
    341                                 bool isPrefix(const std::string & pref);
    342                                 bool extractNumber(size_t & out);
    343                                 bool extractName(std::string & out);
    344                                 bool stripMangleName(std::string & name);
    345 
    346                                 Type * parseFunction(Type::Qualifiers tq);
    347                                 Type * parseTuple(Type::Qualifiers tq);
    348                                 Type * parseVoid(Type::Qualifiers tq);
    349                                 Type * parsePointer(Type::Qualifiers tq);
    350                                 Type * parseArray(Type::Qualifiers tq);
    351                                 Type * parseStruct(Type::Qualifiers tq);
    352                                 Type * parseUnion(Type::Qualifiers tq);
    353                                 Type * parseEnum(Type::Qualifiers tq);
    354                                 Type * parseType(Type::Qualifiers tq);
    355 
    356                                 Type * parseType();
    357                                 bool parse(std::string & name, Type *& type);
    358                         };
    359 
    360                         StringView::StringView(const std::string & str) : str(str) {
    361                                 // basic types
    362                                 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
    363                                         parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) {
    364                                                 PRINT( std::cerr << "basic type: " << k << std::endl; )
    365                                                 return new BasicType(tq, (BasicType::Kind)k);
    366                                         });
    367                                 }
    368                                 // type variable types
    369                                 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) {
    370                                         static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
    371                                         static_assert(
    372                                                 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS,
    373                                                 "Each type variable kind should have a demangle name prefix"
    374                                         );
    375                                         parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * {
    376                                                 PRINT( std::cerr << "type variable type: " << k << std::endl; )
    377                                                 size_t N;
    378                                                 if (! extractNumber(N)) return nullptr;
    379                                                 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype);
    380                                         });
    381                                 }
    382                                 // everything else
    383                                 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); });
    384                                 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); });
    385                                 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); });
    386                                 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); });
    387                                 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); });
    388                                 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); });
    389                                 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); });
    390                                 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); });
    391                                 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); });
    392                                 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); });
    393                                 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); });
    394                         }
    395 
    396                         bool StringView::extractNumber(size_t & out) {
    397                                 std::stringstream numss;
    398                                 if (idx >= str.size()) return false;
    399                                 while (isdigit(str[idx])) {
    400                                         numss << str[idx];
    401                                         ++idx;
    402                                         if (idx == str.size()) break;
    403                                 }
    404                                 if (! (numss >> out)) return false;
    405                                 PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
    406                                 return true;
    407                         }
    408 
    409                         bool StringView::extractName(std::string & out) {
    410                                 size_t len;
    411                                 if (! extractNumber(len)) return false;
    412                                 if (idx+len > str.size()) return false;
    413                                 out = str.substr(idx, len);
    414                                 idx += len;
    415                                 PRINT( std::cerr << "extractName success: " << out << std::endl; )
    416                                 return true;
    417                         }
    418 
    419                         bool StringView::isPrefix(const std::string & pref) {
    420                                 // if ( pref.size() > str.size()-idx ) return false;
    421                                 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
    422                                 // if (its.first == pref.end()) {
    423                                 //      idx += pref.size();
    424                                 //      return true;
    425                                 // }
    426 
    427                                 // This update is untested because there are no tests for this code.
    428                                 if ( ::isPrefix( str, pref, idx ) ) {
    429                                         idx += pref.size();
    430                                         return true;
    431                                 }
    432                                 return false;
    433                         }
    434 
    435                         // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
    436                         bool StringView::stripMangleName(std::string & name) {
    437                                 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
    438                                 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
    439                                 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
    440 
    441                                 // get name
    442                                 if (! extractName(name)) return false;
    443 
    444                                 // find bounds for type
    445                                 PRINT( std::cerr << idx << " " << str.size() << std::endl; )
    446                                 PRINT( std::cerr << "[");
    447                                 while (isdigit(str.back())) {
    448                                         PRINT(std::cerr << ".");
    449                                         str.pop_back();
    450                                         if (str.size() <= idx) return false;
    451                                 }
    452                                 PRINT( std::cerr << "]" << std::endl );
    453                                 if (str.back() != '_') return false;
    454                                 str.pop_back();
    455                                 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; )
    456                                 return str.size() > idx;
    457                         }
    458 
    459                         Type * StringView::parseFunction(Type::Qualifiers tq) {
    460                                 PRINT( std::cerr << "function..." << std::endl; )
    461                                 if (done()) return nullptr;
    462                                 FunctionType * ftype = new FunctionType( tq, false );
    463                                 std::unique_ptr<Type> manager(ftype);
    464                                 Type * retVal = parseType();
    465                                 if (! retVal) return nullptr;
    466                                 PRINT( std::cerr << "with return type: " << retVal << std::endl; )
    467                                 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr));
    468                                 if (done() || ! expect('_')) return nullptr;
    469                                 while (! done()) {
    470                                         PRINT( std::cerr << "got ch: " << cur() << std::endl; )
    471                                         if (cur() == '_') return manager.release();
    472                                         Type * param = parseType();
    473                                         if (! param) return nullptr;
    474                                         PRINT( std::cerr << "with parameter : " << param << std::endl; )
    475                                         ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr));
    476                                 }
    477                                 return nullptr;
    478                         }
    479 
    480                         Type * StringView::parseTuple(Type::Qualifiers tq) {
    481                                 PRINT( std::cerr << "tuple..." << std::endl; )
    482                                 std::list< Type * > types;
    483                                 size_t ncomponents;
    484                                 if (! extractNumber(ncomponents)) return nullptr;
    485                                 for (size_t i = 0; i < ncomponents; ++i) {
    486                                         // TODO: delete all on return
    487                                         if (done()) return nullptr;
    488                                         PRINT( std::cerr << "got ch: " << cur() << std::endl; )
    489                                         Type * t = parseType();
    490                                         if (! t) return nullptr;
    491                                         PRINT( std::cerr << "with type : " << t << std::endl; )
    492                                         types.push_back(t);
    493                                 }
    494                                 return new TupleType( tq, types );
    495                         }
    496 
    497                         Type * StringView::parseVoid(Type::Qualifiers tq) {
    498                                 return new VoidType( tq );
    499                         }
    500 
    501                         Type * StringView::parsePointer(Type::Qualifiers tq) {
    502                                 PRINT( std::cerr << "pointer..." << std::endl; )
    503                                 Type * t = parseType();
    504                                 if (! t) return nullptr;
    505                                 return new PointerType( tq, t );
    506                         }
    507 
    508                         Type * StringView::parseArray(Type::Qualifiers tq) {
    509                                 PRINT( std::cerr << "array..." << std::endl; )
    510                                 size_t length;
    511                                 if (! extractNumber(length)) return nullptr;
    512                                 Type * t = parseType();
    513                                 if (! t) return nullptr;
    514                                 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false );
    515                         }
    516 
    517                         Type * StringView::parseStruct(Type::Qualifiers tq) {
    518                                 PRINT( std::cerr << "struct..." << std::endl; )
    519                                 std::string name;
    520                                 if (! extractName(name)) return nullptr;
    521                                 return new StructInstType(tq, name);
    522                         }
    523 
    524                         Type * StringView::parseUnion(Type::Qualifiers tq) {
    525                                 PRINT( std::cerr << "union..." << std::endl; )
    526                                 std::string name;
    527                                 if (! extractName(name)) return nullptr;
    528                                 return new UnionInstType(tq, name);
    529                         }
    530 
    531                         Type * StringView::parseEnum(Type::Qualifiers tq) {
    532                                 PRINT( std::cerr << "enum..." << std::endl; )
    533                                 std::string name;
    534                                 if (! extractName(name)) return nullptr;
    535                                 return new EnumInstType(tq, name);
    536                         }
    537 
    538                         Type * StringView::parseType(Type::Qualifiers tq) {
    539                                 PRINT( std::cerr << "type..." << std::endl; )
    540                                 std::string name;
    541                                 if (! extractName(name)) return nullptr;
    542                                 PRINT( std::cerr << "typename..." << name << std::endl; )
    543                                 return new TypeInstType(tq, name, false);
    544                         }
    545 
    546                         Type * StringView::parseType() {
    547                                 if (done()) return nullptr;
    548 
    549                                 std::list<TypeDecl *> forall;
    550                                 if (isPrefix(Encoding::forall)) {
    551                                         PRINT( std::cerr << "polymorphic with..." << std::endl; )
    552                                         size_t dcount, fcount, vcount, acount;
    553                                         if (! extractNumber(dcount)) return nullptr;
    554                                         PRINT( std::cerr << dcount << " dtypes" << std::endl; )
    555                                         if (! expect('_')) return nullptr;
    556                                         if (! extractNumber(fcount)) return nullptr;
    557                                         PRINT( std::cerr << fcount << " ftypes" << std::endl; )
    558                                         if (! expect('_')) return nullptr;
    559                                         if (! extractNumber(vcount)) return nullptr;
    560                                         PRINT( std::cerr << vcount << " ttypes" << std::endl; )
    561                                         if (! expect('_')) return nullptr;
    562                                         if (! extractNumber(acount)) return nullptr;
    563                                         PRINT( std::cerr << acount << " assertions" << std::endl; )
    564                                         if (! expect('_')) return nullptr;
    565                                         for (size_t i = 0; i < acount; ++i) {
    566                                                 // TODO: need to recursively parse assertions, but for now just return nullptr so that
    567                                                 // demangler does not crash if there are assertions
    568                                                 return nullptr;
    569                                         }
    570                                         if (! expect('_')) return nullptr;
    571                                 }
    572 
    573                                 // qualifiers
    574                                 Type::Qualifiers tq;
    575                                 while (true) {
    576                                         auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
    577                                                 return isPrefix(val.second);
    578                                         });
    579                                         if (qual == Encoding::qualifiers.end()) break;
    580                                         tq |= qual->first;
    581                                 }
    582 
    583                                 // find the correct type parser and use it
    584                                 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) {
    585                                         return isPrefix(p.first);
    586                                 });
    587                                 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx);
    588                                 Type * ret = iter->second(tq);
    589                                 if (! ret) return nullptr;
    590                                 ret->forall = std::move(forall);
    591                                 return ret;
    592                         }
    593 
    594                         bool StringView::parse(std::string & name, Type *& type) {
    595                                 if (! stripMangleName(name)) return false;
    596                                 PRINT( std::cerr << "stripped name: " << name << std::endl; )
    597                                 Type * t = parseType();
    598                                 if (! t) return false;
    599                                 type = t;
    600                                 return true;
    601                         }
    602 
    603                         std::string demangle(const std::string & mangleName) {
    604                                 SymTab::Mangler::StringView view(mangleName);
    605                                 std::string name;
    606                                 Type * type = nullptr;
    607                                 if (! view.parse(name, type)) return mangleName;
    608                                 auto info = CodeGen::operatorLookupByOutput(name);
    609                                 if (info) name = info->inputName;
    610                                 std::unique_ptr<Type> manager(type);
    611                                 return genDemangleType(type, name);
    612                         }
    613                 } // namespace
    614         } // namespace Mangler
    615 } // namespace SymTab
     273                if ( !expect('_') ) return nullptr;
     274        }
     275
     276        ast::CV::Qualifiers tq;
     277        while (true) {
     278                auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
     279                        return isPrefix(val.second);
     280                });
     281                if (qual == Encoding::qualifiers.end()) break;
     282                tq |= qual->first;
     283        }
     284
     285        // Find the correct type parser and then apply it.
     286        auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) {
     287                return isPrefix(p.first);
     288        });
     289        assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index);
     290        ast::Type * ret = iter->second(tq);
     291        if ( !ret ) return nullptr;
     292        return ret;
     293}
     294
     295bool Demangler::parse( std::string & name, ast::Type *& type) {
     296        if ( !stripMangleName(name) ) return false;
     297        PRINT( std::cerr << "stripped name: " << name << std::endl; )
     298        ast::Type * t = parseType();
     299        if ( !t ) return false;
     300        type = t;
     301        return true;
     302}
     303
     304std::string demangle( const std::string & mangleName ) {
     305        using namespace CodeGen;
     306        Demangler demangler( mangleName );
     307        std::string name;
     308        ast::Type * type = nullptr;
     309        if ( !demangler.parse( name, type ) ) return mangleName;
     310        ast::readonly<ast::Type> roType = type;
     311        if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName;
     312        return genType( type, name, Options( false, false, false, false ) );
     313}
     314
     315} // namespace
     316
     317} // namespace Mangle
    616318
    617319extern "C" {
    618320        char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) {
    619                 const std::string & demangleName = SymTab::Mangler::demangle(mangleName);
     321                const std::string & demangleName = Mangle::demangle(mangleName);
    620322                return strdup(demangleName.c_str());
    621323        }
  • src/SymTab/FixFunction.cc

    rdf8ba61a r8d182b1  
    2222#include "AST/Type.hpp"
    2323#include "Common/utility.h"       // for copy
    24 #include "SynTree/Declaration.h"  // for FunctionDecl, ObjectDecl, Declarati...
    25 #include "SynTree/Expression.h"   // for Expression
    26 #include "SynTree/Type.h"         // for ArrayType, PointerType, Type, Basic...
    2724
    2825namespace SymTab {
    29         class FixFunction_old : public WithShortCircuiting {
    30                 typedef Mutator Parent;
    31           public:
    32                 FixFunction_old() : isVoid( false ) {}
    33 
    34                 void premutate(FunctionDecl *functionDecl);
    35                 DeclarationWithType* postmutate(FunctionDecl *functionDecl);
    36 
    37                 Type * postmutate(ArrayType * arrayType);
    38 
    39                 void premutate(ArrayType * arrayType);
    40                 void premutate(VoidType * voidType);
    41                 void premutate(BasicType * basicType);
    42                 void premutate(PointerType * pointerType);
    43                 void premutate(StructInstType * aggregateUseType);
    44                 void premutate(UnionInstType * aggregateUseType);
    45                 void premutate(EnumInstType * aggregateUseType);
    46                 void premutate(TraitInstType * aggregateUseType);
    47                 void premutate(TypeInstType * aggregateUseType);
    48                 void premutate(TupleType * tupleType);
    49                 void premutate(VarArgsType * varArgsType);
    50                 void premutate(ZeroType * zeroType);
    51                 void premutate(OneType * oneType);
    52 
    53                 bool isVoid;
    54         };
    55 
    56         DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) {
    57                 // can't delete function type because it may contain assertions, so transfer ownership to new object
    58                 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );
    59                 pointer->location = functionDecl->location;
    60                 functionDecl->attributes.clear();
    61                 functionDecl->type = nullptr;
    62                 delete functionDecl;
    63                 return pointer;
    64         }
    65 
    66         // xxx - this passes on void[], e.g.
    67         //   void foo(void [10]);
    68         // does not cause an error
    69 
    70         Type * FixFunction_old::postmutate(ArrayType *arrayType) {
    71                 // need to recursively mutate the base type in order for multi-dimensional arrays to work.
    72                 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );
    73                 pointerType->location = arrayType->location;
    74                 arrayType->base = nullptr;
    75                 arrayType->dimension = nullptr;
    76                 delete arrayType;
    77                 return pointerType;
    78         }
    79 
    80         void FixFunction_old::premutate(VoidType *) {
    81                 isVoid = true;
    82         }
    83 
    84         void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; }
    85         void FixFunction_old::premutate(ArrayType *) { visit_children = false; }
    86         void FixFunction_old::premutate(BasicType *) { visit_children = false; }
    87         void FixFunction_old::premutate(PointerType *) { visit_children = false; }
    88         void FixFunction_old::premutate(StructInstType *) { visit_children = false; }
    89         void FixFunction_old::premutate(UnionInstType *) { visit_children = false; }
    90         void FixFunction_old::premutate(EnumInstType *) { visit_children = false; }
    91         void FixFunction_old::premutate(TraitInstType *) { visit_children = false; }
    92         void FixFunction_old::premutate(TypeInstType *) { visit_children = false; }
    93         void FixFunction_old::premutate(TupleType *) { visit_children = false; }
    94         void FixFunction_old::premutate(VarArgsType *) { visit_children = false; }
    95         void FixFunction_old::premutate(ZeroType *) { visit_children = false; }
    96         void FixFunction_old::premutate(OneType *) { visit_children = false; }
    97 
    98         bool fixFunction( DeclarationWithType *& dwt ) {
    99                 PassVisitor<FixFunction_old> fixer;
    100                 dwt = dwt->acceptMutator( fixer );
    101                 return fixer.pass.isVoid;
    102         }
    10326
    10427namespace {
    105         struct FixFunction_new final : public ast::WithShortCircuiting {
     28        struct FixFunction final : public ast::WithShortCircuiting {
    10629                bool isVoid = false;
    10730
     
    14770
    14871const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) {
    149         ast::Pass< FixFunction_new > fixer;
     72        ast::Pass< FixFunction > fixer;
    15073        dwt = dwt->accept( fixer );
    15174        isVoid |= fixer.core.isVoid;
     
    15477
    15578const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ) {
    156         ast::Pass< FixFunction_new > fixer;
     79        ast::Pass< FixFunction > fixer;
    15780        type = type->accept( fixer );
    15881        isVoid |= fixer.core.isVoid;
  • src/SymTab/FixFunction.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 #include "Common/PassVisitor.h" // for PassVisitor
    19 #include "SynTree/SynTree.h"    // for Types
    20 
    2118namespace ast {
    2219        class DeclWithType;
     
    2522
    2623namespace SymTab {
    27         /// Replaces function and array types by equivalent pointer types. Returns true if type is
    28         /// void
    29         bool fixFunction( DeclarationWithType *& );
    30 
    3124        /// Returns declaration with function and array types replaced by equivalent pointer types.
    3225        /// Sets isVoid to true if type is void
  • src/SymTab/GenImplicitCall.cpp

    rdf8ba61a r8d182b1  
    3232template< typename OutIter >
    3333ast::ptr< ast::Stmt > genCall(
    34         InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     34        InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
    3535        const CodeLocation & loc, const std::string & fname, OutIter && out,
    3636        const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
     
    4242template< typename OutIter >
    4343ast::ptr< ast::Stmt > genScalarCall(
    44         InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     44        InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
    4545        const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
    4646        const ast::Type * addCast = nullptr
     
    9898template< typename OutIter >
    9999void genArrayCall(
    100         InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     100        InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
    101101        const CodeLocation & loc, const std::string & fname, OutIter && out,
    102102        const ast::ArrayType * array, const ast::Type * addCast = nullptr,
     
    167167template< typename OutIter >
    168168ast::ptr< ast::Stmt > genCall(
    169         InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     169        InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
    170170        const CodeLocation & loc, const std::string & fname, OutIter && out,
    171171        const ast::Type * type, const ast::Type * addCast, LoopDirection forward
     
    185185
    186186ast::ptr< ast::Stmt > genImplicitCall(
    187         InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     187        InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
    188188        const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
    189189        LoopDirection forward
  • src/SymTab/GenImplicitCall.hpp

    rdf8ba61a r8d182b1  
    2626/// dstParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
    2727ast::ptr<ast::Stmt> genImplicitCall(
    28         InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     28        InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
    2929        const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
    3030        LoopDirection forward = LoopForward
  • src/SymTab/Mangler.cc

    rdf8ba61a r8d182b1  
    2424#include "AST/Pass.hpp"
    2525#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
    26 #include "Common/PassVisitor.h"
    2726#include "Common/ToString.hpp"           // for toCString
    2827#include "Common/SemanticError.h"        // for SemanticError
    29 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    30 #include "SynTree/LinkageSpec.h"         // for Spec, isOverridable, AutoGen, Int...
    31 #include "SynTree/Declaration.h"         // for TypeDecl, DeclarationWithType
    32 #include "SynTree/Expression.h"          // for TypeExpr, Expression, operator<<
    33 #include "SynTree/Type.h"                // for Type, ReferenceToType, Type::Fora...
    34 
    35 namespace SymTab {
    36         namespace Mangler {
    37                 namespace {
    38                         /// Mangles names to a unique C identifier
    39                         struct Mangler_old : public WithShortCircuiting, public WithVisitorRef<Mangler_old>, public WithGuards {
    40                                 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
    41                                 Mangler_old( const Mangler_old & ) = delete;
    42 
    43                                 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    44 
    45                                 void postvisit( const ObjectDecl * declaration );
    46                                 void postvisit( const FunctionDecl * declaration );
    47                                 void postvisit( const TypeDecl * declaration );
    48 
    49                                 void postvisit( const VoidType * voidType );
    50                                 void postvisit( const BasicType * basicType );
    51                                 void postvisit( const PointerType * pointerType );
    52                                 void postvisit( const ArrayType * arrayType );
    53                                 void postvisit( const ReferenceType * refType );
    54                                 void postvisit( const FunctionType * functionType );
    55                                 void postvisit( const StructInstType * aggregateUseType );
    56                                 void postvisit( const UnionInstType * aggregateUseType );
    57                                 void postvisit( const EnumInstType * aggregateUseType );
    58                                 void postvisit( const TypeInstType * aggregateUseType );
    59                                 void postvisit( const TraitInstType * inst );
    60                                 void postvisit( const TupleType * tupleType );
    61                                 void postvisit( const VarArgsType * varArgsType );
    62                                 void postvisit( const ZeroType * zeroType );
    63                                 void postvisit( const OneType * oneType );
    64                                 void postvisit( const QualifiedType * qualType );
    65 
    66                                 std::string get_mangleName() { return mangleName; }
    67                           private:
    68                                 std::string mangleName;         ///< Mangled name being constructed
    69                                 typedef std::map< std::string, std::pair< int, int > > VarMapType;
    70                                 VarMapType varNums;             ///< Map of type variables to indices
    71                                 int nextVarNum;                 ///< Next type variable index
    72                                 bool isTopLevel;                ///< Is the Mangler at the top level
    73                                 bool mangleOverridable;         ///< Specially mangle overridable built-in methods
    74                                 bool typeMode;                  ///< Produce a unique mangled name for a type
    75                                 bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
    76                                 bool inFunctionType = false;    ///< Include type qualifiers if false.
    77                                 bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
    78 
    79                           public:
    80                                 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    81                                         int nextVarNum, const VarMapType& varNums );
    82 
    83                           private:
    84                                 void mangleDecl( const DeclarationWithType * declaration );
    85                                 void mangleRef( const ReferenceToType * refType, std::string prefix );
    86 
    87                                 void printQualifiers( const Type *type );
    88                         }; // Mangler_old
    89                 } // namespace
    90 
    91                 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
    92                         PassVisitor<Mangler_old> mangler( mangleOverridable, typeMode, mangleGenericParams );
    93                         maybeAccept( decl, mangler );
    94                         return mangler.pass.get_mangleName();
    95                 }
    96 
    97                 std::string mangleType( const Type * ty ) {
    98                         PassVisitor<Mangler_old> mangler( false, true, true );
    99                         maybeAccept( ty, mangler );
    100                         return mangler.pass.get_mangleName();
    101                 }
    102 
    103                 std::string mangleConcrete( const Type * ty ) {
    104                         PassVisitor<Mangler_old> mangler( false, false, false );
    105                         maybeAccept( ty, mangler );
    106                         return mangler.pass.get_mangleName();
    107                 }
    108 
    109                 namespace {
    110                         Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
    111                                 : nextVarNum( 0 ), isTopLevel( true ),
    112                                 mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    113                                 mangleGenericParams( mangleGenericParams ) {}
    114 
    115                         Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    116                                 int nextVarNum, const VarMapType& varNums )
    117                                 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
    118                                 mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    119                                 mangleGenericParams( mangleGenericParams ) {}
    120 
    121                         void Mangler_old::mangleDecl( const DeclarationWithType * declaration ) {
    122                                 bool wasTopLevel = isTopLevel;
    123                                 if ( isTopLevel ) {
    124                                         varNums.clear();
    125                                         nextVarNum = 0;
    126                                         isTopLevel = false;
    127                                 } // if
    128                                 mangleName += Encoding::manglePrefix;
    129                                 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
    130                                 if ( opInfo ) {
    131                                         mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
    132                                 } else {
    133                                         mangleName += std::to_string( declaration->name.size() ) + declaration->name;
    134                                 } // if
    135                                 maybeAccept( declaration->get_type(), *visitor );
    136                                 if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
    137                                         // want to be able to override autogenerated and intrinsic routines,
    138                                         // so they need a different name mangling
    139                                         if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
    140                                                 mangleName += Encoding::autogen;
    141                                         } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
    142                                                 mangleName += Encoding::intrinsic;
    143                                         } else {
    144                                                 // if we add another kind of overridable function, this has to change
    145                                                 assert( false && "unknown overrideable linkage" );
    146                                         } // if
    147                                 }
    148                                 isTopLevel = wasTopLevel;
    149                         }
    150 
    151                         void Mangler_old::postvisit( const ObjectDecl * declaration ) {
    152                                 mangleDecl( declaration );
    153                         }
    154 
    155                         void Mangler_old::postvisit( const FunctionDecl * declaration ) {
    156                                 mangleDecl( declaration );
    157                         }
    158 
    159                         void Mangler_old::postvisit( const VoidType * voidType ) {
    160                                 printQualifiers( voidType );
    161                                 mangleName += Encoding::void_t;
    162                         }
    163 
    164                         void Mangler_old::postvisit( const BasicType * basicType ) {
    165                                 printQualifiers( basicType );
    166                                 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    167                                 mangleName += Encoding::basicTypes[ basicType->kind ];
    168                         }
    169 
    170                         void Mangler_old::postvisit( const PointerType * pointerType ) {
    171                                 printQualifiers( pointerType );
    172                                 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    173                                 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;
    174                                 maybeAccept( pointerType->base, *visitor );
    175                         }
    176 
    177                         void Mangler_old::postvisit( const ArrayType * arrayType ) {
    178                                 // TODO: encode dimension
    179                                 printQualifiers( arrayType );
    180                                 mangleName += Encoding::array + "0";
    181                                 maybeAccept( arrayType->base, *visitor );
    182                         }
    183 
    184                         void Mangler_old::postvisit( const ReferenceType * refType ) {
    185                                 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
    186                                 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
    187                                 // by pretending every reference type is a function parameter.
    188                                 GuardValue( inFunctionType );
    189                                 inFunctionType = true;
    190                                 printQualifiers( refType );
    191                                 maybeAccept( refType->base, *visitor );
    192                         }
    193 
    194                         namespace {
    195                                 inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
    196                                         std::list< Type* > ret;
    197                                         std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
    198                                                                         std::mem_fun( &DeclarationWithType::get_type ) );
    199                                         return ret;
    200                                 }
    201                         }
    202 
    203                         void Mangler_old::postvisit( const FunctionType * functionType ) {
    204                                 printQualifiers( functionType );
    205                                 mangleName += Encoding::function;
    206                                 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    207                                 // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
    208                                 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different
    209                                 GuardValue( inFunctionType );
    210                                 inFunctionType = true;
    211                                 std::list< Type* > returnTypes = getTypes( functionType->returnVals );
    212                                 if (returnTypes.empty()) mangleName += Encoding::void_t;
    213                                 else acceptAll( returnTypes, *visitor );
    214                                 mangleName += "_";
    215                                 std::list< Type* > paramTypes = getTypes( functionType->parameters );
    216                                 acceptAll( paramTypes, *visitor );
    217                                 mangleName += "_";
    218                         }
    219 
    220                         void Mangler_old::mangleRef( const ReferenceToType * refType, std::string prefix ) {
    221                                 printQualifiers( refType );
    222 
    223                                 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    224 
    225                                 if ( mangleGenericParams ) {
    226                                         const std::list< Expression* > & params = refType->parameters;
    227                                         if ( ! params.empty() ) {
    228                                                 mangleName += "_";
    229                                                 for ( const Expression * param : params ) {
    230                                                         const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );
    231                                                         assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    232                                                         maybeAccept( paramType->type, *visitor );
    233                                                 }
    234                                                 mangleName += "_";
    235                                         }
    236                                 }
    237                         }
    238 
    239                         void Mangler_old::postvisit( const StructInstType * aggregateUseType ) {
    240                                 mangleRef( aggregateUseType, Encoding::struct_t );
    241                         }
    242 
    243                         void Mangler_old::postvisit( const UnionInstType * aggregateUseType ) {
    244                                 mangleRef( aggregateUseType, Encoding::union_t );
    245                         }
    246 
    247                         void Mangler_old::postvisit( const EnumInstType * aggregateUseType ) {
    248                                 mangleRef( aggregateUseType, Encoding::enum_t );
    249                         }
    250 
    251                         void Mangler_old::postvisit( const TypeInstType * typeInst ) {
    252                                 VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
    253                                 if ( varNum == varNums.end() ) {
    254                                         mangleRef( typeInst, Encoding::type );
    255                                 } else {
    256                                         printQualifiers( typeInst );
    257                                         // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
    258                                         //   forall(dtype T) void f(T);
    259                                         //   forall(dtype S) void f(S);
    260                                         // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    261                                         // are first found and prefixing with the appropriate encoding for the type class.
    262                                         assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    263                                         mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    264                                 } // if
    265                         }
    266 
    267                         void Mangler_old::postvisit( const TraitInstType * inst ) {
    268                                 printQualifiers( inst );
    269                                 mangleName += std::to_string( inst->name.size() ) + inst->name;
    270                         }
    271 
    272                         void Mangler_old::postvisit( const TupleType * tupleType ) {
    273                                 printQualifiers( tupleType );
    274                                 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
    275                                 acceptAll( tupleType->types, *visitor );
    276                         }
    277 
    278                         void Mangler_old::postvisit( const VarArgsType * varArgsType ) {
    279                                 printQualifiers( varArgsType );
    280                                 static const std::string vargs = "__builtin_va_list";
    281                                 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
    282                         }
    283 
    284                         void Mangler_old::postvisit( const ZeroType * ) {
    285                                 mangleName += Encoding::zero;
    286                         }
    287 
    288                         void Mangler_old::postvisit( const OneType * ) {
    289                                 mangleName += Encoding::one;
    290                         }
    291 
    292                         void Mangler_old::postvisit( const QualifiedType * qualType ) {
    293                                 bool inqual = inQualifiedType;
    294                                 if (! inqual ) {
    295                                         // N marks the start of a qualified type
    296                                         inQualifiedType = true;
    297                                         mangleName += Encoding::qualifiedTypeStart;
    298                                 }
    299                                 maybeAccept( qualType->parent, *visitor );
    300                                 maybeAccept( qualType->child, *visitor );
    301                                 if ( ! inqual ) {
    302                                         // E marks the end of a qualified type
    303                                         inQualifiedType = false;
    304                                         mangleName += Encoding::qualifiedTypeEnd;
    305                                 }
    306                         }
    307 
    308                         void Mangler_old::postvisit( const TypeDecl * decl ) {
    309                                 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
    310                                 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
    311                                 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply
    312                                 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
    313                                 // aside from the assert false.
    314                                 assertf( false, "Mangler_old should not visit typedecl: %s", toCString(decl));
    315                                 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    316                                 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
    317                         }
    318 
    319                         __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
    320                                 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
    321                                         os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
    322                                 } // for
    323                         }
    324 
    325                         void Mangler_old::printQualifiers( const Type * type ) {
    326                                 // skip if not including qualifiers
    327                                 if ( typeMode ) return;
    328                                 if ( ! type->forall.empty() ) {
    329                                         std::list< std::string > assertionNames;
    330                                         int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    331                                         mangleName += Encoding::forall;
    332                                         for ( const TypeDecl * i : type->forall ) {
    333                                                 switch ( i->kind ) {
    334                                                   case TypeDecl::Dtype:
    335                                                         dcount++;
    336                                                         break;
    337                                                   case TypeDecl::Ftype:
    338                                                         fcount++;
    339                                                         break;
    340                                                   case TypeDecl::Ttype:
    341                                                         vcount++;
    342                                                         break;
    343                                                   default:
    344                                                         assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[i->kind].c_str() );
    345                                                 } // switch
    346                                                 varNums[ i->name ] = std::make_pair( nextVarNum, (int)i->kind );
    347                                                 for ( const DeclarationWithType * assert : i->assertions ) {
    348                                                         PassVisitor<Mangler_old> sub_mangler(
    349                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    350                                                         assert->accept( sub_mangler );
    351                                                         assertionNames.push_back( sub_mangler.pass.get_mangleName() );
    352                                                         acount++;
    353                                                 } // for
    354                                         } // for
    355                                         mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    356                                         for(const auto & a : assertionNames) mangleName += a;
    357 //                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    358                                         mangleName += "_";
    359                                 } // if
    360                                 if ( ! inFunctionType ) {
    361                                         // these qualifiers do not distinguish the outermost type of a function parameter
    362                                         if ( type->get_const() ) {
    363                                                 mangleName += Encoding::qualifiers.at(Type::Const);
    364                                         } // if
    365                                         if ( type->get_volatile() ) {
    366                                                 mangleName += Encoding::qualifiers.at(Type::Volatile);
    367                                         } // if
    368                                         // Removed due to restrict not affecting function compatibility in GCC
    369                                         // if ( type->get_isRestrict() ) {
    370                                         //      mangleName += "E";
    371                                         // } // if
    372                                         if ( type->get_atomic() ) {
    373                                                 mangleName += Encoding::qualifiers.at(Type::Atomic);
    374                                         } // if
    375                                 }
    376                                 if ( type->get_mutex() ) {
    377                                         mangleName += Encoding::qualifiers.at(Type::Mutex);
    378                                 } // if
    379                                 if ( inFunctionType ) {
    380                                         // turn off inFunctionType so that types can be differentiated for nested qualifiers
    381                                         GuardValue( inFunctionType );
    382                                         inFunctionType = false;
    383                                 }
    384                         }
    385                 } // namespace
    386         } // namespace Mangler
    387 } // namespace SymTab
    38828
    38929namespace Mangle {
    39030        namespace {
    39131                /// Mangles names to a unique C identifier
    392                 struct Mangler_new : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler_new>, public ast::WithGuards {
    393                         Mangler_new( Mangle::Mode mode );
    394                         Mangler_new( const Mangler_new & ) = delete;
     32                struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards {
     33                        Mangler( Mangle::Mode mode );
     34                        Mangler( const Mangler & ) = delete;
    39535
    39636                        void previsit( const ast::Node * ) { visit_children = false; }
     
    43272
    43373                  private:
    434                         Mangler_new( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
     74                        Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    43575                                int nextVarNum, const VarMapType& varNums );
    436                         friend class ast::Pass<Mangler_new>;
     76                        friend class ast::Pass<Mangler>;
    43777
    43878                  private:
     
    44181
    44282                        void printQualifiers( const ast::Type *type );
    443                 }; // Mangler_new
     83                }; // Mangler
    44484        } // namespace
    44585
    44686        std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
    447                 return ast::Pass<Mangler_new>::read( decl, mode );
     87                return ast::Pass<Mangler>::read( decl, mode );
    44888        }
    44989
    45090        namespace {
    451                 Mangler_new::Mangler_new( Mangle::Mode mode )
     91                Mangler::Mangler( Mangle::Mode mode )
    45292                        : nextVarNum( 0 ), isTopLevel( true ),
    45393                        mangleOverridable  ( ! mode.no_overrideable   ),
     
    45595                        mangleGenericParams( ! mode.no_generic_params ) {}
    45696
    457                 Mangler_new::Mangler_new( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
     97                Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    45898                        int nextVarNum, const VarMapType& varNums )
    45999                        : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
     
    461101                        mangleGenericParams( mangleGenericParams ) {}
    462102
    463                 void Mangler_new::mangleDecl( const ast::DeclWithType * decl ) {
     103                void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
    464104                        bool wasTopLevel = isTopLevel;
    465105                        if ( isTopLevel ) {
     
    491131                }
    492132
    493                 void Mangler_new::postvisit( const ast::ObjectDecl * decl ) {
     133                void Mangler::postvisit( const ast::ObjectDecl * decl ) {
    494134                        mangleDecl( decl );
    495135                }
    496136
    497                 void Mangler_new::postvisit( const ast::FunctionDecl * decl ) {
     137                void Mangler::postvisit( const ast::FunctionDecl * decl ) {
    498138                        mangleDecl( decl );
    499139                }
    500140
    501                 void Mangler_new::postvisit( const ast::VoidType * voidType ) {
     141                void Mangler::postvisit( const ast::VoidType * voidType ) {
    502142                        printQualifiers( voidType );
    503143                        mangleName += Encoding::void_t;
    504144                }
    505145
    506                 void Mangler_new::postvisit( const ast::BasicType * basicType ) {
     146                void Mangler::postvisit( const ast::BasicType * basicType ) {
    507147                        printQualifiers( basicType );
    508148                        assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
     
    510150                }
    511151
    512                 void Mangler_new::postvisit( const ast::PointerType * pointerType ) {
     152                void Mangler::postvisit( const ast::PointerType * pointerType ) {
    513153                        printQualifiers( pointerType );
    514154                        // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
     
    517157                }
    518158
    519                 void Mangler_new::postvisit( const ast::ArrayType * arrayType ) {
     159                void Mangler::postvisit( const ast::ArrayType * arrayType ) {
    520160                        // TODO: encode dimension
    521161                        printQualifiers( arrayType );
     
    524164                }
    525165
    526                 void Mangler_new::postvisit( const ast::ReferenceType * refType ) {
     166                void Mangler::postvisit( const ast::ReferenceType * refType ) {
    527167                        // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
    528168                        // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
     
    534174                }
    535175
    536                 void Mangler_new::postvisit( const ast::FunctionType * functionType ) {
     176                void Mangler::postvisit( const ast::FunctionType * functionType ) {
    537177                        printQualifiers( functionType );
    538178                        mangleName += Encoding::function;
     
    549189                }
    550190
    551                 void Mangler_new::mangleRef(
     191                void Mangler::mangleRef(
    552192                                const ast::BaseInstType * refType, const std::string & prefix ) {
    553193                        printQualifiers( refType );
     
    566206                }
    567207
    568                 void Mangler_new::postvisit( const ast::StructInstType * aggregateUseType ) {
     208                void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
    569209                        mangleRef( aggregateUseType, Encoding::struct_t );
    570210                }
    571211
    572                 void Mangler_new::postvisit( const ast::UnionInstType * aggregateUseType ) {
     212                void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
    573213                        mangleRef( aggregateUseType, Encoding::union_t );
    574214                }
    575215
    576                 void Mangler_new::postvisit( const ast::EnumInstType * aggregateUseType ) {
     216                void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
    577217                        mangleRef( aggregateUseType, Encoding::enum_t );
    578218                }
    579219
    580                 void Mangler_new::postvisit( const ast::TypeInstType * typeInst ) {
     220                void Mangler::postvisit( const ast::TypeInstType * typeInst ) {
    581221                        VarMapType::iterator varNum = varNums.find( typeInst->name );
    582222                        if ( varNum == varNums.end() ) {
     
    594234                }
    595235
    596                 void Mangler_new::postvisit( const ast::TraitInstType * inst ) {
     236                void Mangler::postvisit( const ast::TraitInstType * inst ) {
    597237                        printQualifiers( inst );
    598238                        mangleName += std::to_string( inst->name.size() ) + inst->name;
    599239                }
    600240
    601                 void Mangler_new::postvisit( const ast::TupleType * tupleType ) {
     241                void Mangler::postvisit( const ast::TupleType * tupleType ) {
    602242                        printQualifiers( tupleType );
    603243                        mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
     
    605245                }
    606246
    607                 void Mangler_new::postvisit( const ast::VarArgsType * varArgsType ) {
     247                void Mangler::postvisit( const ast::VarArgsType * varArgsType ) {
    608248                        printQualifiers( varArgsType );
    609249                        static const std::string vargs = "__builtin_va_list";
     
    611251                }
    612252
    613                 void Mangler_new::postvisit( const ast::ZeroType * ) {
     253                void Mangler::postvisit( const ast::ZeroType * ) {
    614254                        mangleName += Encoding::zero;
    615255                }
    616256
    617                 void Mangler_new::postvisit( const ast::OneType * ) {
     257                void Mangler::postvisit( const ast::OneType * ) {
    618258                        mangleName += Encoding::one;
    619259                }
    620260
    621                 void Mangler_new::postvisit( const ast::QualifiedType * qualType ) {
     261                void Mangler::postvisit( const ast::QualifiedType * qualType ) {
    622262                        bool inqual = inQualifiedType;
    623263                        if ( !inqual ) {
     
    635275                }
    636276
    637                 void Mangler_new::postvisit( const ast::TypeDecl * decl ) {
     277                void Mangler::postvisit( const ast::TypeDecl * decl ) {
    638278                        // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
    639279                        // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
     
    641281                        // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
    642282                        // aside from the assert false.
    643                         assertf(false, "Mangler_new should not visit typedecl: %s", toCString(decl));
     283                        assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
    644284                        assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    645285                        mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
     
    653293                }
    654294
    655                 void Mangler_new::printQualifiers( const ast::Type * type ) {
     295                void Mangler::printQualifiers( const ast::Type * type ) {
    656296                        // skip if not including qualifiers
    657297                        if ( typeMode ) return;
     
    678318                                } // for
    679319                                for ( auto & assert : funcType->assertions ) {
    680                                         assertionNames.push_back( ast::Pass<Mangler_new>::read(
     320                                        assertionNames.push_back( ast::Pass<Mangler>::read(
    681321                                                assert->var.get(),
    682322                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
  • src/SymTab/Mangler.h

    rdf8ba61a r8d182b1  
    2222
    2323#include "AST/Bitfield.hpp"
    24 #include "SynTree/SynTree.h"  // for Types
    25 #include "SynTree/Visitor.h"  // for Visitor, maybeAccept
    2624
    2725// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
     
    3533        class Node;
    3634}
    37 namespace ResolvExpr {
    38         class TypeEnvironment;
    39 }
    4035
    4136namespace SymTab {
    4237        namespace Mangler {
    43                 /// Mangle syntax tree object; primary interface to clients
    44                 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
    45 
    46                 /// Mangle a type name; secondary interface
    47                 std::string mangleType( const Type * ty );
    48                 /// Mangle ignoring generic type parameters
    49                 std::string mangleConcrete( const Type * ty );
    50 
    5138                namespace Encoding {
    5239                        extern const std::string manglePrefix;
  • src/SymTab/module.mk

    rdf8ba61a r8d182b1  
    1616
    1717SRC_SYMTAB = \
    18         SymTab/Autogen.cc \
    19         SymTab/Autogen.h \
    2018        SymTab/FixFunction.cc \
    2119        SymTab/FixFunction.h \
    2220        SymTab/GenImplicitCall.cpp \
    2321        SymTab/GenImplicitCall.hpp \
    24         SymTab/Indexer.cc \
    25         SymTab/Indexer.h \
    2622        SymTab/Mangler.cc \
    2723        SymTab/ManglerCommon.cc \
    28         SymTab/Mangler.h \
    29         SymTab/ValidateType.cc \
    30         SymTab/ValidateType.h
     24        SymTab/Mangler.h
    3125
    32 SRC += $(SRC_SYMTAB) \
    33         SymTab/Validate.cc \
    34         SymTab/Validate.h
     26SRC += $(SRC_SYMTAB)
    3527
    3628SRCDEMANGLE += $(SRC_SYMTAB) \
  • src/Tuples/Explode.cc

    rdf8ba61a r8d182b1  
    1515
    1616#include "Explode.h"
    17 #include <list>                  // for list
    1817
    1918#include "AST/Pass.hpp"          // for Pass
    20 #include "SynTree/Mutator.h"     // for Mutator
    21 #include "Common/PassVisitor.h"  // for PassVisitor
    2219
    2320namespace Tuples {
    24         namespace {
    25                 // remove one level of reference from a reference type -- may be useful elsewhere.
    26                 Type * getReferenceBase( Type * t ) {
    27                         if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {
    28                                 return refType->get_base();
    29                         } else {
    30                                 // for the moment, I want to know immediately if a non-reference type is ever passed in here.
    31                                 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );
    32                                 return nullptr;
    33                         }
    34                 }
    35 
    36                 struct CastExploder {
    37                         bool castAdded = false;
    38                         bool foundUniqueExpr = false;
    39                         Expression * applyCast( Expression * expr, bool first = true ) {
    40                                 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){
    41                                         foundUniqueExpr = true;
    42                                         std::list< Expression * > exprs;
    43                                         for ( Expression *& expr : tupleExpr->get_exprs() ) {
    44                                                 // move cast into tuple exprs
    45                                                 exprs.push_back( applyCast( expr, false ) );
    46                                         }
    47                                         // want the top-level expression to be cast to reference type, but not nested
    48                                         // tuple expressions
    49                                         if ( first ) {
    50                                                 castAdded = true;
    51                                                 Expression * tupleExpr = new TupleExpr( exprs );
    52                                                 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );
    53                                         } else {
    54                                                 return new TupleExpr( exprs );
    55                                         }
    56                                 }
    57                                 if ( dynamic_cast<ReferenceType*>( expr->result ) ) {
    58                                         // don't need to cast reference type to another reference type
    59                                         return expr->clone();
    60                                 } else {
    61                                         // anything else should be cast to reference as normal
    62                                         castAdded = true;
    63                                         return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
    64                                 }
    65                         }
    66 
    67                         Expression * postmutate( UniqueExpr * uniqueExpr ) {
    68                                 // move cast into unique expr so that the unique expr has type T& rather than
    69                                 // type T. In particular, this transformation helps with generating the
    70                                 // correct code for reference-cast member tuple expressions, since the result
    71                                 // should now be a tuple of references rather than a reference to a tuple.
    72                                 // Still, this code is a bit awkward, and could use some improvement.
    73                                 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );
    74                                 delete uniqueExpr;
    75                                 if ( castAdded ) {
    76                                         // if a cast was added by applyCast, then unique expr now has one more layer of reference
    77                                         // than it had coming into this function. To ensure types still match correctly, need to cast
    78                                         //  to reference base so that outer expressions are still correct.
    79                                         castAdded = false;
    80                                         Type * toType = getReferenceBase( newUniqueExpr->result );
    81                                         return new CastExpr( newUniqueExpr, toType->clone() );
    82                                 }
    83                                 return newUniqueExpr;
    84                         }
    85 
    86 
    87                         Expression * postmutate( TupleIndexExpr * tupleExpr ) {
    88                                 // tuple index expr needs to be rebuilt to ensure that the type of the
    89                                 // field is consistent with the type of the tuple expr, since the field
    90                                 // may have changed from type T to T&.
    91                                 Expression * expr = tupleExpr->get_tuple();
    92                                 tupleExpr->set_tuple( nullptr );
    93                                 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );
    94                                 delete tupleExpr;
    95                                 return ret;
    96                         }
    97                 };
    98         } // namespace
    99 
    100         Expression * distributeReference( Expression * expr ) {
    101                 PassVisitor<CastExploder> exploder;
    102                 expr = expr->acceptMutator( exploder );
    103                 if ( ! exploder.pass.foundUniqueExpr ) {
    104                         // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate
    105                         expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
    106                 }
    107                 return expr;
    108         }
    10921
    11022namespace {
  • src/Tuples/Explode.h

    rdf8ba61a r8d182b1  
    2020
    2121#include "AST/Expr.hpp"
    22 #include "ResolvExpr/Alternative.h"     // for Alternative, AltList
    2322#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
    24 #include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
    2523#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
    26 #include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
    27 #include "SynTree/Type.h"               // for TupleType, Type
    2824#include "Tuples.h"                     // for maybeImpure
    2925
     
    3228}
    3329
    34 namespace SymTab {
    35 class Indexer;
    36 }  // namespace SymTab
    37 
    3830namespace Tuples {
    39         Expression * distributeReference( Expression * );
    40 
    41         static inline CastExpr * isReferenceCast( Expression * expr ) {
    42                 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    43                         if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {
    44                                 return castExpr;
    45                         }
    46                 }
    47                 return nullptr;
    48         }
    49 
    50         /// Append alternative to an OutputIterator of Alternatives
    51         template<typename OutputIterator>
    52         void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,
    53                         const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,
    54                         const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
    55                 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };
    56         }
    57 
    58         /// Append alternative to an ExplodedActual
    59         static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,
    60                         const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,
    61                         const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
    62                 ea.exprs.emplace_back( expr );
    63                 /// xxx -- merge environment, openVars, need, cost?
    64         }
    65 
    66         /// helper function used by explode
    67         template< typename Output >
    68         void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,
    69                         const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {
    70                 if ( isTupleAssign ) {
    71                         // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components
    72                         if ( CastExpr * castExpr = isReferenceCast( expr ) ) {
    73                                 ResolvExpr::AltList alts;
    74                                 explodeUnique(
    75                                         castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
    76                                 for ( ResolvExpr::Alternative & alt : alts ) {
    77                                         // distribute reference cast over all components
    78                                         append( std::forward<Output>(out), distributeReference( alt.release_expr() ),
    79                                                 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );
    80                                 }
    81                                 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
    82                                 return;
    83                         }
    84                 }
    85                 Type * res = expr->get_result()->stripReferences();
    86                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
    87                         if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
    88                                 // can open tuple expr and dump its exploded components
    89                                 for ( Expression * expr : tupleExpr->get_exprs() ) {
    90                                         explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
    91                                 }
    92                         } else {
    93                                 // tuple type, but not tuple expr - recursively index into its components.
    94                                 // if expr type is reference, convert to value type
    95                                 Expression * arg = expr->clone();
    96                                 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    97                                         // expressions which may contain side effects require a single unique instance of the expression.
    98                                         arg = new UniqueExpr( arg );
    99                                 }
    100                                 // cast reference to value type to facilitate further explosion
    101                                 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {
    102                                         arg = new CastExpr( arg, tupleType->clone() );
    103                                 }
    104                                 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
    105                                         TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
    106                                         explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );
    107                                         delete idx;
    108                                 }
    109                                 delete arg;
    110                         }
    111                 } else {
    112                         // atomic (non-tuple) type - output a clone of the expression in a new alternative
    113                         append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,
    114                                 alt.cost, alt.cvtCost );
    115                 }
    116         }
    117 
    118         /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
    119         template< typename Output >
    120         void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,
    121                         Output&& out, bool isTupleAssign = false ) {
    122                 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
    123         }
    124 
    125         // explode list of alternatives
    126         template< typename AltIterator, typename Output >
    127         void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,
    128                         Output&& out, bool isTupleAssign = false ) {
    129                 for ( ; altBegin != altEnd; ++altBegin ) {
    130                         explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );
    131                 }
    132         }
    133 
    134         template< typename Output >
    135         void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,
    136                         bool isTupleAssign = false ) {
    137                 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
    138         }
    13931
    14032const ast::Expr * distributeReference( const ast::Expr * );
  • src/Tuples/TupleAssignment.cc

    rdf8ba61a r8d182b1  
    2828#include "AST/TypeEnvironment.hpp"
    2929#include "CodeGen/OperatorTable.h"
    30 #include "Common/PassVisitor.h"
    3130#include "Common/UniqueName.h"             // for UniqueName
    3231#include "Common/utility.h"                // for splice, zipWith
     
    3433#include "InitTweak/GenInit.h"             // for genCtorInit
    3534#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
    36 #include "ResolvExpr/Alternative.h"        // for AltList, Alternative
    37 #include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
    3835#include "ResolvExpr/Cost.h"               // for Cost
    3936#include "ResolvExpr/Resolver.h"           // for resolveCtorInit
    40 #include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    4137#include "ResolvExpr/typeops.h"            // for combos
    42 #include "SynTree/LinkageSpec.h"           // for Cforall
    43 #include "SynTree/Declaration.h"           // for ObjectDecl
    44 #include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
    45 #include "SynTree/Initializer.h"           // for ConstructorInit, SingleInit
    46 #include "SynTree/Statement.h"             // for ExprStmt
    47 #include "SynTree/Type.h"                  // for Type, Type::Qualifiers
    48 #include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
    49 #include "SynTree/Visitor.h"               // for Visitor
    5038
    5139#if 0
     
    5644
    5745namespace Tuples {
    58         class TupleAssignSpotter_old {
    59           public:
    60                 // dispatcher for Tuple (multiple and mass) assignment operations
    61                 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
    62                 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
    63 
    64           private:
    65                 void match();
    66 
    67                 struct Matcher {
    68                   public:
    69                         Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    70                                 const ResolvExpr::AltList& rhs );
    71                         virtual ~Matcher() {}
    72 
    73                         virtual void match( std::list< Expression * > &out ) = 0;
    74                         ObjectDecl * newObject( UniqueName & namer, Expression * expr );
    75 
    76                         void combineState( const ResolvExpr::Alternative& alt ) {
    77                                 compositeEnv.simpleCombine( alt.env );
    78                                 ResolvExpr::mergeOpenVars( openVars, alt.openVars );
    79                                 cloneAll( alt.need, need );
    80                         }
    81 
    82                         void combineState( const ResolvExpr::AltList& alts ) {
    83                                 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }
    84                         }
    85 
    86                         ResolvExpr::AltList lhs, rhs;
    87                         TupleAssignSpotter_old &spotter;
    88                         ResolvExpr::Cost baseCost;
    89                         std::list< ObjectDecl * > tmpDecls;
    90                         ResolvExpr::TypeEnvironment compositeEnv;
    91                         ResolvExpr::OpenVarSet openVars;
    92                         ResolvExpr::AssertionSet need;
    93                 };
    94 
    95                 struct MassAssignMatcher : public Matcher {
    96                   public:
    97                         MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    98                                 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    99                         virtual void match( std::list< Expression * > &out );
    100                 };
    101 
    102                 struct MultipleAssignMatcher : public Matcher {
    103                   public:
    104                         MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    105                                 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    106                         virtual void match( std::list< Expression * > &out );
    107                 };
    108 
    109                 ResolvExpr::AlternativeFinder &currentFinder;
    110                 std::string fname;
    111                 std::unique_ptr< Matcher > matcher;
    112         };
    113 
    114         /// true if expr is an expression of tuple type
    115         bool isTuple( Expression *expr ) {
    116                 if ( ! expr ) return false;
    117                 assert( expr->result );
    118                 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
    119         }
    120 
    121         template< typename AltIter >
    122         bool isMultAssign( AltIter begin, AltIter end ) {
    123                 // multiple assignment if more than one alternative in the range or if
    124                 // the alternative is a tuple
    125                 if ( begin == end ) return false;
    126                 if ( isTuple( begin->expr ) ) return true;
    127                 return ++begin != end;
    128         }
    129 
    130         bool refToTuple( Expression *expr ) {
    131                 assert( expr->get_result() );
    132                 // also check for function returning tuple of reference types
    133                 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    134                         return refToTuple( castExpr->get_arg() );
    135                 } else {
    136                         return isTuple( expr );
    137                 }
    138                 return false;
    139         }
    140 
    141         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    142                                 std::vector<ResolvExpr::AlternativeFinder> &args ) {
    143                 TupleAssignSpotter_old spotter( currentFinder );
    144                 spotter.spot( expr, args );
    145         }
    146 
    147         TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    148                 : currentFinder(f) {}
    149 
    150         void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    151                         std::vector<ResolvExpr::AlternativeFinder> &args ) {
    152                 if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
    153                         if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
    154                                 fname = op->get_name();
    155 
    156                                 // AlternativeFinder will naturally handle this case case, if it's legal
    157                                 if ( args.size() == 0 ) return;
    158 
    159                                 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote
    160                                 // the function, in which case AlternativeFinder will handle it normally
    161                                 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;
    162 
    163                                 // look over all possible left-hand-sides
    164                                 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {
    165                                         // skip non-tuple LHS
    166                                         if ( ! refToTuple(lhsAlt.expr) ) continue;
    167 
    168                                         // explode is aware of casts - ensure every LHS expression is sent into explode
    169                                         // with a reference cast
    170                                         // xxx - this seems to change the alternatives before the normal
    171                                         //  AlternativeFinder flow; maybe this is desired?
    172                                         if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {
    173                                                 lhsAlt.expr = new CastExpr( lhsAlt.expr,
    174                                                                 new ReferenceType( Type::Qualifiers(),
    175                                                                         lhsAlt.expr->result->clone() ) );
    176                                         }
    177 
    178                                         // explode the LHS so that each field of a tuple-valued-expr is assigned
    179                                         ResolvExpr::AltList lhs;
    180                                         explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );
    181                                         for ( ResolvExpr::Alternative& alt : lhs ) {
    182                                                 // each LHS value must be a reference - some come in with a cast expression,
    183                                                 // if not just cast to reference here
    184                                                 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {
    185                                                         alt.expr = new CastExpr( alt.expr,
    186                                                                 new ReferenceType( Type::Qualifiers(),
    187                                                                         alt.expr->get_result()->clone() ) );
    188                                                 }
    189                                         }
    190 
    191                                         if ( args.size() == 1 ) {
    192                                                 // mass default-initialization/destruction
    193                                                 ResolvExpr::AltList rhs{};
    194                                                 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
    195                                                 match();
    196                                         } else if ( args.size() > 2 ) {
    197                                                 // expand all possible RHS possibilities
    198                                                 // TODO build iterative version of this instead of using combos
    199                                                 std::vector< ResolvExpr::AltList > rhsAlts;
    200                                                 combos( std::next(args.begin(), 1), args.end(),
    201                                                         std::back_inserter( rhsAlts ) );
    202                                                 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {
    203                                                         // multiple assignment
    204                                                         ResolvExpr::AltList rhs;
    205                                                         explode( rhsAlt, currentFinder.get_indexer(),
    206                                                                 std::back_inserter(rhs), true );
    207                                                         matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
    208                                                         match();
    209                                                 }
    210                                         } else {
    211                                                 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {
    212                                                         ResolvExpr::AltList rhs;
    213                                                         if ( isTuple(rhsAlt.expr) ) {
    214                                                                 // multiple assignment
    215                                                                 explode( rhsAlt, currentFinder.get_indexer(),
    216                                                                         std::back_inserter(rhs), true );
    217                                                                 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
    218                                                         } else {
    219                                                                 // mass assignment
    220                                                                 rhs.push_back( rhsAlt );
    221                                                                 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
    222                                                         }
    223                                                         match();
    224                                                 }
    225                                         }
    226                                 }
    227                         }
    228                 }
    229         }
    230 
    231         void TupleAssignSpotter_old::match() {
    232                 assert ( matcher != 0 );
    233 
    234                 std::list< Expression * > new_assigns;
    235                 matcher->match( new_assigns );
    236 
    237                 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
    238                         // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
    239                         // if not the empty tuple case, return early so that no new alternatives are generated.
    240                         if ( new_assigns.empty() ) return;
    241                 }
    242                 ResolvExpr::AltList current;
    243                 // now resolve new assignments
    244                 for ( std::list< Expression * >::iterator i = new_assigns.begin();
    245                                 i != new_assigns.end(); ++i ) {
    246                         PRINT(
    247                                 std::cerr << "== resolving tuple assign ==" << std::endl;
    248                                 std::cerr << *i << std::endl;
    249                         )
    250 
    251                         ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
    252                                 matcher->compositeEnv };
    253 
    254                         try {
    255                                 finder.findWithAdjustment(*i);
    256                         } catch (...) {
    257                                 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid
    258                         }
    259                         // prune expressions that don't coincide with
    260                         ResolvExpr::AltList alts = finder.get_alternatives();
    261                         assert( alts.size() == 1 );
    262                         assert( alts.front().expr != 0 );
    263                         current.push_back( alts.front() );
    264                 }
    265 
    266                 // extract expressions from the assignment alternatives to produce a list of assignments
    267                 // that together form a single alternative
    268                 std::list< Expression *> solved_assigns;
    269                 for ( ResolvExpr::Alternative & alt : current ) {
    270                         solved_assigns.push_back( alt.expr->clone() );
    271                         matcher->combineState( alt );
    272                 }
    273 
    274                 // xxx -- was push_front
    275                 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{
    276                         new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,
    277                         matcher->openVars,
    278                         ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),
    279                         ResolvExpr::sumCost( current ) + matcher->baseCost } );
    280         }
    281 
    282         TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
    283                 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    284         : lhs(lhs), rhs(rhs), spotter(spotter),
    285           baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
    286                 combineState( lhs );
    287                 combineState( rhs );
    288         }
    289 
    290         UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
    291                 assert( left );
    292                 std::list< Expression * > args;
    293                 args.push_back( new VariableExpr( left ) );
    294                 // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
    295                 if ( right ) args.push_back( new VariableExpr( right ) );
    296                 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
    297                         args.front() = new AddressExpr( args.front() );
    298                         if ( right ) args.back() = new AddressExpr( args.back() );
    299                         return new UntypedExpr( new NameExpr( "?=?" ), args );
    300                 } else {
    301                         return new UntypedExpr( new NameExpr( fname ), args );
    302                 }
    303         }
    304 
    305         // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv
    306         // xxx - maybe this should happen in alternative finder for every StmtExpr?
    307         struct EnvRemover {
    308                 void previsit( ExprStmt * stmt ) {
    309                         assert( compositeEnv );
    310                         if ( stmt->expr->env ) {
    311                                 compositeEnv->add( *stmt->expr->env );
    312                                 delete stmt->expr->env;
    313                                 stmt->expr->env = nullptr;
    314                         }
    315                 }
    316 
    317                 ResolvExpr::TypeEnvironment * compositeEnv = nullptr;
    318         };
    319 
    320         ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    321                 assert( expr->result && ! expr->get_result()->isVoid() );
    322                 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
    323                 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
    324                 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {
    325                         ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
    326                         ret->init = ctorInit;
    327                         ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
    328                         PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs
    329                         rm.pass.compositeEnv = &compositeEnv;
    330                         ctorInit->accept( rm );
    331                 }
    332                 PRINT( std::cerr << "new object: " << ret << std::endl; )
    333                 return ret;
    334         }
    335 
    336         void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    337                 static UniqueName lhsNamer( "__massassign_L" );
    338                 static UniqueName rhsNamer( "__massassign_R" );
    339                 // empty tuple case falls into this matcher, hence the second part of the assert
    340                 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
    341 
    342                 // xxx - may need to split this up into multiple declarations, because potential conversion to references
    343                 //  probably should not reference local variable - see MultipleAssignMatcher::match
    344                 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    345                 for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
    346                         // create a temporary object for each value in the lhs and create a call involving the rhs
    347                         ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
    348                         out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
    349                         tmpDecls.push_back( ltmp );
    350                 }
    351                 if ( rtmp ) tmpDecls.push_back( rtmp );
    352         }
    353 
    354         void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    355                 static UniqueName lhsNamer( "__multassign_L" );
    356                 static UniqueName rhsNamer( "__multassign_R" );
    357 
    358                 if ( lhs.size() == rhs.size() ) {
    359                         // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
    360                         std::list< ObjectDecl * > ltmp;
    361                         std::list< ObjectDecl * > rtmp;
    362                         for ( auto p : group_iterate( lhs, rhs ) ) {
    363                                 ResolvExpr::Alternative & lhsAlt = std::get<0>(p);
    364                                 ResolvExpr::Alternative & rhsAlt = std::get<1>(p);
    365                                 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.
    366                                 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );
    367                                 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );
    368                                 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );
    369                                 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );
    370                                 out.push_back( createFunc(spotter.fname, lobj, robj) );
    371                                 ltmp.push_back( lobj );
    372                                 rtmp.push_back( robj );
    373 
    374                                 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment
    375                                 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };
    376                                 finder.findWithAdjustment( rhsAlt.expr );
    377                                 assert( finder.get_alternatives().size() == 1 );
    378                                 compositeEnv = std::move( finder.get_alternatives().front().env );
    379                         }
    380                         tmpDecls.splice( tmpDecls.end(), ltmp );
    381                         tmpDecls.splice( tmpDecls.end(), rtmp );
    382                 }
    383         }
    38446
    38547namespace {
     
    40365
    40466        /// Dispatcher for tuple (multiple and mass) assignment operations
    405         class TupleAssignSpotter_new final {
     67        class TupleAssignSpotter final {
    40668                /// Actually finds tuple assignment operations, by subclass
    40769                struct Matcher {
    40870                        ResolvExpr::CandidateList lhs, rhs;
    409                         TupleAssignSpotter_new & spotter;
     71                        TupleAssignSpotter & spotter;
    41072                        CodeLocation location;
    41173                        ResolvExpr::Cost baseCost;
     
    42284
    42385                        Matcher(
    424                                 TupleAssignSpotter_new & s, const CodeLocation & loc,
     86                                TupleAssignSpotter & s, const CodeLocation & loc,
    42587                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    42688                        : lhs( l ), rhs( r ), spotter( s ), location( loc ),
     
    499161                struct MassAssignMatcher final : public Matcher {
    500162                        MassAssignMatcher(
    501                                 TupleAssignSpotter_new & s, const CodeLocation & loc,
     163                                TupleAssignSpotter & s, const CodeLocation & loc,
    502164                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    503165                        : Matcher( s, loc, l, r ) {}
     
    529191                struct MultipleAssignMatcher final : public Matcher {
    530192                        MultipleAssignMatcher(
    531                                 TupleAssignSpotter_new & s, const CodeLocation & loc,
     193                                TupleAssignSpotter & s, const CodeLocation & loc,
    532194                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    533195                        : Matcher( s, loc, l, r ) {}
     
    578240
    579241        public:
    580                 TupleAssignSpotter_new( ResolvExpr::CandidateFinder & f )
     242                TupleAssignSpotter( ResolvExpr::CandidateFinder & f )
    581243                : crntFinder( f ), fname(), matcher() {}
    582244
     
    715377        std::vector< ResolvExpr::CandidateFinder > & args
    716378) {
    717         TupleAssignSpotter_new spotter{ finder };
     379        TupleAssignSpotter spotter{ finder };
    718380        spotter.spot( assign, args );
    719381}
  • src/Tuples/TupleExpansion.cc

    rdf8ba61a r8d182b1  
    2323#include "AST/Node.hpp"
    2424#include "AST/Type.hpp"
    25 #include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2625#include "Common/ScopedMap.h"     // for ScopedMap
    2726#include "Common/utility.h"       // for CodeLocation
    2827#include "InitTweak/InitTweak.h"  // for getFunction
    29 #include "SynTree/LinkageSpec.h"  // for Spec, C, Intrinsic
    30 #include "SynTree/Constant.h"     // for Constant
    31 #include "SynTree/Declaration.h"  // for StructDecl, DeclarationWithType
    32 #include "SynTree/Expression.h"   // for UntypedMemberExpr, Expression, Uniq...
    33 #include "SynTree/Label.h"        // for operator==, Label
    34 #include "SynTree/Mutator.h"      // for Mutator
    35 #include "SynTree/Type.h"         // for Type, Type::Qualifiers, TupleType
    36 #include "SynTree/Visitor.h"      // for Visitor
    3728#include "Tuples.h"
    3829
    39 class CompoundStmt;
    40 class TypeSubstitution;
     30namespace Tuples {
    4131
    42 namespace Tuples {
    43         namespace {
    44                 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {
    45                         void premutate( UntypedMemberExpr * ) { visit_children = false; }
    46                         Expression * postmutate( UntypedMemberExpr * memberExpr );
    47                 };
    48 
    49                 struct UniqueExprExpander final : public WithDeclsToAdd {
    50                         Expression * postmutate( UniqueExpr * unqExpr );
    51 
    52                         std::map< int, Expression * > decls; // not vector, because order added may not be increasing order
    53 
    54                         ~UniqueExprExpander() {
    55                                 for ( std::pair<const int, Expression *> & p : decls ) {
    56                                         delete p.second;
    57                                 }
    58                         }
    59                 };
    60 
    61                 struct TupleAssignExpander {
    62                         Expression * postmutate( TupleAssignExpr * tupleExpr );
    63                 };
    64 
    65                 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
    66                         Type * postmutate( TupleType * tupleType );
    67 
    68                         void premutate( CompoundStmt * ) {
    69                                 GuardScope( typeMap );
    70                         }
    71                   private:
    72                         ScopedMap< int, StructDecl * > typeMap;
    73                 };
    74 
    75                 struct TupleIndexExpander {
    76                         Expression * postmutate( TupleIndexExpr * tupleExpr );
    77                 };
    78 
    79                 struct TupleExprExpander final {
    80                         Expression * postmutate( TupleExpr * tupleExpr );
    81                 };
    82         }
    83 
    84         void expandMemberTuples( std::list< Declaration * > & translationUnit ) {
    85                 PassVisitor<MemberTupleExpander> expander;
    86                 mutateAll( translationUnit, expander );
    87         }
    88 
    89         void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
    90                 PassVisitor<UniqueExprExpander> unqExpander;
    91                 mutateAll( translationUnit, unqExpander );
    92         }
    93 
    94         void expandTuples( std::list< Declaration * > & translationUnit ) {
    95                 PassVisitor<TupleAssignExpander> assnExpander;
    96                 mutateAll( translationUnit, assnExpander );
    97 
    98                 PassVisitor<TupleTypeReplacer> replacer;
    99                 mutateAll( translationUnit, replacer );
    100 
    101                 PassVisitor<TupleIndexExpander> idxExpander;
    102                 mutateAll( translationUnit, idxExpander );
    103 
    104                 PassVisitor<TupleExprExpander> exprExpander;
    105                 mutateAll( translationUnit, exprExpander );
    106         }
    107 
    108         namespace {
    109                 /// given a expression representing the member and an expression representing the aggregate,
    110                 /// reconstructs a flattened UntypedMemberExpr with the right precedence
    111                 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {
    112                         if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
    113                                 // construct a new UntypedMemberExpr with the correct structure , and recursively
    114                                 // expand that member expression.
    115                                 PassVisitor<MemberTupleExpander> expander;
    116                                 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );
    117                                 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );
    118                                 inner->location = newMemberExpr->location = loc;
    119                                 memberExpr->member = nullptr;
    120                                 memberExpr->aggregate = nullptr;
    121                                 delete memberExpr;
    122                                 return newMemberExpr->acceptMutator( expander );
    123                         } else {
    124                                 // not a member expression, so there is nothing to do but attach and return
    125                                 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );
    126                                 newMemberExpr->location = loc;
    127                                 return newMemberExpr;
    128                         }
    129                 }
    130         }
    131 
    132         Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {
    133                 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {
    134                         Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );
    135                         // aggregate expressions which might be impure must be wrapped in unique expressions
    136                         if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );
    137                         for ( Expression *& expr : tupleExpr->exprs ) {
    138                                 expr = reconstructMemberExpr( expr, aggr, memberExpr->location );
    139                                 expr->location = memberExpr->location;
    140                         }
    141                         delete aggr;
    142                         tupleExpr->location = memberExpr->location;
    143                         return tupleExpr;
    144                 } else {
    145                         // there may be a tuple expr buried in the aggregate
    146                         // xxx - this is a memory leak
    147                         UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );
    148                         newMemberExpr->location = memberExpr->location;
    149                         return newMemberExpr;
    150                 }
    151         }
    152 
    153         Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {
    154                 const int id = unqExpr->get_id();
    155 
    156                 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
    157                 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
    158                 if ( ! decls.count( id ) ) {
    159                         Expression * assignUnq;
    160                         Expression * var = unqExpr->get_var();
    161                         if ( unqExpr->get_object() ) {
    162                                 // an object was generated to represent this unique expression -- it should be added to the list of declarations now
    163                                 declsToAddBefore.push_back( unqExpr->get_object() );
    164                                 unqExpr->set_object( nullptr );
    165                                 // steal the expr from the unqExpr
    166                                 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );
    167                                 unqExpr->set_expr( nullptr );
    168                         } else {
    169                                 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit
    170                                 Expression * expr = unqExpr->get_expr();
    171                                 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );
    172                                 assignUnq = commaExpr->get_arg1();
    173                                 commaExpr->set_arg1( nullptr );
    174                         }
    175                         ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),
    176                                                                                                         new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    177                         declsToAddBefore.push_back( finished );
    178                         // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
    179                         // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
    180                         Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );
    181                         ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),
    182                                 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );
    183                         condExpr->set_result( var->get_result()->clone() );
    184                         condExpr->set_env( maybeClone( unqExpr->get_env() ) );
    185                         decls[id] = condExpr;
    186                 }
    187                 delete unqExpr;
    188                 return decls[id]->clone();
    189         }
    190 
    191         Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {
    192                 StmtExpr * ret = assnExpr->get_stmtExpr();
    193                 assnExpr->set_stmtExpr( nullptr );
    194                 // move env to StmtExpr
    195                 ret->set_env( assnExpr->get_env() );
    196                 assnExpr->set_env( nullptr );
    197                 delete assnExpr;
    198                 return ret;
    199         }
    200 
    201         Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {
    202                 unsigned tupleSize = tupleType->size();
    203                 if ( ! typeMap.count( tupleSize ) ) {
    204                         // generate struct type to replace tuple type based on the number of components in the tuple
    205                         StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );
    206                         decl->location = tupleType->location;
    207                         decl->set_body( true );
    208                         for ( size_t i = 0; i < tupleSize; ++i ) {
    209                                 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );
    210                                 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );
    211                                 decl->get_parameters().push_back( tyParam );
    212                         }
    213                         if ( tupleSize == 0 ) {
    214                                 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.
    215                                 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
    216                         }
    217                         typeMap[tupleSize] = decl;
    218                         declsToAddBefore.push_back( decl );
    219                 }
    220                 Type::Qualifiers qualifiers = tupleType->get_qualifiers();
    221 
    222                 StructDecl * decl = typeMap[tupleSize];
    223                 StructInstType * newType = new StructInstType( qualifiers, decl );
    224                 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {
    225                         Type * t = std::get<0>(p);
    226                         newType->get_parameters().push_back( new TypeExpr( t->clone() ) );
    227                 }
    228                 delete tupleType;
    229                 return newType;
    230         }
    231 
    232         Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {
    233                 Expression * tuple = tupleExpr->tuple;
    234                 assert( tuple );
    235                 tupleExpr->tuple = nullptr;
    236                 unsigned int idx = tupleExpr->index;
    237                 TypeSubstitution * env = tupleExpr->env;
    238                 tupleExpr->env = nullptr;
    239                 delete tupleExpr;
    240 
    241                 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {
    242                         if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {
    243                                 // optimization: definitely pure tuple expr => can reduce to the only relevant component.
    244                                 assert( tupleExpr->exprs.size() > idx );
    245                                 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);
    246                                 Expression * ret = expr;
    247                                 ret->env = env;
    248                                 expr = nullptr; // remove from list so it can safely be deleted
    249                                 delete tupleExpr;
    250                                 return ret;
    251                         }
    252                 }
    253 
    254                 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );
    255                 StructDecl * structDecl = type->baseStruct;
    256                 assert( structDecl->members.size() > idx );
    257                 Declaration * member = *std::next(structDecl->members.begin(), idx);
    258                 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );
    259                 memExpr->env = env;
    260                 return memExpr;
    261         }
    262 
    263         Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {
    264                 if ( result->isVoid() ) {
    265                         // void result - don't need to produce a value for cascading - just output a chain of comma exprs
    266                         assert( ! exprs.empty() );
    267                         std::list< Expression * >::const_iterator iter = exprs.begin();
    268                         Expression * expr = new CastExpr( *iter++ );
    269                         for ( ; iter != exprs.end(); ++iter ) {
    270                                 expr = new CommaExpr( expr, new CastExpr( *iter ) );
    271                         }
    272                         expr->set_env( env );
    273                         return expr;
    274                 } else {
    275                         // typed tuple expression - produce a compound literal which performs each of the expressions
    276                         // as a distinct part of its initializer - the produced compound literal may be used as part of
    277                         // another expression
    278                         std::list< Initializer * > inits;
    279                         for ( Expression * expr : exprs ) {
    280                                 inits.push_back( new SingleInit( expr ) );
    281                         }
    282                         Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );
    283                         expr->set_env( env );
    284                         return expr;
    285                 }
    286         }
    287 
    288         Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {
    289                 Type * result = tupleExpr->get_result();
    290                 std::list< Expression * > exprs = tupleExpr->get_exprs();
    291                 assert( result );
    292                 TypeSubstitution * env = tupleExpr->get_env();
    293 
    294                 // remove data from shell and delete it
    295                 tupleExpr->set_result( nullptr );
    296                 tupleExpr->get_exprs().clear();
    297                 tupleExpr->set_env( nullptr );
    298                 delete tupleExpr;
    299 
    300                 return replaceTupleExpr( result, exprs, env );
    301         }
    302 
    303         Type * makeTupleType( const std::list< Expression * > & exprs ) {
    304                 // produce the TupleType which aggregates the types of the exprs
    305                 std::list< Type * > types;
    306                 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );
    307                 for ( Expression * expr : exprs ) {
    308                         assert( expr->get_result() );
    309                         if ( expr->get_result()->isVoid() ) {
    310                                 // if the type of any expr is void, the type of the entire tuple is void
    311                                 return new VoidType( Type::Qualifiers() );
    312                         }
    313                         Type * type = expr->get_result()->clone();
    314                         types.push_back( type );
    315                         // the qualifiers on the tuple type are the qualifiers that exist on all component types
    316                         qualifiers &= type->get_qualifiers();
    317                 } // for
    318                 if ( exprs.empty() ) qualifiers = Type::Qualifiers();
    319                 return new TupleType( qualifiers, types );
    320         }
    32132        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
    32233                // produce the TupleType which aggregates the types of the exprs
     
    34152        }
    34253
    343         TypeInstType * isTtype( Type * type ) {
    344                 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {
    345                         if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {
    346                                 return inst;
    347                         }
    348                 }
    349                 return nullptr;
    350         }
    351 
    352         const TypeInstType * isTtype( const Type * type ) {
    353                 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {
    354                         if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {
    355                                 return inst;
    356                         }
    357                 }
    358                 return nullptr;
    359         }
    360 
    36154        const ast::TypeInstType * isTtype( const ast::Type * type ) {
    36255                if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
  • src/Tuples/Tuples.cc

    rdf8ba61a r8d182b1  
    1919#include "AST/Inspect.hpp"
    2020#include "AST/LinkageSpec.hpp"
    21 #include "Common/PassVisitor.h"
    2221#include "InitTweak/InitTweak.h"
    2322
     
    2524
    2625namespace {
    27         /// Checks if impurity (read: side-effects) may exist in a piece of code.
    28         /// Currently gives a very crude approximation, wherein any function
    29         /// call expression means the code may be impure.
    30         struct ImpurityDetector_old : public WithShortCircuiting {
    31                 bool const ignoreUnique;
    32                 bool maybeImpure;
    33 
    34                 ImpurityDetector_old( bool ignoreUnique ) :
    35                         ignoreUnique( ignoreUnique ), maybeImpure( false )
    36                 {}
    37 
    38                 void previsit( const ApplicationExpr * appExpr ) {
    39                         visit_children = false;
    40                         if ( const DeclarationWithType * function =
    41                                         InitTweak::getFunction( appExpr ) ) {
    42                                 if ( function->linkage == LinkageSpec::Intrinsic ) {
    43                                         if ( function->name == "*?" || function->name == "?[?]" ) {
    44                                                 // intrinsic dereference, subscript are pure,
    45                                                 // but need to recursively look for impurity
    46                                                 visit_children = true;
    47                                                 return;
    48                                         }
    49                                 }
    50                         }
    51                         maybeImpure = true;
    52                 }
    53 
    54                 void previsit( const UntypedExpr * ) {
    55                         maybeImpure = true;
    56                         visit_children = false;
    57                 }
    58 
    59                 void previsit( const UniqueExpr * ) {
    60                         if ( ignoreUnique ) {
    61                                 // bottom out at unique expression.
    62                                 // The existence of a unique expression doesn't change the purity of an expression.
    63                                 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
    64                                 visit_children = false;
    65                                 return;
    66                         }
    67                 }
    68         };
    69 
    70         bool detectImpurity( const Expression * expr, bool ignoreUnique ) {
    71                 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );
    72                 expr->accept( detector );
    73                 return detector.pass.maybeImpure;
    74         }
    7526
    7627        /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
     
    11061}
    11162
    112 bool maybeImpure( const Expression * expr ) {
    113         return detectImpurity( expr, false );
    114 }
    115 
    116 bool maybeImpureIgnoreUnique( const Expression * expr ) {
    117         return detectImpurity( expr, true );
    118 }
    119 
    12063} // namespace Tuples
    12164
  • src/Tuples/Tuples.h

    rdf8ba61a r8d182b1  
    2121#include "AST/Fwd.hpp"
    2222#include "AST/Node.hpp"
    23 #include "SynTree/Expression.h"
    24 #include "SynTree/Declaration.h"
    25 #include "SynTree/Type.h"
    26 
    27 #include "ResolvExpr/AlternativeFinder.h"
    2823#include "ResolvExpr/CandidateFinder.hpp"
    2924
    3025namespace Tuples {
    3126        // TupleAssignment.cc
    32         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
    33                 std::vector< ResolvExpr::AlternativeFinder >& args );
    3427        void handleTupleAssignment(
    3528                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     
    3831        // TupleExpansion.cc
    3932        /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
    40         void expandMemberTuples( std::list< Declaration * > & translationUnit );
    4133        void expandMemberTuples( ast::TranslationUnit & translationUnit );
    4234
    4335        /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
    44         void expandTuples( std::list< Declaration * > & translationUnit );
    4536        void expandTuples( ast::TranslationUnit & translaionUnit );
    4637
    4738        /// replaces UniqueExprs with a temporary variable and one call
    48         void expandUniqueExpr( std::list< Declaration * > & translationUnit );
    4939        void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    5040
    5141        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    52         Type * makeTupleType( const std::list< Expression * > & exprs );
    5342        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    5443
    5544        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    56         TypeInstType * isTtype( Type * type );
    57         const TypeInstType * isTtype( const Type * type );
    5845        const ast::TypeInstType * isTtype( const ast::Type * type );
    5946
    6047        /// returns true if the expression may contain side-effects.
    61         bool maybeImpure( const Expression * expr );
    6248        bool maybeImpure( const ast::Expr * expr );
    6349
    6450        /// Returns true if the expression may contain side-effect,
    6551        /// ignoring the presence of unique expressions.
    66         bool maybeImpureIgnoreUnique( const Expression * expr );
    6752        bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    6853} // namespace Tuples
  • src/Validate/Autogen.cpp

    rdf8ba61a r8d182b1  
    4949
    5050// --------------------------------------------------------------------------
    51 struct AutogenerateRoutines_new final :
     51struct AutogenerateRoutines final :
    5252                public ast::WithDeclsToAdd<>,
    5353                public ast::WithShortCircuiting {
     
    232232
    233233// --------------------------------------------------------------------------
    234 void AutogenerateRoutines_new::previsit( const ast::EnumDecl * enumDecl ) {
     234void AutogenerateRoutines::previsit( const ast::EnumDecl * enumDecl ) {
    235235        // Must visit children (enum constants) to add them to the symbol table.
    236236        if ( !enumDecl->body ) return;
     
    249249}
    250250
    251 void AutogenerateRoutines_new::previsit( const ast::StructDecl * structDecl ) {
     251void AutogenerateRoutines::previsit( const ast::StructDecl * structDecl ) {
    252252        visit_children = false;
    253253        if ( !structDecl->body ) return;
     
    265265}
    266266
    267 void AutogenerateRoutines_new::previsit( const ast::UnionDecl * unionDecl ) {
     267void AutogenerateRoutines::previsit( const ast::UnionDecl * unionDecl ) {
    268268        visit_children = false;
    269269        if ( !unionDecl->body ) return;
     
    282282
    283283/// Generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
    284 void AutogenerateRoutines_new::previsit( const ast::TypeDecl * typeDecl ) {
     284void AutogenerateRoutines::previsit( const ast::TypeDecl * typeDecl ) {
    285285        if ( !typeDecl->base ) return;
    286286
     
    290290}
    291291
    292 void AutogenerateRoutines_new::previsit( const ast::TraitDecl * ) {
     292void AutogenerateRoutines::previsit( const ast::TraitDecl * ) {
    293293        // Ensure that we don't add assignment ops for types defined as part of the trait
    294294        visit_children = false;
    295295}
    296296
    297 void AutogenerateRoutines_new::previsit( const ast::FunctionDecl * ) {
     297void AutogenerateRoutines::previsit( const ast::FunctionDecl * ) {
    298298        // Track whether we're currently in a function.
    299299        // Can ignore function type idiosyncrasies, because function type can never
     
    302302}
    303303
    304 void AutogenerateRoutines_new::postvisit( const ast::FunctionDecl * ) {
     304void AutogenerateRoutines::postvisit( const ast::FunctionDecl * ) {
    305305        functionNesting -= 1;
    306306}
     
    521521                const ast::Expr * src, const ast::ObjectDecl * field,
    522522                ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
    523         InitTweak::InitExpander_new srcParam( src );
     523        InitTweak::InitExpander srcParam( src );
    524524        // Assign to destination.
    525525        ast::MemberExpr * dstSelect = new ast::MemberExpr(
     
    795795
    796796void autogenerateRoutines( ast::TranslationUnit & translationUnit ) {
    797         ast::Pass<AutogenerateRoutines_new>::run( translationUnit );
     797        ast::Pass<AutogenerateRoutines>::run( translationUnit );
    798798}
    799799
  • src/Validate/FindSpecialDecls.h

    rdf8ba61a r8d182b1  
    1616#pragma once
    1717
    18 #include <list>  // for list
    19 
    20 class Declaration;
    21 class FunctionDecl;
    22 class StructDecl;
    23 class Type;
    24 
    2518namespace ast {
    2619        class TranslationUnit;
     
    2821
    2922namespace Validate {
    30         /// size_t type - set when size_t typedef is seen. Useful in a few places,
    31         /// such as in determining array dimension type
    32         extern Type * SizeType;
    33 
    34         /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations.
    35         /// Useful for creating dereference ApplicationExprs without a full resolver pass.
    36         extern FunctionDecl * dereferenceOperator;
    37 
    38         /// special built-in functions and data structures necessary for destructor generation
    39         extern StructDecl * dtorStruct;
    40         extern FunctionDecl * dtorStructDestroy;
    41 
    42         /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times.
    43         void findSpecialDecls( std::list< Declaration * > & translationUnit );
    4423
    4524/// Find and remember some of the special declarations that are useful for
  • src/Validate/module.mk

    rdf8ba61a r8d182b1  
    1616
    1717SRC_VALIDATE = \
    18         Validate/FindSpecialDecls.cc \
    1918        Validate/FindSpecialDecls.h
    2019
     
    3736        Validate/GenericParameter.cpp \
    3837        Validate/GenericParameter.hpp \
    39         Validate/HandleAttributes.cc \
    40         Validate/HandleAttributes.h \
    4138        Validate/HoistStruct.cpp \
    4239        Validate/HoistStruct.hpp \
  • src/Virtual/ExpandCasts.cc

    rdf8ba61a r8d182b1  
    2424#include "AST/Expr.hpp"
    2525#include "AST/Pass.hpp"
    26 #include "Common/PassVisitor.h"    // for PassVisitor
    2726#include "Common/ScopedMap.h"      // for ScopedMap
    2827#include "Common/SemanticError.h"  // for SemanticError
    2928#include "SymTab/Mangler.h"        // for mangleType
    30 #include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
    31 #include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
    32 #include "SynTree/Mutator.h"       // for mutateAll
    33 #include "SynTree/Type.h"          // for Type, PointerType, StructInstType
    34 #include "SynTree/Visitor.h"       // for acceptAll
    3529
    3630namespace Virtual {
     
    4337}
    4438
    45 bool is_type_id_object( const ObjectDecl * objectDecl ) {
    46         const std::string & objectName = objectDecl->name;
    47         return is_prefix( "__cfatid_", objectName );
    48 }
    49 
    5039bool is_type_id_object( const ast::ObjectDecl * decl ) {
    5140        return is_prefix( "__cfatid_", decl->name );
     
    5544
    5645        /// Maps virtual table types the instance for that type.
    57         class VirtualTableMap final {
    58                 ScopedMap<std::string, ObjectDecl *> vtable_instances;
    59         public:
    60                 void enterScope() {
    61                         vtable_instances.beginScope();
    62                 }
    63                 void leaveScope() {
    64                         vtable_instances.endScope();
    65                 }
    66 
    67                 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
    68                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
    69                         ObjectDecl *& value = vtable_instances[ mangledName ];
    70                         if ( value ) {
    71                                 if ( vtableDecl->storageClasses.is_extern ) {
    72                                         return nullptr;
    73                                 } else if ( ! value->storageClasses.is_extern ) {
    74                                         return value;
    75                                 }
    76                         }
    77                         value = vtableDecl;
    78                         return nullptr;
    79                 }
    80 
    81                 ObjectDecl * lookup( const Type * vtableType ) {
    82                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
    83                         const auto it = vtable_instances.find( mangledName );
    84                         return ( vtable_instances.end() == it ) ? nullptr : it->second;
    85                 }
    86         };
    87 
    88         class VirtualCastCore {
    89                 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
    90                         Type * type = new StructInstType(
    91                                 Type::Qualifiers( Type::Const ), pvt_decl );
    92                         for (int i = 0 ; i < level_of_indirection ; ++i) {
    93                                 type = new PointerType( noQualifiers, type );
    94                         }
    95                         return new CastExpr( expr, type );
    96                 }
    97 
    98         public:
    99                 VirtualCastCore() :
    100                         indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
    101                 {}
    102 
    103                 void premutate( FunctionDecl * functionDecl );
    104                 void premutate( StructDecl * structDecl );
    105                 void premutate( ObjectDecl * objectDecl );
    106 
    107                 Expression * postmutate( VirtualCastExpr * castExpr );
    108 
    109                 VirtualTableMap indexer;
    110         private:
    111                 FunctionDecl *vcast_decl;
    112                 StructDecl *pvt_decl;
    113         };
    114 
    115         void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
    116                 if ( (! vcast_decl) &&
    117                      functionDecl->get_name() == "__cfavir_virtual_cast" ) {
    118                         vcast_decl = functionDecl;
    119                 }
    120         }
    121 
    122         void VirtualCastCore::premutate( StructDecl * structDecl ) {
    123                 if ( pvt_decl || ! structDecl->has_body() ) {
    124                         return;
    125                 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {
    126                         pvt_decl = structDecl;
    127                 }
    128         }
    129 
    130         void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    131                 if ( is_type_id_object( objectDecl ) ) {
    132                         // Multiple definitions should be fine because of linkonce.
    133                         indexer.insert( objectDecl );
    134                 }
    135         }
    136 
    137         /// Better error locations for generated casts.
    138         CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
    139                 if ( castExpr->location.isSet() ) {
    140                         return castExpr->location;
    141                 } else if ( castExpr->arg->location.isSet() ) {
    142                         return castExpr->arg->location;
    143                 } else if ( castExpr->result->location.isSet() ) {
    144                         return castExpr->result->location;
    145                 } else {
    146                         return CodeLocation();
    147                 }
    148         }
    149 
    150         [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
    151                 SemanticError( castLocation( castExpr ), message );
    152         }
    153 
    154         /// Get the base type from a pointer or reference.
    155         const Type * getBaseType( const Type * type ) {
    156                 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
    157                         return target->base;
    158                 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
    159                         return target->base;
    160                 } else {
    161                         return nullptr;
    162                 }
    163         }
    164 
    165         /* Attempt to follow the "head" field of the structure to get the...
    166          * Returns nullptr on error, otherwise owner must free returned node.
    167          */
    168         StructInstType * followHeadPointerType(
    169                         const StructInstType * oldType,
    170                         const std::string& fieldName,
    171                         const CodeLocation& errorLocation ) {
    172 
    173                 // First section of the function is all about trying to fill this variable in.
    174                 StructInstType * newType = nullptr;
    175                 {
    176                         const StructDecl * oldDecl = oldType->baseStruct;
    177                         assert( oldDecl );
    178 
    179                         // Helper function for throwing semantic errors.
    180                         auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
    181                                 const std::string& context = "While following head pointer of " +
    182                                         oldDecl->name + " named '" + fieldName + "': ";
    183                                 SemanticError( errorLocation, context + message );
    184                         };
    185 
    186                         if ( oldDecl->members.empty() ) {
    187                                 throwError( "Type has no fields." );
    188                         }
    189                         const Declaration * memberDecl = oldDecl->members.front();
    190                         assert( memberDecl );
    191                         const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    192                         assert( fieldDecl );
    193                         if ( fieldName != fieldDecl->name ) {
    194                                 throwError( "Head field did not have expected name." );
    195                         }
    196 
    197                         const Type * fieldType = fieldDecl->type;
    198                         if ( nullptr == fieldType ) {
    199                                 throwError( "Could not get head field." );
    200                         }
    201                         const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
    202                         if ( nullptr == ptrType ) {
    203                                 throwError( "First field is not a pointer type." );
    204                         }
    205                         assert( ptrType->base );
    206                         newType = dynamic_cast<StructInstType *>( ptrType->base );
    207                         if ( nullptr == newType ) {
    208                                 throwError( "First field does not point to a structure type." );
    209                         }
    210                 }
    211 
    212                 // Now we can look into copying it.
    213                 newType = newType->clone();
    214                 if ( ! oldType->parameters.empty() ) {
    215                         deleteAll( newType->parameters );
    216                         newType->parameters.clear();
    217                         cloneAll( oldType->parameters, newType->parameters );
    218                 }
    219                 return newType;
    220         }
    221 
    222         /// Get the type-id type from a virtual type.
    223         StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
    224                 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
    225                 if ( nullptr == typeInst ) {
    226                         return nullptr;
    227                 }
    228                 StructInstType * tableInst =
    229                         followHeadPointerType( typeInst, "virtual_table", errorLocation );
    230                 if ( nullptr == tableInst ) {
    231                         return nullptr;
    232                 }
    233                 StructInstType * typeIdInst =
    234                         followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
    235                 delete tableInst;
    236                 return typeIdInst;
    237         }
    238 
    239         Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    240                 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
    241 
    242                 assert( vcast_decl );
    243                 assert( pvt_decl );
    244 
    245                 const Type * base_type = getBaseType( castExpr->result );
    246                 if ( nullptr == base_type ) {
    247                         castError( castExpr, "Virtual cast target must be a pointer or reference type." );
    248                 }
    249                 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
    250                 if ( nullptr == type_id_type ) {
    251                         castError( castExpr, "Ill formed virtual cast target type." );
    252                 }
    253                 ObjectDecl * type_id = indexer.lookup( type_id_type );
    254                 delete type_id_type;
    255                 if ( nullptr == type_id ) {
    256                         castError( castExpr, "Virtual cast does not target a virtual type." );
    257                 }
    258 
    259                 Expression * result = new CastExpr(
    260                         new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    261                                 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
    262                                 cast_to_type_id( castExpr->get_arg(), 2 ),
    263                         } ),
    264                         castExpr->get_result()->clone()
    265                 );
    266 
    267                 castExpr->set_arg( nullptr );
    268                 castExpr->set_result( nullptr );
    269                 delete castExpr;
    270                 return result;
    271         }
    27246
    27347/// Better error locations for generated casts.
     
    494268} // namespace
    495269
    496 void expandCasts( std::list< Declaration * > & translationUnit ) {
    497         PassVisitor<VirtualCastCore> translator;
    498         mutateAll( translationUnit, translator );
    499 }
    500 
    501270void expandCasts( ast::TranslationUnit & translationUnit ) {
    502271        ast::Pass<ExpandCastsCore>::run( translationUnit );
  • src/Virtual/Tables.cc

    rdf8ba61a r8d182b1  
    2121#include "AST/Stmt.hpp"
    2222#include "AST/Type.hpp"
    23 #include <SynTree/Attribute.h>
    24 #include <SynTree/Declaration.h>
    25 #include <SynTree/Expression.h>
    26 #include <SynTree/Statement.h>
    27 #include <SynTree/Type.h>
    2823
    2924namespace Virtual {
     
    6560        return 17 < name.size() && '_' == name[0] &&
    6661                std::string("_vtable_instance") == name.substr(1, name.size() - 17);
    67 }
    68 
    69 static ObjectDecl * makeVtableDeclaration(
    70                 std::string const & name,
    71                 StructInstType * type, Initializer * init ) {
    72         Type::StorageClasses storage = noStorageClasses;
    73         if ( nullptr == init ) {
    74                 storage.is_extern = true;
    75         }
    76         return new ObjectDecl(
    77                 name,
    78                 storage,
    79                 LinkageSpec::Cforall,
    80                 nullptr,
    81                 type,
    82                 init
    83         );
    8462}
    8563
     
    10179}
    10280
    103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
    104         assert( type );
    105         return makeVtableDeclaration( name, type, nullptr );
    106 }
    107 
    10881ast::ObjectDecl * makeVtableForward(
    10982                CodeLocation const & location, std::string const & name,
     
    11184        assert( vtableType );
    11285        return makeVtableDeclaration( location, name, vtableType, nullptr );
    113 }
    114 
    115 ObjectDecl * makeVtableInstance(
    116                 std::string const & name, StructInstType * vtableType,
    117                 Type * objectType, Initializer * init ) {
    118         assert( vtableType );
    119         assert( objectType );
    120         StructDecl * vtableStruct = vtableType->baseStruct;
    121         // Build the initialization
    122         if ( nullptr == init ) {
    123                 std::list< Initializer * > inits;
    124 
    125                 // This is going to have to be run before the resolver to connect expressions.
    126                 for ( auto field : vtableStruct->members ) {
    127                         if ( std::string( "parent" ) == field->name ) {
    128                                 // This will not work with polymorphic state.
    129                                 auto oField = strict_dynamic_cast< ObjectDecl * >( field );
    130                                 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );
    131                                 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );
    132                                 std::string const & parentInstance = instanceName( parentType->name );
    133                                 inits.push_back(
    134                                                 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
    135                         } else if ( std::string( "__cfavir_typeid" ) == field->name ) {
    136                                 std::string const & baseType = baseTypeName( vtableType->name );
    137                                 std::string const & typeId = typeIdName( baseType );
    138                                 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
    139                         } else if ( std::string( "size" ) == field->name ) {
    140                                 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
    141                         } else if ( std::string( "align" ) == field->name ) {
    142                                 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) );
    143                         } else {
    144                                 inits.push_back( new SingleInit( new NameExpr( field->name ) ) );
    145                         }
    146                 }
    147                 init = new ListInit( inits );
    148         // This should initialize everything except the parent pointer, the
    149         // size-of and align-of fields. These should be inserted.
    150         } else {
    151                 assert(false);
    152         }
    153         return makeVtableDeclaration( name, vtableType, init );
    15486}
    15587
     
    224156}
    225157
    226 FunctionDecl * makeGetExceptionForward(
    227                 Type * vtableType, Type * exceptType ) {
    228         assert( vtableType );
    229         assert( exceptType );
    230         FunctionType * type = new FunctionType( noQualifiers, false );
    231         vtableType->tq.is_const = true;
    232         type->returnVals.push_back( new ObjectDecl(
    233                 "_retvalue",
    234                 noStorageClasses,
    235                 LinkageSpec::Cforall,
    236                 nullptr,
    237                 new ReferenceType( noQualifiers, vtableType ),
    238                 nullptr,
    239                 { new Attribute("unused") }
    240         ) );
    241         type->parameters.push_back( new ObjectDecl(
    242                 "__unused",
    243                 noStorageClasses,
    244                 LinkageSpec::Cforall,
    245                 nullptr,
    246                 new PointerType( noQualifiers, exceptType ),
    247                 nullptr,
    248                 { new Attribute("unused") }
    249         ) );
    250         return new FunctionDecl(
    251                 functionName,
    252                 noStorageClasses,
    253                 LinkageSpec::Cforall,
    254                 type,
    255                 nullptr
    256         );
    257 }
    258 
    259158ast::FunctionDecl * makeGetExceptionForward(
    260159                CodeLocation const & location,
     
    284183}
    285184
    286 FunctionDecl * makeGetExceptionFunction(
    287                 ObjectDecl * vtableInstance, Type * exceptType ) {
    288         assert( vtableInstance );
    289         assert( exceptType );
    290         FunctionDecl * func = makeGetExceptionForward(
    291                 vtableInstance->type->clone(), exceptType );
    292         func->statements = new CompoundStmt( {
    293                 new ReturnStmt( new VariableExpr( vtableInstance ) ),
    294         } );
    295         return func;
    296 }
    297 
    298185ast::FunctionDecl * makeGetExceptionFunction(
    299186                CodeLocation const & location,
     
    307194        } );
    308195        return func;
    309 }
    310 
    311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    312         assert( typeIdType );
    313         StructInstType * type = typeIdType->clone();
    314         type->tq.is_const = true;
    315         std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
    316         return new ObjectDecl(
    317                 typeid_name,
    318                 noStorageClasses,
    319                 LinkageSpec::Cforall,
    320                 /* bitfieldWidth */ nullptr,
    321                 type,
    322                 new ListInit( { new SingleInit(
    323                         new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    324                         ) } ),
    325                 { new Attribute( "cfa_linkonce", {} ) },
    326                 noFuncSpecifiers
    327         );
    328196}
    329197
  • src/Virtual/Tables.h

    rdf8ba61a r8d182b1  
    1818#include <string>
    1919#include "AST/Fwd.hpp"
    20 class Declaration;
    21 class Expression;
    22 class FunctionDecl;
    23 class Initializer;
    24 class ObjectDecl;
    25 class StructDecl;
    26 class StructInstType;
    27 class Type;
    2820
    2921namespace Virtual {
     
    3729bool isVTableInstanceName( std::string const & name );
    3830
    39 ObjectDecl * makeVtableForward(
    40         std::string const & name, StructInstType * vtableType );
    4131/* Create a forward declaration of a vtable of the given type.
    4232 * vtableType node is consumed.
     
    4636        ast::StructInstType const * vtableType );
    4737
    48 ObjectDecl * makeVtableInstance(
    49         std::string const & name,
    50         StructInstType * vtableType, Type * objectType,
    51         Initializer * init = nullptr );
    5238/* Create an initialized definition of a vtable.
    5339 * vtableType and init (if provided) nodes are consumed.
     
    6147
    6248// Some special code for how exceptions interact with virtual tables.
    63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType );
     49
    6450/* Create a forward declaration of the exception virtual function
    6551 * linking the vtableType to the exceptType. Both nodes are consumed.
     
    7056        ast::Type const * exceptType );
    7157
    72 FunctionDecl * makeGetExceptionFunction(
    73         ObjectDecl * vtableInstance, Type * exceptType );
    7458/* Create the definition of the exception virtual function.
    7559 * exceptType node is consumed.
     
    7963        ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType );
    8064
    81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
    8265/* Build an instance of the type-id from the type of the type-id.
    8366 * TODO: Should take the parent type. Currently locked to the exception_t.
  • src/main.cc

    rdf8ba61a r8d182b1  
    2929#include <string>                           // for char_traits, operator<<
    3030
    31 #include "AST/Convert.hpp"
    3231#include "AST/Pass.hpp"                     // for pass_visitor_stats
    3332#include "AST/Print.hpp"                    // for printAll
     
    4039#include "CodeGen/Generate.h"               // for generate
    4140#include "CodeGen/LinkOnce.h"               // for translateLinkOnce
    42 #include "CodeTools/TrackLoc.h"             // for fillLocations
    4341#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4442#include "Common/DeclStats.hpp"             // for printDeclStats
     
    6664#include "ResolvExpr/EraseWith.hpp"         // for eraseWith
    6765#include "ResolvExpr/Resolver.h"            // for resolve
    68 #include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    69 #include "SynTree/Declaration.h"            // for Declaration
    7066#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
    7167#include "Validate/Autogen.hpp"             // for autogenerateRoutines
     
    10197                ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
    10298        }
    103         {
    104                 static auto group = build<CounterGroup>( "Syntax Node" );
    105                 auto pass = build<CounterGroup>( name, group );
    106                 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass );
    107         }
    10899}
    109100
     
    259250
    260251        parse_cmdline( argc, argv );                                            // process command-line arguments
    261         CodeGen::FixMain::setReplaceMain( !nomainp );
    262252
    263253        if ( waiting_for_gdb ) {
     
    403393                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
    404394                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
     395                PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );
    405396
    406397                // Needs to happen before tuple types are expanded.
     
    430421
    431422                PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
    432 
    433                 CodeGen::FixMain::fix( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
     423                CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
     424
    434425                if ( output != &cout ) {
    435426                        delete output;
  • tests/concurrency/waitfor/parse.cfa

    rdf8ba61a r8d182b1  
    1010// Created On       : Wed Aug 30 17:53:29 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 22:52:18 2023
    13 // Update Count     : 64
     12// Last Modified On : Wed Nov  1 07:28:19 2023
     13// Update Count     : 65
    1414//
    1515
     
    258258// Local Variables: //
    259259// tab-width: 4 //
    260 // compile-command: "cfa waitfor.cfa" //
     260// compile-command: "cfa parse.cfa" //
    261261// End: //
  • tests/io/.expect/manipulatorsInput.arm64.txt

    rdf8ba61a r8d182b1  
    24243 abcxxx
    25254 aaaaaaaa
    26 5 aaaaaaaa
     265
    27276 aabbccbb
    28287 dddwww
    29 8 dddwww
    30 9 dddwww
     298
     309
    313110 aaaaaaaa
    323211 wwwwwwww
    33 12 wwwwwwww
    34 13 wwwwwwww
     3312
     3413
    353514 cccc
    36 15 q
     3615
    3737a
    3838a
  • tests/io/.expect/manipulatorsInput.x64.txt

    rdf8ba61a r8d182b1  
    24243 abcxxx
    25254 aaaaaaaa
    26 5 aaaaaaaa
     265
    27276 aabbccbb
    28287 dddwww
    29 8 dddwww
    30 9 dddwww
     298
     309
    313110 aaaaaaaa
    323211 wwwwwwww
    33 12 wwwwwwww
    34 13 wwwwwwww
     3312
     3413
    353514 cccc
    36 15 q
     3615
    3737a
    3838a
  • tests/io/.expect/manipulatorsInput.x86.txt

    rdf8ba61a r8d182b1  
    24243 abcxxx
    25254 aaaaaaaa
    26 5 aaaaaaaa
     265
    27276 aabbccbb
    28287 dddwww
    29 8 dddwww
    30 9 dddwww
     298
     309
    313110 aaaaaaaa
    323211 wwwwwwww
    33 12 wwwwwwww
    34 13 wwwwwwww
     3312
     3413
    353514 cccc
    36 15 q
     3615
    3737a
    3838a
Note: See TracChangeset for help on using the changeset viewer.