Changeset 8d182b1
- Timestamp:
- Nov 14, 2023, 12:19:09 PM (23 months ago)
- 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. - Files:
-
- 115 deleted
- 104 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/bibliography/pl.bib
rdf8ba61a r8d182b1 4108 4108 } 4109 4109 4110 @article{Buhr2 2,4110 @article{Buhr23, 4111 4111 contributer = {pabuhr@plg}, 4112 4112 author = {Peter A. Buhr and Colby A. Parsons and Thierry Delisle and He Nan Li}, … … 4114 4114 journal = spe, 4115 4115 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}, 4118 4121 } 4119 4122 … … 4133 4136 journal = spe, 4134 4137 year = 1983, 4138 month = jul, 4135 4139 volume = 13, 4136 4140 number = 7, 4137 4141 pages = {577-596}, 4138 month = jul4139 4142 } 4140 4143 -
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 38 4 \usepackage{xcolor} 39 5 \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} 47 46 48 47 \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, 55 56 breakatwhitespace=false, 56 breaklines=true,57 % breaklines=true, 57 58 captionpos=b, 58 59 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, 62 64 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 77 76 \begin{document} 78 77 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} 90 79 \author{Jiada Liang} 91 80 92 93 %% 94 %% The abstract is a short summary of the work to be presented in the 95 %% article. 81 \maketitle 82 96 83 \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. 84 An enumeration is a type that defines a list of named constant values in C (and other languages). 85 C 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. 98 87 \end{abstract} 99 88 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 title108 %% information and builds the first part of the formatted document.109 \maketitle110 111 89 \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] 113 93 enum Weekday { Monday, Tuesday, Wednesday, Thursday=10, Friday, Saturday, Sunday }; 114 94 \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] 95 The example defines an @enum@ type @Weekday@ with ordered enumerators @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@. 96 The successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@. 97 A C enumeration has an integral type, with consecutive enumerator values assigned by the compiler starting at zero or explicitly initialized by the programmer. 98 For example, @Monday@ to @Wednesday@ have values 0--2, @Thursday@ is set to @10@, and after it, @Friday@ to @Sunday@ have values 11--13. 99 100 There are 3 attributes for an enumeration: position, label, and value: 101 \begin{cquote} 102 \small\sf 103 \begin{tabular}{rccccccccccc} 104 enum Weekday \{ & Monday, & Tuesday, & Wednesday, & Thursday=10, & Friday, & Saturday, & Sunday \}; \\ 105 position & 0 & 1 & 2 & 3 & 4 & 5 & 6 \\ 106 label & Monday & Tuesday & Wednesday & Thursday & Friday & Saturday & Sunday \\ 107 value & 0 & 1 & 2 & 10 & 11 & 12 & 13 108 \end{tabular} 109 \end{cquote} 110 111 The 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 } 117 int j = G; // ERROR! G is not declared in this scope 118 \end{lstlisting} 119 120 \section{\CFA-Style Enum} 121 122 A \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] 125 enum Colour( @char *@ ) { Red = "R", Green = "G", Blue = "B" }; 126 \end{lstlisting} 127 The type of @Colour@ is @char *@ and each enumerator is initialized with a C string. 128 Only 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 135 A \CFA-enum is scoped: enumeration constants are not automatically exposed to the global scope. 136 Enumeration 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] 142 Colour green = Colour.Green; 143 \end{lstlisting} 144 The ~\ref{lst:sample_cforall_enum_usage} example declares a $enumeration\ instance$ named @red@ and initializes it with $enumeration\ constant$ @Color.Red@. 145 An 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} 147 int green_pos = position( green ); // 1 148 char * green_value = value( green ); // "G" 149 char * green_label = label( green ); // "Green" 150 \end{lstlisting} 151 An 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] 153 int green_pos = green; // equivalent to position( green ); 154 \end{lstlisting} 155 A resolution of an enumeration constant is $unambigious$ if only one of the attributes has the resolvable type. 156 In example~\ref{lst:enum_inst_assign_int}, the right-hand side of the assignment expression expects integer type. 157 The position of an enumeration is @int@, while the other two cannot be resolved as integers. 158 The expression unambiguously returns the position of @green@. 159 \begin{lstlisting}[label=lst:enum_inst_assign_string] 160 char * green_value = green; // equivalent to value( green ); 161 \end{lstlisting} 162 On the other hand, the resolution of an enumeration constant is $ambigious$ if multiple attributes have the expected type. 163 In example~\ref{lst:enum_inst_assign_string}, both value and label have the expected type @char *@. 164 When 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] 167 enum(double) Foo { Bar }; 168 int tee = Foo.Bar; // value( Bar ); 169 \end{lstlisting} 170 In 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 172 Although \CFA enumeration captures three different attributes, an instance of enumeration does not occupy extra memory. 173 The @sizeof@ \CFA enumeration instance is always 4 bytes, the same amount of memory to store a C enumeration instance. 174 It comes from the fact that: 175 \begin{enumerate} 176 \item 177 a \CFA enumeration is always statically typed; 178 \item 179 it is always resolved as one of its attributes in terms of real usage. 180 \end{enumerate} 181 When 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. 182 The invocations of $positions()$, $value()$, and $label()$ turn into calls to special functions defined in the prelude: 183 \begin{lstlisting}[label=lst:companion_call] 184 position( green ); 185 >>> position( Colour, 1 ) -> int 186 value( green ); 187 >>> value( Colour, 1 ) -> T 188 label( 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. 192 These 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] 197 forall( 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. 206 A 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. 209 Companions function $value$ and $label$ return the array item at the given position of $values$ and $labels$, respectively. 210 \begin{lstlisting}[label=lst:companion_definition] 211 int position( Companion o, int pos ) { return pos; } 212 T value( Companion o, int pos ) { return o.values[ pos ]; } 213 char * label( Companion o, int pos ) { return o.labels[ pos ]; } 214 \end{lstlisting} 215 Notably, the Companion structure definition, and all companion objects, are visible to the users. 216 A 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] 218 Colour.values; // read the Companion's values 219 values( Colour ); // Same as Colour.values 220 \end{lstlisting} 221 222 \subsection{User Define Enumeration Functions} 223 224 The Companion objects make extending features for \CFA enumeration easy. 225 226 \begin{lstlisting}[label=lst:companion_user_definition] 227 char * charastic_string( Companion o, int position ) { 228 return sprintf("Label: %s; Value: %s", label( o, position ), value( o, position) ); 229 } 230 printf( charactic_string ( Color, 1 ) ); 231 >>> Label: G; Value: G 232 \end{lstlisting} 233 Defining a function takes a Companion object effectively defines functions for all \CFA enumeration. 234 235 The \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. 236 Therefore, a user can use the syntax with a user-defined enumeration function call: 237 \begin{lstlisting}[label=lst:companion_user_definition] 238 charactic_string ( Color.Green ); // equivalent to charactic_string ( Color, 1 ) 239 >>> Label: G; Value: G 240 \end{lstlisting} 241 Similarly, the user can work with the enumeration type itself: (see section ref...) 242 \begin{lstlisting}[ label=lst:companion_user_definition] 243 void print_enumerators ( Companion o ) { 244 for ( c : Companion o ) { 245 sout | label (c) | value( c ) ; 246 } 247 } 248 print_enumerators( Colour ); 249 \end{lstlisting} 250 251 \subsection{Runtime Enumeration} 252 253 The 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 ] 255 const char values[] = { "Hello", "World" }; 256 const char labels[] = { "First", "Second" }; 257 Companion (char *) MyEnum = { .values: values, .labels: labels, .length: 2 }; 258 \end{lstlisting} 259 A runtime enumeration can be used to call enumeration functions. 260 \begin{lstlisting}[ label=lst:runtime_enum_usage ] 261 sout | charatstic_string( MyEnum, 1 ); 262 >>> Label: Second; Value: World 263 \end{lstlisting} 264 However, a runtime enumeration cannot create an enumeration instance, and it does not support enum-qualified syntax. 265 \begin{lstlisting}[ label=lst:runtime_enum_usage ] 266 MyEnum e = MyEnum.First; // Does not work: cannot create an enumeration instance e, 267 // and MyEnum.First is not recognizable 268 \end{lstlisting} 269 During 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 273 A trait is a collection of constraints in \CFA, which can be used to describe types. 274 The \CFA standard library defines traits to categorize types with related enumeration features. 275 276 \subsection{Auto Initializable} 277 \label{s:AutoInitializable} 278 279 TODO: make the initialization rule a separate section. 280 281 If 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. 283 However, not all types can be automatically initialized by \CFA because the meaning of $zero$, $one$, and addition operator may not be well-defined. 284 285 A type is auto-Initializable if it has defined @zero_t@, @one_t@, and an addition operator. 286 \begin{lstlisting} 148 287 forall(T) 149 288 trait 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} 294 An example of user-defined @AutoInitializable@ would look like the following: 295 \begin{lstlisting}[label=lst:sample_auto_Initializable] 296 struct Odd { int i; }; 297 void ?()( Odd & t, zero_t ) { t.i = 1; }; 298 void ?()( Odd & t, one_t ) { t.i = 2; }; 299 Odd ?+?( Odd t1, Odd t2 ) 300 { return Odd( t1.i + t2.i); }; 301 \end{lstlisting} 302 When an enumeration declares an AutoInitializable as its type, no explicit initialization is necessary. 303 \begin{lstlisting}[label=lst:sample_auto_Initializable_usage] 304 enum AutoInitUsage(Odd) { 305 A, B, C = 6, D 306 }; 307 \end{lstlisting} 308 309 In 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. 311 Therefore, the enumeration is initialized as the following: 312 \begin{lstlisting}[label=lst:sample_auto_Initializable_usage_gen] 313 enum AutoInitUsage(Odd) { 314 A=1, B=3, C = 6, D=8 315 }; 316 \end{lstlisting} 317 In \CFA, integral types, float types, and imaginary numbers are example types that are AutoInitialiable. 318 \begin{lstlisting}[label=lst:letter] 319 enum 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 }; 325 print( "%c, %c, %c", Alphabet.F, Alphabet.o, Alphabet.o ); 326 >>> F, o, o 327 \end{lstlisting} 248 328 249 329 \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 331 It is convenient to iterate over a \CFA enumeration. 332 Here is the basic usage: 333 \begin{lstlisting}[label=lst:range_functions] 334 for ( Alphabet ah; Alphabet; ) { 335 printf( "%d ", ah ); 336 } 337 >>> A B C (...omit the rest) 338 \end{lstlisting} 339 The for-loop uses the enumeration type @Alphabet@ as range. 340 When 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] 345 for ( Alphabet ch ) { 346 printf( "%d ", ch ); 347 } 348 >>> A B C (...omit the rest) 349 \end{lstlisting} 350 351 Enumeration supports the \CFA loop control syntax for for-loop. 352 \begin{lstlisting}[label=lst:range_functions] 353 for ( Alphabet.D ) 354 for ( ch; Alphabet.g ~ Alphabet.z ) 355 for ( Alphabet ch; Alphabet.R ~ Alphabet.X ~ 2 ) 356 \end{lstlisting} 357 Notably, the meaning of "step" of iteration has changed for enumeration. 358 Consider the following example: 359 \begin{lstlisting}[label=lst:range_functions] 360 enum(int) Sequence { 361 A = 10, B = 12, C = 14; 362 } 363 for ( s; Sequence.A ~ Sequence.C ) { 364 printf( "%d ", s ); 365 } 366 367 >>> 10 12 14 368 369 for ( s; Sequence.A ~ Sequence.A ~ 2 ) { 370 printf( "%d ", s ); 371 } 372 >>> 10 14 373 \end{lstlisting} 374 The range iteration of enumeration does not return the @current_value++@ until it reaches the upper bound. 375 The semantics is to return the next enumeration constant. 376 If a stepping is specified, 2 for example, it returns the 2 enumeration constant after the current one, rather than the @current+2@. 377 378 It is also possible to iterate over an enumeration's labels, implicitly or explicitly: 379 \begin{lstlisting}[label=lst:range_functions_label_implicit] 380 for ( char * ch; Alphabet ) 381 \end{lstlisting} 382 This 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. 383 If 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] 385 for ( char * ch; labels( Alphabet ) ) 260 386 \end{lstlisting} 261 387 262 388 \section{Implementation} 263 389 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 394 The qualified enumeration syntax is dedicated to \CFA enumeration. 395 \begin{lstlisting}[label=lst:range_functions] 396 enum (type_declaration) name { enumerator = const_expr, enumerator = const_expr, ... } 397 \end{lstlisting} 398 A compiler stores the name, the underlying type, and all enumerators in an @enumeration table@. 399 During the $Validation$ pass, the compiler links the type declaration to the type's definition. 400 It 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. 401 If the declared type is not @Auto Initializable@, \CFA rejects the enumeration definition. 402 Otherwise, 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] 405 struct T { ... }; 406 void ?{}( T & t, zero_t ) { ... }; 407 void ?{}( T & t, one_t ) { ... }; 408 T ?+?( T & lhs, T & rhs ) { ... }; 409 410 enum (T) Sample { 411 Zero: 0 /* zero_t */, 412 One: Zero + 1 /* ?+?( Zero, one_t ) */ , ... 413 }; 414 \end{lstlisting} 415 Challenge: \\ 416 The value of an enumerator, or the initializer, requires @const_expr@. 417 While 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. 418 Might 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] 422 Companion( 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. 429 But 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] 435 aggregation_name.field; 436 \end{lstlisting} 437 The qualified expression is not dedicated to \CFA enumeration. 438 It is a feature that is supported by other aggregation in \CFA as well, including a C enumeration. 439 When 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. 441 If 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 447 Instead 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] 454 enum Sample s1; 455 Sample s2; 456 \end{lstlisting} 457 A declaration of \CFA enumeration instance that has no difference than a C enumeration or other \CFA aggregation. 458 The compiler recognizes the type of a variable declaration by searching the name in all possible types. 459 The @enum@ keyword is not necessary but helps to disambiguate types (questionable). 460 The generated code for a \CFA enumeration declaration is utterly an integer, which is meant to store the position. 461 \begin{lstlisting}[label=lst:declaration] 462 int s1; 463 int s2; 464 \end{lstlisting} 465 466 \subsection{Compiler Representation} 467 468 \emph{Work in Progress} 469 470 The internal representation of an enumeration constant is @EnumInstType@. 471 The 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] 473 class 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} 484 enum Colour( char * ) { Red = "R", Green = "G", Blue = "B" }; 485 \end{lstlisting} 486 The @EnumInstType@ is convertible to other types. 487 A \CFA enumeration expression is implicitly \emph{overloaded} with its three different attributes: value, position, and label. 488 The \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} 495 In example~\ref{lst:null_context}, the environment gives no information to help with the resolution of @Colour.Green@. 496 In this case, any of the attributes is resolvable. 497 According to the \textit{precedence rule}, the expression with @EnumInstType@ resolves as @value( Colour.Green )@. 498 The @EnumInstType@ is converted to the type of the value, which is statically known to the compiler as @char *@. 499 When 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} 510 The assignment expression gives a context for the EnumInstType resolution. 511 The EnumInstType is used as an @int@, and \CFA needs to determine which of the attributes can be resolved as an @int@ type. 512 The functions $Unify( T1, T2 ): bool$ take two types as parameters and determine if one type can be used as another. 513 In 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} 532 After 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. 542 Backward 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} 561 Steps: 562 \begin{enumerate} 563 \item 564 identify @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 568 return 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} 576 Steps: 577 \begin{enumerate} 578 \item 579 identify @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 583 return the FIRST enumeration constant that has the value 1, by searching through the values array 584 \end{enumerate} 585 The 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 309 586 310 587 \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 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Oct 19 21:10:10202313 // Update Count : 180 112 // Last Modified On : Sat Nov 11 07:06:27 2023 13 // Update Count : 1803 14 14 // 15 15 … … 1001 1001 } // if 1002 1002 } // 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 1003 1005 } else { 1004 1006 if ( f.flags.delimiter ) { // getline … … 1041 1043 } // if 1042 1044 } // if 1045 if ( rwd > 0 && args == 0 ) f.s[0]= '\0'; // read failed => no pattern match => set string to null 1043 1046 } // if 1044 1047 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF -
src/AST/Decl.cpp
rdf8ba61a r8d182b1 20 20 #include <unordered_map> 21 21 22 #include "CodeGen/FixMain.h" // for FixMain23 22 #include "Common/Eval.h" // for eval 24 23 … … 76 75 } 77 76 this->type = ftype; 78 // Hack forcing the function "main" to have Cforall linkage to replace79 // main even if it is inside an extern "C", and also makes sure the80 // replacing function is always a C function.81 if ( name == "main" ) {82 this->linkage = CodeGen::FixMain::getMainLinkage();83 }84 77 } 85 78 … … 108 101 } 109 102 this->type = type; 110 // See note above about this hack.111 if ( name == "main" ) {112 this->linkage = CodeGen::FixMain::getMainLinkage();113 }114 103 } 115 104 -
src/AST/SymbolTable.cpp
rdf8ba61a r8d182b1 39 39 static inline auto stats() { 40 40 using namespace Stats::Counters; 41 static auto group = build<CounterGroup>(" Indexers");41 static auto group = build<CounterGroup>("Symbol Tables"); 42 42 static struct { 43 43 SimpleCounter * count; -
src/AST/SymbolTable.hpp
rdf8ba61a r8d182b1 88 88 using Ptr = std::shared_ptr<const SymbolTable>; 89 89 90 Ptr prevScope; ///< Indexerfor parent scope90 Ptr prevScope; ///< Symbol Table for parent scope 91 91 unsigned long scope; ///< Scope index of this indexer 92 92 unsigned long repScope; ///< Scope index of currently represented scope -
src/AST/Type.hpp
rdf8ba61a r8d182b1 34 34 35 35 namespace ast { 36 37 template< typename T > class Pass;38 36 39 37 class Type : public Node { -
src/AST/module.mk
rdf8ba61a r8d182b1 20 20 AST/Bitfield.hpp \ 21 21 AST/Chain.hpp \ 22 AST/Convert.cpp \23 AST/Convert.hpp \24 22 AST/Copy.cpp \ 25 23 AST/Copy.hpp \ -
src/BasicTypes-gen.cc
rdf8ba61a r8d182b1 272 272 size_t start, end; 273 273 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 newline280 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 } // for287 code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;288 code << "\t} kind;" << endl;289 code << "\t"; // indentation for end marker290 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 newline303 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 } // for310 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 OVER320 274 #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp" 321 275 resetInput( file, TypeH_AST, buffer, code, str ); -
src/CodeGen/CodeGeneratorNew.cpp
rdf8ba61a r8d182b1 24 24 namespace CodeGen { 25 25 26 int CodeGenerator _new::tabsize = 4;26 int CodeGenerator::tabsize = 4; 27 27 28 28 // The kinds of statements that should be followed by whitespace. … … 35 35 } 36 36 37 void CodeGenerator _new::extension( ast::Expr const * expr ) {37 void CodeGenerator::extension( ast::Expr const * expr ) { 38 38 if ( expr->extension ) output << "__extension__ "; 39 39 } 40 40 41 void CodeGenerator _new::extension( ast::Decl const * decl ) {41 void CodeGenerator::extension( ast::Decl const * decl ) { 42 42 if ( decl->extension ) output << "__extension__ "; 43 43 } 44 44 45 void CodeGenerator _new::asmName( ast::DeclWithType const * decl ) {45 void CodeGenerator::asmName( ast::DeclWithType const * decl ) { 46 46 if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) { 47 47 output << " asm ( " << asmName->rep << " )"; … … 49 49 } 50 50 51 CodeGenerator _new::LabelPrinter & CodeGenerator_new::LabelPrinter::operator()(51 CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()( 52 52 std::vector<ast::Label> const & l ) { 53 53 labels = &l; … … 55 55 } 56 56 57 std::ostream & CodeGenerator _new::LabelPrinter::operator()( std::ostream & output ) const {57 std::ostream & CodeGenerator::LabelPrinter::operator()( std::ostream & output ) const { 58 58 const std::vector<ast::Label> & labels = *this->labels; 59 59 for ( const ast::Label & label : labels ) { … … 66 66 // Using updateLocation at the beginning of a node and endl within a node 67 67 // should become the method of formating. 68 void CodeGenerator _new::updateLocation( CodeLocation const & to ) {68 void CodeGenerator::updateLocation( CodeLocation const & to ) { 69 69 // Skip if linemarks shouldn't appear or if location is unset. 70 70 if ( !options.lineMarks || to.isUnset() ) return; … … 86 86 } 87 87 88 void CodeGenerator _new::updateLocation( ast::ParseNode const * to ) {88 void CodeGenerator::updateLocation( ast::ParseNode const * to ) { 89 89 updateLocation( to->location ); 90 90 } 91 91 92 std::ostream & CodeGenerator _new::LineEnder::operator()( std::ostream & os ) const {92 std::ostream & CodeGenerator::LineEnder::operator()( std::ostream & os ) const { 93 93 os << "\n" << std::flush; 94 94 cg.currentLocation.first_line++; … … 96 96 } 97 97 98 CodeGenerator _new::CodeGenerator_new( std::ostream & os, const Options & options ) :99 indent( 0, CodeGenerator _new::tabsize ), output( os ),98 CodeGenerator::CodeGenerator( std::ostream & os, const Options & options ) : 99 indent( 0, CodeGenerator::tabsize ), output( os ), 100 100 options( options ), printLabels( *this ), endl( *this ) 101 101 {} 102 102 103 std::string CodeGenerator _new::mangleName( ast::DeclWithType const * decl ) {103 std::string CodeGenerator::mangleName( ast::DeclWithType const * decl ) { 104 104 // GCC builtins should always be printed unmangled. 105 105 if ( options.pretty || decl->linkage.is_gcc_builtin ) { … … 112 112 } 113 113 114 void CodeGenerator _new::genAttributes(114 void CodeGenerator::genAttributes( 115 115 const std::vector<ast::ptr<ast::Attribute>> & attributes ) { 116 116 if ( attributes.empty() ) return; … … 129 129 } 130 130 131 void CodeGenerator _new::previsit( ast::Node const * ) {131 void CodeGenerator::previsit( ast::Node const * ) { 132 132 // All traversal is manual. 133 133 // TODO: Which means the ast::Pass is just providing a default no visit? … … 135 135 } 136 136 137 void CodeGenerator _new::previsit( ast::ParseNode const * node ) {137 void CodeGenerator::previsit( ast::ParseNode const * node ) { 138 138 previsit( (ast::Node const *)node ); 139 139 updateLocation( node ); 140 140 } 141 141 142 void CodeGenerator _new::postvisit( ast::Node const * node ) {142 void CodeGenerator::postvisit( ast::Node const * node ) { 143 143 std::stringstream ss; 144 144 ast::print( ss, node ); … … 146 146 } 147 147 148 void CodeGenerator _new::previsit( ast::Expr const * expr ) {148 void CodeGenerator::previsit( ast::Expr const * expr ) { 149 149 previsit( (ast::ParseNode const *)expr ); 150 150 GuardAction( [this, expr](){ … … 155 155 } 156 156 157 void CodeGenerator _new::postvisit( ast::FunctionDecl const * decl ) {157 void CodeGenerator::postvisit( ast::FunctionDecl const * decl ) { 158 158 // Deleted decls should never be used, so don't print them in C. 159 159 if ( decl->isDeleted && options.genC ) return; … … 168 168 169 169 std::ostringstream acc; 170 ast::Pass<CodeGenerator _new> subCG( acc, subOptions );170 ast::Pass<CodeGenerator> subCG( acc, subOptions ); 171 171 // Add the forall clause. 172 172 // TODO: These probably should be removed by now and the assert used. … … 213 213 } 214 214 215 //void CodeGenerator_new::postvisit( ast::ObjectDecl const * decl_ ) { 216 ast::ObjectDecl const * CodeGenerator_new::postvisit( 215 ast::ObjectDecl const * CodeGenerator::postvisit( 217 216 ast::ObjectDecl const * decl ) { 218 217 // Deleted decls should never be used, so don't print them in C. … … 262 261 } 263 262 264 void CodeGenerator _new::handleStorageClass( ast::DeclWithType const * decl ) {263 void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) { 265 264 if ( decl->storage.any() ) { 266 265 ast::print( output, decl->storage ); … … 268 267 } 269 268 270 void CodeGenerator _new::handleAggregate(269 void CodeGenerator::handleAggregate( 271 270 ast::AggregateDecl const * decl, std::string const & kind ) { 272 271 if ( !decl->params.empty() && !options.genC ) { … … 296 295 } 297 296 298 void CodeGenerator _new::postvisit( ast::StructDecl const * decl ) {297 void CodeGenerator::postvisit( ast::StructDecl const * decl ) { 299 298 extension( decl ); 300 299 handleAggregate( decl, "struct " ); 301 300 } 302 301 303 void CodeGenerator _new::postvisit( ast::UnionDecl const * decl ) {302 void CodeGenerator::postvisit( ast::UnionDecl const * decl ) { 304 303 extension( decl ); 305 304 handleAggregate( decl, "union " ); … … 332 331 } 333 332 334 void CodeGenerator _new::postvisit( ast::EnumDecl const * decl ) {333 void CodeGenerator::postvisit( ast::EnumDecl const * decl ) { 335 334 extension( decl ); 336 335 auto members = decl->members; … … 370 369 } 371 370 372 void CodeGenerator _new::postvisit( ast::TraitDecl const * decl ) {371 void CodeGenerator::postvisit( ast::TraitDecl const * decl ) { 373 372 assertf( !options.genC, "TraitDecls should not reach code generation." ); 374 373 extension( decl ); … … 376 375 } 377 376 378 void CodeGenerator _new::postvisit( ast::TypedefDecl const * decl ) {377 void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) { 379 378 assertf( !options.genC, "Typedefs should not reach code generation." ); 380 379 output << "typedef " << genType( decl->base, decl->name, options ) << endl; 381 380 } 382 381 383 void CodeGenerator _new::postvisit( ast::TypeDecl const * decl ) {382 void CodeGenerator::postvisit( ast::TypeDecl const * decl ) { 384 383 assertf( !options.genC, "TypeDecls should not reach code generation." ); 385 384 output << decl->genTypeString() << " " << decl->name; … … 397 396 } 398 397 399 void CodeGenerator _new::postvisit( ast::StaticAssertDecl const * decl ) {398 void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) { 400 399 output << "_Static_assert("; 401 400 decl->cond->accept( *visitor ); … … 405 404 } 406 405 407 void CodeGenerator _new::postvisit( ast::Designation const * designation ) {406 void CodeGenerator::postvisit( ast::Designation const * designation ) { 408 407 auto designators = designation->designators; 409 408 if ( 0 == designators.size() ) return; … … 423 422 } 424 423 425 void CodeGenerator _new::postvisit( ast::SingleInit const * init ) {424 void CodeGenerator::postvisit( ast::SingleInit const * init ) { 426 425 init->value->accept( *visitor ); 427 426 } 428 427 429 void CodeGenerator _new::postvisit( ast::ListInit const * init ) {428 void CodeGenerator::postvisit( ast::ListInit const * init ) { 430 429 auto initBegin = init->initializers.begin(); 431 430 auto initEnd = init->initializers.end(); … … 446 445 } 447 446 448 void CodeGenerator _new::postvisit( ast::ConstructorInit const * init ) {447 void CodeGenerator::postvisit( ast::ConstructorInit const * init ) { 449 448 assertf( !options.genC, "ConstructorInit nodes should not reach code generation." ); 450 449 // This isn't actual code, but labels the constructor/destructor pairs. … … 456 455 } 457 456 458 void CodeGenerator _new::postvisit( ast::ApplicationExpr const * expr ) {457 void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) { 459 458 extension( expr ); 460 459 if ( auto var = expr->func.as<ast::VariableExpr>() ) { … … 550 549 } 551 550 552 void CodeGenerator _new::postvisit( ast::UntypedExpr const * expr ) {551 void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) { 553 552 extension( expr ); 554 553 if ( auto name = expr->func.as<ast::NameExpr>() ) { … … 638 637 } 639 638 640 void CodeGenerator _new::postvisit( ast::RangeExpr const * expr ) {639 void CodeGenerator::postvisit( ast::RangeExpr const * expr ) { 641 640 expr->low->accept( *visitor ); 642 641 output << " ... "; … … 644 643 } 645 644 646 void CodeGenerator _new::postvisit( ast::NameExpr const * expr ) {645 void CodeGenerator::postvisit( ast::NameExpr const * expr ) { 647 646 extension( expr ); 648 647 if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) { … … 657 656 } 658 657 659 void CodeGenerator _new::postvisit( ast::DimensionExpr const * expr ) {658 void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) { 660 659 extension( expr ); 661 660 output << "/*non-type*/" << expr->name; 662 661 } 663 662 664 void CodeGenerator _new::postvisit( ast::AddressExpr const * expr ) {663 void CodeGenerator::postvisit( ast::AddressExpr const * expr ) { 665 664 extension( expr ); 666 665 output << "(&"; … … 669 668 } 670 669 671 void CodeGenerator _new::postvisit( ast::LabelAddressExpr const * expr ) {670 void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) { 672 671 extension( expr ); 673 672 output << "(&&" << expr->arg << ")"; 674 673 } 675 674 676 void CodeGenerator _new::postvisit( ast::CastExpr const * expr ) {675 void CodeGenerator::postvisit( ast::CastExpr const * expr ) { 677 676 extension( expr ); 678 677 output << "("; … … 688 687 } 689 688 690 void CodeGenerator _new::postvisit( ast::KeywordCastExpr const * expr ) {689 void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) { 691 690 assertf( !options.genC, "KeywordCastExpr should not reach code generation." ); 692 691 extension( expr ); … … 696 695 } 697 696 698 void CodeGenerator _new::postvisit( ast::VirtualCastExpr const * expr ) {697 void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) { 699 698 assertf( !options.genC, "VirtualCastExpr should not reach code generation." ); 700 699 extension( expr ); … … 705 704 } 706 705 707 void CodeGenerator _new::postvisit( ast::UntypedMemberExpr const * expr ) {706 void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) { 708 707 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." ); 709 708 extension( expr ); … … 713 712 } 714 713 715 void CodeGenerator _new::postvisit( ast::MemberExpr const * expr ) {714 void CodeGenerator::postvisit( ast::MemberExpr const * expr ) { 716 715 extension( expr ); 717 716 expr->aggregate->accept( *visitor ); … … 719 718 } 720 719 721 void CodeGenerator _new::postvisit( ast::VariableExpr const * expr ) {720 void CodeGenerator::postvisit( ast::VariableExpr const * expr ) { 722 721 extension( expr ); 723 722 const OperatorInfo * opInfo; … … 733 732 } 734 733 735 void CodeGenerator _new::postvisit( ast::ConstantExpr const * expr ) {734 void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) { 736 735 extension( expr ); 737 736 output << expr->rep; 738 737 } 739 738 740 void CodeGenerator _new::postvisit( ast::SizeofExpr const * expr ) {739 void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) { 741 740 extension( expr ); 742 741 output << "sizeof("; … … 749 748 } 750 749 751 void CodeGenerator _new::postvisit( ast::AlignofExpr const * expr ) {750 void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) { 752 751 // Using the GCC extension to avoid changing the std to C11. 753 752 extension( expr ); … … 761 760 } 762 761 763 void CodeGenerator _new::postvisit( ast::UntypedOffsetofExpr const * expr ) {762 void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) { 764 763 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." ); 765 764 output << "offsetof("; … … 769 768 } 770 769 771 void CodeGenerator _new::postvisit( ast::OffsetofExpr const * expr ) {770 void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) { 772 771 // Use GCC builtin 773 772 output << "__builtin_offsetof("; … … 777 776 } 778 777 779 void CodeGenerator _new::postvisit( ast::OffsetPackExpr const * expr ) {778 void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) { 780 779 assertf( !options.genC, "OffsetPackExpr should not reach code generation." ); 781 780 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")"; 782 781 } 783 782 784 void CodeGenerator _new::postvisit( ast::LogicalExpr const * expr ) {783 void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) { 785 784 extension( expr ); 786 785 output << "("; … … 791 790 } 792 791 793 void CodeGenerator _new::postvisit( ast::ConditionalExpr const * expr ) {792 void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) { 794 793 extension( expr ); 795 794 output << "("; … … 802 801 } 803 802 804 void CodeGenerator _new::postvisit( ast::CommaExpr const * expr ) {803 void CodeGenerator::postvisit( ast::CommaExpr const * expr ) { 805 804 extension( expr ); 806 805 output << "("; … … 818 817 } 819 818 820 void CodeGenerator _new::postvisit( ast::TupleAssignExpr const * expr ) {819 void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) { 821 820 assertf( !options.genC, "TupleAssignExpr should not reach code generation." ); 822 821 expr->stmtExpr->accept( *visitor ); 823 822 } 824 823 825 void CodeGenerator _new::postvisit( ast::UntypedTupleExpr const * expr ) {824 void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) { 826 825 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." ); 827 826 extension( expr ); … … 831 830 } 832 831 833 void CodeGenerator _new::postvisit( ast::TupleExpr const * expr ) {832 void CodeGenerator::postvisit( ast::TupleExpr const * expr ) { 834 833 assertf( !options.genC, "TupleExpr should not reach code generation." ); 835 834 extension( expr ); … … 839 838 } 840 839 841 void CodeGenerator _new::postvisit( ast::TupleIndexExpr const * expr ) {840 void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) { 842 841 assertf( !options.genC, "TupleIndexExpr should not reach code generation." ); 843 842 extension( expr ); … … 846 845 } 847 846 848 void CodeGenerator _new::postvisit( ast::TypeExpr const * expr ) {847 void CodeGenerator::postvisit( ast::TypeExpr const * expr ) { 849 848 // TODO: Should there be an assertion there? 850 849 if ( !options.genC ) { … … 853 852 } 854 853 855 void CodeGenerator _new::postvisit( ast::AsmExpr const * expr ) {854 void CodeGenerator::postvisit( ast::AsmExpr const * expr ) { 856 855 if ( !expr->inout.empty() ) { 857 856 output << "[ " << expr->inout << " ] "; … … 863 862 } 864 863 865 void CodeGenerator _new::postvisit( ast::CompoundLiteralExpr const * expr ) {864 void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) { 866 865 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) ); 867 866 assert( expr->result && expr->init.as<ast::ListInit>() ); … … 870 869 } 871 870 872 void CodeGenerator _new::postvisit( ast::UniqueExpr const * expr ) {871 void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) { 873 872 assertf( !options.genC, "UniqueExpr should not reach code generation." ); 874 873 output << "unq<" << expr->id << ">{ "; … … 877 876 } 878 877 879 void CodeGenerator _new::postvisit( ast::StmtExpr const * expr ) {878 void CodeGenerator::postvisit( ast::StmtExpr const * expr ) { 880 879 auto stmts = expr->stmts->kids; 881 880 output << "({" << endl; … … 905 904 } 906 905 907 void CodeGenerator _new::postvisit( ast::ConstructorExpr const * expr ) {906 void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) { 908 907 assertf( !options.genC, "ConstructorExpr should not reach code generation." ); 909 908 expr->callExpr->accept( *visitor ); 910 909 } 911 910 912 void CodeGenerator _new::postvisit( ast::DeletedExpr const * expr ) {911 void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) { 913 912 assertf( !options.genC, "DeletedExpr should not reach code generation." ); 914 913 expr->expr->accept( *visitor ); 915 914 } 916 915 917 void CodeGenerator _new::postvisit( ast::DefaultArgExpr const * expr ) {916 void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) { 918 917 assertf( !options.genC, "DefaultArgExpr should not reach code generation." ); 919 918 expr->expr->accept( *visitor ); 920 919 } 921 920 922 void CodeGenerator _new::postvisit( ast::GenericExpr const * expr ) {921 void CodeGenerator::postvisit( ast::GenericExpr const * expr ) { 923 922 assertf( !options.genC, "GenericExpr should not reach code generation." ); 924 923 output << "_Generic("; … … 940 939 } 941 940 942 void CodeGenerator _new::postvisit( ast::CompoundStmt const * stmt ) {941 void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) { 943 942 output << "{" << endl; 944 943 … … 955 954 } 956 955 957 void CodeGenerator _new::postvisit( ast::ExprStmt const * stmt ) {956 void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) { 958 957 assert( stmt ); 959 958 // Cast the top-level expression to void to reduce gcc warnings. … … 967 966 } 968 967 969 void CodeGenerator _new::postvisit( ast::AsmStmt const * stmt ) {968 void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) { 970 969 output << "asm "; 971 970 if ( stmt->isVolatile ) output << "volatile "; … … 991 990 } 992 991 993 void CodeGenerator _new::postvisit( ast::AsmDecl const * decl ) {992 void CodeGenerator::postvisit( ast::AsmDecl const * decl ) { 994 993 output << "asm "; 995 994 ast::AsmStmt const * stmt = decl->stmt; … … 999 998 } 1000 999 1001 void CodeGenerator _new::postvisit( ast::DirectiveDecl const * decl ) {1000 void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) { 1002 1001 // endl prevents spaces before the directive. 1003 1002 output << endl << decl->stmt->directive; 1004 1003 } 1005 1004 1006 void CodeGenerator _new::postvisit( ast::DirectiveStmt const * stmt ) {1005 void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) { 1007 1006 // endl prevents spaces before the directive. 1008 1007 output << endl << stmt->directive; 1009 1008 } 1010 1009 1011 void CodeGenerator _new::postvisit( ast::IfStmt const * stmt ) {1010 void CodeGenerator::postvisit( ast::IfStmt const * stmt ) { 1012 1011 output << "if ( "; 1013 1012 stmt->cond->accept( *visitor ); … … 1022 1021 } 1023 1022 1024 void CodeGenerator _new::postvisit( ast::SwitchStmt const * stmt ) {1023 void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) { 1025 1024 output << "switch ( "; 1026 1025 stmt->cond->accept( *visitor ); … … 1036 1035 } 1037 1036 1038 void CodeGenerator _new::postvisit( ast::CaseClause const * clause ) {1037 void CodeGenerator::postvisit( ast::CaseClause const * clause ) { 1039 1038 updateLocation( clause ); 1040 1039 output << indent; … … 1056 1055 } 1057 1056 1058 void CodeGenerator _new::postvisit( ast::BranchStmt const * stmt ) {1057 void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) { 1059 1058 switch ( stmt->kind ) { 1060 1059 case ast::BranchStmt::Goto: … … 1091 1090 } 1092 1091 1093 void CodeGenerator _new::postvisit( ast::ReturnStmt const * stmt ) {1092 void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) { 1094 1093 output << "return "; 1095 1094 if ( stmt->expr ) stmt->expr->accept( *visitor ); … … 1097 1096 } 1098 1097 1099 void CodeGenerator _new::postvisit( ast::ThrowStmt const * stmt ) {1098 void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) { 1100 1099 assertf( !options.genC, "ThrowStmt should not reach code generation." ); 1101 1100 … … 1112 1111 } 1113 1112 1114 void CodeGenerator _new::postvisit( ast::CatchClause const * stmt ) {1113 void CodeGenerator::postvisit( ast::CatchClause const * stmt ) { 1115 1114 assertf( !options.genC, "CatchClause should not reach code generation." ); 1116 1115 … … 1126 1125 } 1127 1126 1128 void CodeGenerator _new::postvisit( ast::WaitForStmt const * stmt ) {1127 void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) { 1129 1128 assertf( !options.genC, "WaitforStmt should not reach code generation." ); 1130 1129 … … 1172 1171 } 1173 1172 1174 void CodeGenerator _new::postvisit( ast::WithStmt const * stmt ) {1173 void CodeGenerator::postvisit( ast::WithStmt const * stmt ) { 1175 1174 assertf( !options.genC, "WithStmt should not reach code generation." ); 1176 1175 … … 1181 1180 } 1182 1181 1183 void CodeGenerator _new::postvisit( ast::WhileDoStmt const * stmt ) {1182 void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) { 1184 1183 if ( stmt->isDoWhile ) { 1185 1184 output << "do"; … … 1191 1190 output << " "; 1192 1191 1193 output << CodeGenerator _new::printLabels( stmt->body->labels );1192 output << CodeGenerator::printLabels( stmt->body->labels ); 1194 1193 stmt->body->accept( *visitor ); 1195 1194 … … 1203 1202 } 1204 1203 1205 void CodeGenerator _new::postvisit( ast::ForStmt const * stmt ) {1204 void CodeGenerator::postvisit( ast::ForStmt const * stmt ) { 1206 1205 // Initializer is always hoised so don't generate it. 1207 1206 // TODO: Do an assertion check? … … 1226 1225 } 1227 1226 1228 void CodeGenerator _new::postvisit( ast::NullStmt const * ) {1227 void CodeGenerator::postvisit( ast::NullStmt const * ) { 1229 1228 output << "/* null statement */ ;"; 1230 1229 } 1231 1230 1232 void CodeGenerator _new::postvisit( ast::DeclStmt const * stmt ) {1231 void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) { 1233 1232 stmt->decl->accept( *visitor ); 1234 1233 … … 1236 1235 } 1237 1236 1238 void CodeGenerator _new::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {1237 void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) { 1239 1238 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." ); 1240 1239 stmt->callStmt->accept( *visitor ); 1241 1240 } 1242 1241 1243 void CodeGenerator _new::postvisit( ast::MutexStmt const * stmt ) {1242 void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) { 1244 1243 assertf( !options.genC, "MutexStmt should not reach code generation." ); 1245 1244 // TODO: But this isn't what a mutex statement looks like. -
src/CodeGen/CodeGeneratorNew.hpp
rdf8ba61a r8d182b1 25 25 namespace CodeGen { 26 26 27 #warning Remove the _new when old version is removed. 28 struct CodeGenerator_new : 27 struct CodeGenerator final : 29 28 public ast::WithGuards, 30 29 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 ); 33 32 34 33 // Turn off visit_children for all nodes. … … 119 118 /// Custom local implementation of endl that updates print location. 120 119 struct LineEnder { 121 CodeGenerator _new& cg;122 LineEnder( CodeGenerator _new& cg ) : cg( cg ) {}120 CodeGenerator & cg; 121 LineEnder( CodeGenerator & cg ) : cg( cg ) {} 123 122 std::ostream & operator()( std::ostream & ) const; 124 123 }; … … 129 128 /// Wrapper class to help print vectors of Labels. 130 129 struct LabelPrinter { 131 LabelPrinter( CodeGenerator _new& cg ) : cg( cg ), labels( nullptr ) {}130 LabelPrinter( CodeGenerator & cg ) : cg( cg ), labels( nullptr ) {} 132 131 LabelPrinter & operator()( std::vector<ast::Label> const & l ); 133 132 std::ostream & operator()( std::ostream & ) const; 134 CodeGenerator _new& cg;133 CodeGenerator & cg; 135 134 std::vector<ast::Label> const * labels; 136 135 }; -
src/CodeGen/FixMain.cc
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.cc -- 7 // FixMain.cc -- Tools to change a Cforall main into a C main. 8 8 // 9 9 // Author : Thierry Delisle … … 25 25 #include "AST/Type.hpp" 26 26 #include "AST/Vector.hpp" 27 #include "Common/PassVisitor.h"28 27 #include "Common/SemanticError.h" // for SemanticError 29 28 #include "CodeGen/GenType.h" // for GenType 30 #include "SynTree/Declaration.h" // for FunctionDecl, operator<<31 #include "SynTree/Type.h" // for FunctionType32 29 #include "SymTab/Mangler.h" 33 30 … … 36 33 namespace { 37 34 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 { 35 struct FindMainCore final { 52 36 ast::FunctionDecl const * main_declaration = nullptr; 53 37 54 38 void previsit( ast::FunctionDecl const * decl ) { 55 if ( FixMain::isMain( decl ) ) {39 if ( isMain( decl ) ) { 56 40 if ( main_declaration ) { 57 41 SemanticError( decl, "Multiple definition of main routine\n" ); … … 65 49 return genType( types[at], "", Options( false, false, false, false ) ); 66 50 } 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 {102 51 103 52 ast::ObjectDecl * makeIntObj(){ … … 157 106 } 158 107 108 struct 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 159 118 } // namespace 160 119 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 ) { 120 bool isMain( const ast::FunctionDecl * decl ) { 169 121 if ( std::string("main") != decl->name ) { 170 122 return false; … … 173 125 } 174 126 175 void FixMain::fix( ast::TranslationUnit & translationUnit, 127 void 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 134 void fixMainInvoke( ast::TranslationUnit & translationUnit, 176 135 std::ostream &os, const char * bootloader_filename ) { 177 136 178 ast::Pass<FindMainCore _new> main_finder;137 ast::Pass<FindMainCore> main_finder; 179 138 ast::accept_all( translationUnit, main_finder ); 180 139 if ( nullptr == main_finder.core.main_declaration ) return; -
src/CodeGen/FixMain.h
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.h -- 7 // FixMain.h -- Tools to change a Cforall main into a C main. 8 8 // 9 9 // Author : Thierry Delisle … … 17 17 18 18 #include <iosfwd> 19 #include <memory>20 #include <list>21 19 22 #include "AST/LinkageSpec.hpp"23 #include "SynTree/LinkageSpec.h"24 25 class Declaration;26 class FunctionDecl;27 20 namespace ast { 28 21 class FunctionDecl; … … 32 25 namespace CodeGen { 33 26 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? 28 bool isMain( const ast::FunctionDecl * decl ); 42 29 43 static inline void setReplaceMain(bool val) { 44 replace_main = val; 45 } 30 /// Adjust the linkage of main functions. 31 void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain ); 46 32 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. 34 void fixMainInvoke( ast::TranslationUnit & transUnit, 35 std::ostream & os, const char * bootloaderFilename ); 58 36 59 37 } // namespace CodeGen -
src/CodeGen/FixNames.cc
rdf8ba61a r8d182b1 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h"25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "FixMain.h" // for FixMain 27 26 #include "SymTab/Mangler.h" // for Mangler 28 #include "SynTree/LinkageSpec.h" // for Cforall, isMangled29 #include "SynTree/Constant.h" // for Constant30 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarat...31 #include "SynTree/Expression.h" // for ConstantExpr32 #include "SynTree/Label.h" // for Label, noLabels33 #include "SynTree/Statement.h" // for ReturnStmt, CompoundStmt34 #include "SynTree/Type.h" // for Type, BasicType, Type::Qualifiers35 #include "SynTree/Visitor.h" // for Visitor, acceptAll36 27 #include "CompilationState.h" 37 28 38 29 namespace CodeGen { 39 class FixNames : public WithGuards {40 public:41 void postvisit( ObjectDecl *objectDecl );42 void postvisit( FunctionDecl *functionDecl );43 30 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 } 31 namespace { 87 32 88 33 /// Does work with the main function and scopeLevels. 89 class FixNames _newfinal {34 class FixNames final { 90 35 int scopeLevel = 1; 91 36 … … 103 48 104 49 const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) { 105 if ( FixMain::isMain( functionDecl ) ) {50 if ( isMain( functionDecl ) ) { 106 51 auto mutDecl = ast::mutate( functionDecl ); 107 52 … … 138 83 }; 139 84 85 } // namespace 86 140 87 void fixNames( ast::TranslationUnit & translationUnit ) { 141 ast::Pass<FixNames _new>::run( translationUnit );88 ast::Pass<FixNames>::run( translationUnit ); 142 89 } 143 90 -
src/CodeGen/FixNames.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 class Declaration;21 18 namespace ast { 22 19 class TranslationUnit; … … 24 21 25 22 namespace CodeGen { 26 /// mangles object and function names 27 void fixNames( std::list< Declaration* > & translationUnit ); 23 28 24 /// Sets scope levels and fills in main's default return. 29 25 void fixNames( ast::TranslationUnit & translationUnit ); 26 30 27 } // namespace CodeGen 31 28 -
src/CodeGen/GenType.cc
rdf8ba61a r8d182b1 21 21 #include "AST/Print.hpp" // for print 22 22 #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 29 25 30 26 namespace 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 } // if74 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 // *** BaseSyntaxNode90 void GenType::previsit( BaseSyntaxNode * ) {91 // turn off automatic recursion for all nodes, to allow each visitor to92 // 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 } // if122 } // if123 os << "[";124 125 if ( isStatic ) {126 os << "static ";127 } // if128 if ( qualifiers.is_const ) {129 os << "const ";130 } // if131 if ( qualifiers.is_volatile ) {132 os << "volatile ";133 } // if134 if ( qualifiers.is_restrict ) {135 os << "__restrict ";136 } // if137 if ( qualifiers.is_atomic ) {138 os << "_Atomic ";139 } // if140 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 * token145 os << "*";146 } // if147 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 } // if165 pointerType->base->accept( *visitor );166 } // if167 }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 } // if190 } // if191 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 } // if202 } 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 } // if211 os << ")";212 } // if213 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 } // if221 222 // add forall223 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 ints296 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 ints302 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 } // if347 if ( type->get_volatile() ) {348 typeString = "volatile " + typeString;349 } // if350 if ( type->get_restrict() ) {351 typeString = "__restrict " + typeString;352 } // if353 if ( type->get_atomic() ) {354 typeString = "_Atomic " + typeString;355 } // if356 }357 27 358 28 namespace { 359 29 360 #warning Remove the _new when old version is removed. 361 struct GenType_new : 30 struct GenType final : 362 31 public ast::WithShortCircuiting, 363 public ast::WithVisitorRef<GenType _new> {32 public ast::WithVisitorRef<GenType> { 364 33 std::string result; 365 GenType _new( const std::string &typeString, const Options &options );34 GenType( const std::string &typeString, const Options &options ); 366 35 367 36 void previsit( ast::Node const * ); … … 397 66 }; 398 67 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 * ) {68 GenType::GenType( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {} 69 70 void GenType::previsit( ast::Node const * ) { 402 71 // Turn off automatic recursion for all nodes, to allow each visitor to 403 72 // precisely control the order in which its children are visited. … … 405 74 } 406 75 407 void GenType _new::postvisit( ast::Node const * node ) {76 void GenType::postvisit( ast::Node const * node ) { 408 77 std::stringstream ss; 409 78 ast::print( ss, node ); … … 411 80 } 412 81 413 void GenType _new::postvisit( ast::VoidType const * type ) {82 void GenType::postvisit( ast::VoidType const * type ) { 414 83 result = "void " + result; 415 84 handleQualifiers( type ); 416 85 } 417 86 418 void GenType _new::postvisit( ast::BasicType const * type ) {87 void GenType::postvisit( ast::BasicType const * type ) { 419 88 ast::BasicType::Kind kind = type->kind; 420 89 assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES ); … … 423 92 } 424 93 425 void GenType _new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {94 void GenType::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) { 426 95 std::ostringstream os; 427 96 if ( result != "" ) { … … 449 118 } 450 119 if ( dimension != 0 ) { 451 ast::Pass<CodeGenerator _new>::read( dimension, os, options );120 ast::Pass<CodeGenerator>::read( dimension, os, options ); 452 121 } else if ( isVarLen ) { 453 122 // no dimension expression on a VLA means it came in with the * token … … 461 130 } 462 131 463 void GenType _new::postvisit( ast::PointerType const * type ) {132 void GenType::postvisit( ast::PointerType const * type ) { 464 133 if ( type->isStatic || type->isVarLen || type->dimension ) { 465 134 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); … … 475 144 } 476 145 477 void GenType _new::postvisit( ast::ArrayType const * type ) {146 void GenType::postvisit( ast::ArrayType const * type ) { 478 147 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); 479 148 } 480 149 481 void GenType _new::postvisit( ast::ReferenceType const * type ) {150 void GenType::postvisit( ast::ReferenceType const * type ) { 482 151 assertf( !options.genC, "Reference types should not reach code generation." ); 483 152 handleQualifiers( type ); … … 486 155 } 487 156 488 void GenType _new::postvisit( ast::FunctionType const * type ) {157 void GenType::postvisit( ast::FunctionType const * type ) { 489 158 std::ostringstream os; 490 159 … … 526 195 //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." ); 527 196 std::ostringstream os; 528 ast::Pass<CodeGenerator _new> cg( os, options );197 ast::Pass<CodeGenerator> cg( os, options ); 529 198 os << "forall("; 530 199 cg.core.genCommaList( type->forall ); … … 534 203 } 535 204 536 std::string GenType _new::handleGeneric( ast::BaseInstType const * type ) {205 std::string GenType::handleGeneric( ast::BaseInstType const * type ) { 537 206 if ( !type->params.empty() ) { 538 207 std::ostringstream os; 539 ast::Pass<CodeGenerator _new> cg( os, options );208 ast::Pass<CodeGenerator> cg( os, options ); 540 209 os << "("; 541 210 cg.core.genCommaList( type->params ); … … 546 215 } 547 216 548 void GenType _new::postvisit( ast::StructInstType const * type ) {217 void GenType::postvisit( ast::StructInstType const * type ) { 549 218 result = type->name + handleGeneric( type ) + " " + result; 550 219 if ( options.genC ) result = "struct " + result; … … 552 221 } 553 222 554 void GenType _new::postvisit( ast::UnionInstType const * type ) {223 void GenType::postvisit( ast::UnionInstType const * type ) { 555 224 result = type->name + handleGeneric( type ) + " " + result; 556 225 if ( options.genC ) result = "union " + result; … … 558 227 } 559 228 560 void GenType _new::postvisit( ast::EnumInstType const * type ) {229 void GenType::postvisit( ast::EnumInstType const * type ) { 561 230 if ( type->base && type->base->base ) { 562 231 result = genType( type->base->base, result, options ); … … 570 239 } 571 240 572 void GenType _new::postvisit( ast::TypeInstType const * type ) {241 void GenType::postvisit( ast::TypeInstType const * type ) { 573 242 assertf( !options.genC, "TypeInstType should not reach code generation." ); 574 243 result = type->name + " " + result; … … 576 245 } 577 246 578 void GenType _new::postvisit( ast::TupleType const * type ) {247 void GenType::postvisit( ast::TupleType const * type ) { 579 248 assertf( !options.genC, "TupleType should not reach code generation." ); 580 249 unsigned int i = 0; … … 589 258 } 590 259 591 void GenType _new::postvisit( ast::VarArgsType const * type ) {260 void GenType::postvisit( ast::VarArgsType const * type ) { 592 261 result = "__builtin_va_list " + result; 593 262 handleQualifiers( type ); 594 263 } 595 264 596 void GenType _new::postvisit( ast::ZeroType const * type ) {265 void GenType::postvisit( ast::ZeroType const * type ) { 597 266 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 598 267 result = (options.pretty ? "zero_t " : "long int ") + result; … … 600 269 } 601 270 602 void GenType _new::postvisit( ast::OneType const * type ) {271 void GenType::postvisit( ast::OneType const * type ) { 603 272 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 604 273 result = (options.pretty ? "one_t " : "long int ") + result; … … 606 275 } 607 276 608 void GenType _new::postvisit( ast::GlobalScopeType const * type ) {277 void GenType::postvisit( ast::GlobalScopeType const * type ) { 609 278 assertf( !options.genC, "GlobalScopeType should not reach code generation." ); 610 279 handleQualifiers( type ); 611 280 } 612 281 613 void GenType _new::postvisit( ast::TraitInstType const * type ) {282 void GenType::postvisit( ast::TraitInstType const * type ) { 614 283 assertf( !options.genC, "TraitInstType should not reach code generation." ); 615 284 result = type->name + " " + result; … … 617 286 } 618 287 619 void GenType _new::postvisit( ast::TypeofType const * type ) {288 void GenType::postvisit( ast::TypeofType const * type ) { 620 289 std::ostringstream os; 621 290 os << "typeof("; 622 ast::Pass<CodeGenerator _new>::read( type, os, options );291 ast::Pass<CodeGenerator>::read( type, os, options ); 623 292 os << ") " << result; 624 293 result = os.str(); … … 626 295 } 627 296 628 void GenType _new::postvisit( ast::VTableType const * type ) {297 void GenType::postvisit( ast::VTableType const * type ) { 629 298 assertf( !options.genC, "Virtual table types should not reach code generation." ); 630 299 std::ostringstream os; … … 634 303 } 635 304 636 void GenType _new::postvisit( ast::QualifiedType const * type ) {305 void GenType::postvisit( ast::QualifiedType const * type ) { 637 306 assertf( !options.genC, "QualifiedType should not reach code generation." ); 638 307 std::ostringstream os; … … 642 311 } 643 312 644 void GenType _new::handleQualifiers( ast::Type const * type ) {313 void GenType::handleQualifiers( ast::Type const * type ) { 645 314 if ( type->is_const() ) { 646 315 result = "const " + result; … … 657 326 } 658 327 659 std::string GenType _new::genParamList( const ast::vector<ast::Type> & range ) {328 std::string GenType::genParamList( const ast::vector<ast::Type> & range ) { 660 329 auto cur = range.begin(); 661 330 auto end = range.end(); 662 331 if ( cur == end ) return ""; 663 332 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 ); 666 336 if ( cur == end ) break; 667 337 oss << ", "; … … 675 345 std::ostringstream os; 676 346 if ( !type->attributes.empty() ) { 677 ast::Pass<CodeGenerator _new> cg( os, options );347 ast::Pass<CodeGenerator> cg( os, options ); 678 348 cg.core.genAttributes( type->attributes ); 679 349 } 680 350 681 return os.str() + ast::Pass<GenType _new>::read( type, base, options );351 return os.str() + ast::Pass<GenType>::read( type, base, options ); 682 352 } 683 353 684 354 std::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 ); 686 356 } 687 357 -
src/CodeGen/Generate.cc
rdf8ba61a r8d182b1 19 19 #include <string> // for operator<< 20 20 21 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new, doSemicolon, ... 22 #include "CodeGenerator.h" // for CodeGenerator, doSemicolon, oper... 21 #include "CodeGeneratorNew.hpp" // for CodeGenerator, doSemicolon, ... 23 22 #include "GenType.h" // for genPrettyType 24 #include "Common/PassVisitor.h" // for PassVisitor25 #include "SynTree/LinkageSpec.h" // for isBuiltin, isGeneratable26 #include "SynTree/BaseSyntaxNode.h" // for BaseSyntaxNode27 #include "SynTree/Declaration.h" // for Declaration28 #include "SynTree/Type.h" // for Type29 23 30 24 using namespace std; 31 25 32 26 namespace CodeGen { 33 namespace {34 /// Removes misc. nodes that should not exist in CodeGen35 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 } // cleanTree47 } // namespace48 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 } // if60 os << cgv.pass.endl;61 } // if62 } // for63 }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 } // namespace96 27 97 28 namespace { … … 101 32 102 33 /// Removes various nodes that should not exist in CodeGen. 103 struct TreeCleaner _new{34 struct TreeCleaner final { 104 35 ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) { 105 36 auto mutStmt = ast::mutate( stmt ); … … 120 51 bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) { 121 52 erase_if( translationUnit.decls, shouldClean ); 122 ast::Pass<TreeCleaner _new>::run( translationUnit );53 ast::Pass<TreeCleaner>::run( translationUnit ); 123 54 124 ast::Pass<CodeGenerator _new> cgv( os,55 ast::Pass<CodeGenerator> cgv( os, 125 56 Options( pretty, generateC, lineMarks, printExprTypes ) ); 126 57 for ( auto & decl : translationUnit.decls ) { -
src/CodeGen/Generate.h
rdf8ba61a r8d182b1 17 17 18 18 #include <iostream> // for ostream 19 #include <list> // for list20 21 class BaseSyntaxNode;22 class Declaration;23 19 24 20 namespace ast { … … 27 23 28 24 namespace 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 gdb33 void generate( BaseSyntaxNode * node, std::ostream & os );34 25 35 26 /// Generates all code in transUnit and writing it to the os. -
src/CodeGen/LinkOnce.cc
rdf8ba61a r8d182b1 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h" // for PassVisitor, WithShortCircuiting25 24 26 25 namespace CodeGen { 27 26 28 27 namespace { 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.linkonce63 // visibility is a mess otherwise64 attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));65 66 }67 visit_children = false;68 }69 };70 28 71 29 bool is_cfa_linkonce( ast::Attribute const * attr ) { … … 122 80 } // namespace 123 81 124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {125 PassVisitor<LinkOnceVisitorCore> translator;126 acceptAll( translationUnit, translator );127 }128 129 82 void translateLinkOnce( ast::TranslationUnit & translationUnit ) { 130 83 ast::Pass<LinkOnceCore>::run( translationUnit ); -
src/CodeGen/LinkOnce.h
rdf8ba61a r8d182b1 20 20 // for now its almost the only attribute we handle. 21 21 22 #include <list> // for list23 22 24 class Declaration;25 23 namespace ast { 26 24 class TranslationUnit; … … 29 27 namespace CodeGen { 30 28 31 void translateLinkOnce( std::list< Declaration *> & translationUnit );32 29 void translateLinkOnce( ast::TranslationUnit & translationUnit ); 33 30 /* Convert the cfa_linkonce attribute on top level declaration into -
src/CodeGen/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC_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 \ 20 22 CodeGen/OperatorTable.cc \ 21 23 CodeGen/OperatorTable.h 22 24 23 25 SRC += $(SRC_CODEGEN) \ 24 CodeGen/CodeGenerator.cc \25 CodeGen/CodeGenerator.h \26 CodeGen/CodeGeneratorNew.cpp \27 CodeGen/CodeGeneratorNew.hpp \28 26 CodeGen/Generate.cc \ 29 27 CodeGen/Generate.h \ 30 28 CodeGen/FixMain.cc \ 29 CodeGen/FixMain.h \ 31 30 CodeGen/FixNames.cc \ 32 31 CodeGen/FixNames.h \ 33 CodeGen/GenType.cc \34 CodeGen/GenType.h \35 32 CodeGen/LinkOnce.cc \ 36 33 CodeGen/LinkOnce.h \ -
src/Common/Eval.cc
rdf8ba61a r8d182b1 19 19 20 20 #include "AST/Inspect.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "CodeGen/OperatorTable.h" // access: OperatorInfo 23 22 #include "AST/Pass.hpp" 24 23 #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 97 25 struct EvalNew : public ast::WithShortCircuiting { 98 26 Evaluation result = { 0, true, true }; … … 270 198 }; 271 199 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 282 200 Evaluation eval( const ast::Expr * expr ) { 283 201 if ( expr ) { -
src/Common/Eval.h
rdf8ba61a r8d182b1 30 30 31 31 /// 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);34 32 Evaluation eval(const ast::Expr * expr); 35 33 -
src/Common/Examine.cc
rdf8ba61a r8d182b1 19 19 #include "CodeGen/OperatorTable.h" 20 20 #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 }38 21 39 22 namespace { … … 69 52 70 53 namespace { 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 }83 54 84 55 const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) { … … 88 59 } 89 60 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;98 61 } 99 62 -
src/Common/Examine.h
rdf8ba61a r8d182b1 15 15 16 16 #include "AST/Decl.hpp" 17 #include "SynTree/Declaration.h"18 17 19 18 /// Check if this is a main function for a type of an aggregate kind. 20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );21 19 const ast::DeclWithType * isMainFor( 22 20 const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ); … … 24 22 25 23 /// Check if this function is a destructor for the given structure. 26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );27 24 bool isDestructorFor( 28 25 const ast::FunctionDecl * func, const ast::StructDecl * type ); -
src/Common/UniqueName.cc
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.cc -- 7 // UniqueName.cc -- Create a unique variants of a base name with a counter. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jun 8 14:47:49 201513 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Nov 7 15:04:00 2023 13 // Update Count : 4 14 14 // 15 15 16 #include <string> 17 #include <sstream> 16 #include "UniqueName.h" 18 17 19 #include " UniqueName.h"18 #include "Common/ToString.hpp" 20 19 21 20 UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) { … … 23 22 24 23 std::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++ ); 28 25 } 29 26 -
src/Common/UniqueName.h
rdf8ba61a r8d182b1 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.h -- 7 // UniqueName.h -- Create a unique variants of a base name with a counter. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 21 22:18:45 201713 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Nov 7 15:00:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 19 19 20 20 class UniqueName { 21 22 UniqueName( const std::string &base = "");21 public: 22 UniqueName( const std::string &base ); 23 23 std::string newName( const std::string &additional = "" ); 24 24 private: 25 25 std::string base; 26 26 int count; -
src/Common/module.mk
rdf8ba61a r8d182b1 31 31 Common/Indenter.cc \ 32 32 Common/Iterate.hpp \ 33 Common/PassVisitor.cc \34 Common/PassVisitor.h \35 Common/PassVisitor.impl.h \36 Common/PassVisitor.proto.h \37 33 Common/PersistentMap.h \ 38 34 Common/ResolvProtoDump.hpp \ -
src/Concurrency/module.mk
rdf8ba61a r8d182b1 21 21 Concurrency/Corun.hpp \ 22 22 Concurrency/KeywordsNew.cpp \ 23 Concurrency/Keywords.cc \24 23 Concurrency/Keywords.h \ 25 24 Concurrency/WaitforNew.cpp \ 26 Concurrency/Waitfor.cc \27 25 Concurrency/Waitfor.h \ 28 26 Concurrency/Waituntil.cpp \ -
src/ControlStruct/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC += \ 18 ControlStruct/ExceptDecl.cc \19 18 ControlStruct/ExceptDeclNew.cpp \ 20 19 ControlStruct/ExceptDecl.h \ 21 20 ControlStruct/ExceptTranslateNew.cpp \ 22 ControlStruct/ExceptTranslate.cc \23 21 ControlStruct/ExceptTranslate.h \ 24 22 ControlStruct/FixLabels.cpp \ 25 23 ControlStruct/FixLabels.hpp \ 26 ControlStruct/ForExprMutator.cc \27 ControlStruct/ForExprMutator.h \28 24 ControlStruct/HoistControlDecls.cpp \ 29 25 ControlStruct/HoistControlDecls.hpp \ 30 ControlStruct/LabelFixer.cc \31 ControlStruct/LabelFixer.h \32 ControlStruct/LabelGenerator.cc \33 ControlStruct/LabelGenerator.h \34 26 ControlStruct/LabelGeneratorNew.cpp \ 35 27 ControlStruct/LabelGeneratorNew.hpp \ 36 ControlStruct/MLEMutator.cc \37 ControlStruct/MLEMutator.h \38 28 ControlStruct/MultiLevelExit.cpp \ 39 ControlStruct/MultiLevelExit.hpp \ 40 ControlStruct/Mutate.cc \ 41 ControlStruct/Mutate.h 29 ControlStruct/MultiLevelExit.hpp 42 30 -
src/GenPoly/FindFunction.cc
rdf8ba61a r8d182b1 20 20 #include "AST/Pass.hpp" // for Pass 21 21 #include "AST/Type.hpp" 22 #include "Common/PassVisitor.h" // for PassVisitor23 22 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::iterator 24 23 #include "GenPoly/GenPoly.h" // for TyVarMap 25 24 #include "ScrubTyVars.h" // for ScrubTyVars 26 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl27 #include "SynTree/Mutator.h" // for Mutator, mutateAll28 #include "SynTree/Type.h" // for FunctionType, Type, Type::For...29 25 30 26 namespace 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 } // if67 } // for68 }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 } // if85 } // if86 return ret;87 }88 89 void FindFunction::premutate( PointerType * pointerType ) {90 GuardScope( tyVars );91 handleForall( pointerType->get_forall() );92 }93 27 94 28 namespace { … … 154 88 void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) { 155 89 GuardScope( typeVars ); 156 //handleForall( type->forall );157 90 } 158 91 … … 164 97 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false ); 165 98 type->accept( pass ); 166 //(void)type;167 //(void)functions;168 //(void)typeVars;169 //(void)predicate;170 99 } 171 100 … … 175 104 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true ); 176 105 return type->accept( pass ); 177 //(void)functions;178 //(void)typeVars;179 //(void)predicate;180 //return type;181 106 } 182 107 -
src/GenPoly/FindFunction.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 18 #include "GenPoly.h" // for TyVarMap 21 19 22 class FunctionType;23 class Type;24 25 20 namespace 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 );32 21 33 22 typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & ); -
src/GenPoly/GenPoly.cc
rdf8ba61a r8d182b1 29 29 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_it... 30 30 #include "ResolvExpr/typeops.h" // for flatten 31 #include "SynTree/Constant.h" // for Constant32 #include "SynTree/Expression.h" // for Expression, TypeExpr, Constan...33 #include "SynTree/Type.h" // for Type, StructInstType, UnionIn...34 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution35 31 36 32 using namespace std; … … 39 35 namespace { 40 36 /// 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 50 37 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) { 51 38 for ( auto ¶m : params ) { … … 58 45 59 46 /// 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 69 47 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) { 70 48 for ( auto & param : params ) { … … 77 55 78 56 /// 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 88 57 bool hasDynParams( 89 58 const std::vector<ast::ptr<ast::Expr>> & params, … … 99 68 return false; 100 69 } 101 102 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present103 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 present113 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;139 70 } 140 71 … … 146 77 } 147 78 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;163 79 } 164 80 … … 178 94 } 179 95 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 197 96 const ast::Type * isPolyType( const ast::Type * type, 198 97 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 211 110 } 212 111 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 229 112 const ast::BaseInstType * isDynType( 230 113 const ast::Type * type, const TypeVarMap & typeVars, … … 249 132 } 250 133 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 257 134 const ast::BaseInstType *isDynRet( 258 135 const ast::FunctionType * type, const TypeVarMap & typeVars ) { … … 262 139 } 263 140 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 272 141 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { 273 142 if ( func->returns.empty() ) return nullptr; … … 278 147 } 279 148 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 // } // if284 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 } // if291 } // for292 return false;293 }294 295 149 bool needsAdapter( 296 150 ast::FunctionType const * adaptee, const TypeVarMap & typeVars ) { … … 304 158 return false; 305 159 } 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 }324 160 325 161 const ast::Type * isPolyPtr( … … 333 169 return nullptr; 334 170 } 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 }369 171 370 172 ast::Type const * hasPolyBase( … … 388 190 } 389 191 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 otherwise426 } else {427 return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise428 }429 }430 431 192 const ast::FunctionType * getFunctionType( const ast::Type * ty ) { 432 193 if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) { … … 437 198 } 438 199 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 operator453 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 variable458 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 478 200 namespace { 479 201 /// Checks if is a pointer to D … … 488 210 inline D const * as( B const * p ) { 489 211 return reinterpret_cast<D const *>( p ); 490 }491 492 /// Flattens a declaration list493 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 types501 template<typename Output>502 void flattenList( list< Type* > src, Output out ) {503 for ( Type* ty : src ) {504 ResolvExpr::flatten( ty, out );505 }506 212 } 507 213 … … 515 221 } 516 222 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 voids529 // 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 537 223 bool paramListsPolyCompatible( 538 224 std::vector<ast::ptr<ast::Expr>> const & lparams, … … 559 245 return true; 560 246 } 561 }562 563 bool typesPolyCompatible( Type *a, Type *b ) {564 type_index aid{ typeid(*a) };565 // polymorphic types always match566 if ( aid == type_index{typeid(TypeInstType)} ) return true;567 568 type_index bid{ typeid(*b) };569 // polymorphic types always match570 if ( bid == type_index{typeid(TypeInstType)} ) return true;571 572 // can't match otherwise if different types573 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 type582 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 && bd599 && 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 type651 247 } 652 248 … … 763 359 } 764 360 765 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {766 // is parameter is not polymorphic, don't need to box767 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 775 361 bool needsBoxing( const ast::Type * param, const ast::Type * arg, 776 362 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 786 372 return !isPolyType( newType ); 787 373 } 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 }796 374 797 375 bool needsBoxing( … … 806 384 } 807 385 808 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {809 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );810 }811 812 386 void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { 813 387 typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); … … 817 391 typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) ); 818 392 } 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 }829 393 830 394 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) { … … 846 410 } 847 411 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 } // for852 os << std::endl;853 }854 855 412 } // namespace GenPoly 856 413 -
src/GenPoly/GenPoly.h
rdf8ba61a r8d182b1 23 23 #include "AST/Fwd.hpp" // for ApplicationExpr, BaseInstType, Func... 24 24 #include "SymTab/Mangler.h" // for Mangler 25 #include "SynTree/Declaration.h" // for TypeDecl::Data, AggregateDecl, Type...26 #include "SynTree/SynTree.h" // for Visitor Nodes27 25 28 26 namespace ast { … … 32 30 namespace GenPoly { 33 31 34 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;35 32 struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> { 36 33 TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {} … … 38 35 39 36 /// 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 );42 37 const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * ); 43 38 44 39 /// 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 );46 40 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 47 41 48 42 /// 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 );50 43 const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr ); 51 44 52 45 /// 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 );54 46 const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 ); 55 47 56 48 /// true iff function has dynamic-layout return type under the given type variable map 57 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );58 49 const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars ); 59 50 60 51 /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters 61 ReferenceToType *isDynRet( FunctionType *function );62 52 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ); 63 53 64 54 /// 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 );66 55 bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars ); 67 56 68 /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided69 Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );70 71 57 /// 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 );73 58 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 provided77 Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );78 59 79 60 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise; 80 61 /// 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 );82 62 const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 ); 83 63 84 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one85 /// 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 with89 /// 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 92 64 /// 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 );94 65 const ast::FunctionType * getFunctionType( const ast::Type * ty ); 95 66 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 provided98 VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );99 100 67 /// true iff types are structurally identical, where TypeInstType's match any type. 101 bool typesPolyCompatible( Type *aty, Type *bty );102 68 bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ); 103 69 104 70 /// true if arg requires boxing given exprTyVars 105 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );106 71 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ); 107 72 108 73 /// true if arg requires boxing in the call to appExpr 109 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );110 74 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst ); 111 75 112 76 /// Adds the type variable `tyVar` to `tyVarMap` 113 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );114 77 void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars ); 115 78 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ); 116 79 117 80 /// 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 );119 81 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ); 120 82 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ); 121 122 /// Prints type variable map123 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 ); }127 83 128 84 /// Gets the name of the sizeof parameter for the type, given its mangled name … … 136 92 137 93 /// 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(); }139 94 inline std::string layoutofName( ast::AggregateDecl const * decl ) { 140 95 return std::string( "_layoutof_" ) + decl->name; -
src/GenPoly/ScrubTyVars.cc
rdf8ba61a r8d182b1 21 21 #include "ScrubTyVars.h" 22 22 #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), NameExpr25 #include "SynTree/Mutator.h" // for Mutator26 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type27 23 28 24 namespace 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 } // switch57 } // if58 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 whether80 // automatic recursion is necessary81 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 T90 if ( dynType ) {91 Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );92 return expr;93 } // if94 return szeof;95 }96 97 Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {98 // alignof( T ) => _alignof_T parameter, which is the alignment of T99 if ( dynType ) {100 Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );101 return expr;102 } // if103 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 }116 25 117 26 namespace { -
src/GenPoly/ScrubTyVars.h
rdf8ba61a r8d182b1 19 19 20 20 #include "AST/Fwd.hpp" // for Node 21 #include "Common/PassVisitor.h"22 21 #include "GenPoly.h" // for TyVarMap, isPolyType, isDynType 23 #include "SynTree/Mutator.h" // for Mutator24 #include "SynTree/Type.h" // for Type (ptr only), PointerType (ptr only)25 26 class AlignofExpr;27 class Expression;28 class SizeofExpr;29 22 30 23 namespace 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 variables33 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 variable42 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 variable47 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 variable52 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; // unreachable81 // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars );82 }83 84 /// Mutates (possibly generic) aggregate types appropriately85 Type* mutateAggregateType( Type *ty );86 87 const TyVarMap *tyVars; ///< Type variables to scrub88 ScrubMode mode; ///< which type variables to scrub? [FromMap]89 90 Type * dynType = nullptr; ///< result of shouldScrub91 };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 }110 24 111 25 // ScrubMode and scrubTypeVarsBase are internal. -
src/GenPoly/SpecializeNew.cpp
rdf8ba61a r8d182b1 23 23 #include "GenPoly/GenPoly.h" // for getFunctionType 24 24 #include "ResolvExpr/FindOpenVars.h" // for findOpenVars 25 #include "ResolvExpr/TypeEnvironment.h" // for FirstOpen, FirstClosed26 25 27 26 namespace GenPoly { -
src/GenPoly/module.mk
rdf8ba61a r8d182b1 23 23 SRC += $(SRC_GENPOLY) \ 24 24 GenPoly/BoxNew.cpp \ 25 GenPoly/Box.cc \26 25 GenPoly/Box.h \ 27 26 GenPoly/ErasableScopedMap.h \ … … 29 28 GenPoly/FindFunction.h \ 30 29 GenPoly/InstantiateGenericNew.cpp \ 31 GenPoly/InstantiateGeneric.cc \32 30 GenPoly/InstantiateGeneric.h \ 33 31 GenPoly/LvalueNew.cpp \ 34 GenPoly/Lvalue.cc \35 32 GenPoly/ScopedSet.h \ 36 33 GenPoly/ScrubTyVars.cc \ 37 34 GenPoly/ScrubTyVars.h \ 38 GenPoly/Specialize.cc \39 35 GenPoly/SpecializeNew.cpp \ 40 36 GenPoly/Specialize.h -
src/InitTweak/FixGlobalInit.cc
rdf8ba61a r8d182b1 20 20 #include <algorithm> // for replace_if 21 21 22 #include "Common/PassVisitor.h"23 #include "Common/UniqueName.h" // for UniqueName24 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt25 #include "SynTree/LinkageSpec.h" // for C26 #include "SynTree/Attribute.h" // for Attribute27 #include "SynTree/Constant.h" // for Constant28 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declaration29 #include "SynTree/Expression.h" // for ConstantExpr, Expression (ptr only)30 #include "SynTree/Initializer.h" // for ConstructorInit, Initializer31 #include "SynTree/Label.h" // for Label32 #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, Visitor35 36 22 #include "AST/Expr.hpp" 37 23 #include "AST/Node.hpp" 38 24 #include "AST/Pass.hpp" 25 #include "Common/UniqueName.h" // for UniqueName 26 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt 39 27 40 28 namespace 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 { 59 30 public: 60 31 void previsit (const ast::ObjectDecl *); … … 70 41 }; 71 42 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 empty77 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {78 delete fixer.initFunction;79 } else {80 translationUnit.push_back( fixer.initFunction );81 } // if82 83 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {84 delete fixer.destroyFunction;85 } else {86 translationUnit.push_back( fixer.destroyFunction );87 } // if88 }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 which95 // is the priority, with lower numbers meaning higher priority.96 // Functions specified with priority are guaranteed to run before97 // functions without a priority. To ensure that constructors and destructors98 // 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 111 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 112 ast::Pass<GlobalFixer _new> fixer;44 ast::Pass<GlobalFixer> fixer; 113 45 accept_all(translationUnit, fixer); 114 46 … … 141 73 } 142 74 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) { 180 76 auto mutDecl = mutate(objDecl); 181 77 assertf(mutDecl == objDecl, "Global object decl must be unique"); … … 207 103 } 208 104 209 // only modify global variables210 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 217 105 } // namespace InitTweak 218 106 -
src/InitTweak/FixInitNew.cpp
rdf8ba61a r8d182b1 178 178 /// (currently by FixInit) 179 179 struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> { 180 typedef std::list< ObjectDecl * > OrderedDecls;181 typedef std::list< OrderedDecls > OrderedDeclsStack;182 183 180 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 184 181 … … 194 191 ast::Pass<LabelFinder> & finder; 195 192 LabelFinder::LabelMap & labelVars; 196 OrderedDeclsStack reverseDeclOrder;197 193 }; 198 194 … … 921 917 // static variables with the same name in different functions. 922 918 // Note: it isn't sufficient to modify only the mangleName, because 923 // then subsequent Indexerpasses can choke on seeing the object's name919 // then subsequent SymbolTable passes can choke on seeing the object's name 924 920 // if another object has the same name and type. An unfortunate side-effect 925 921 // of renaming the object is that subsequent NameExprs may fail to resolve, … … 1173 1169 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) ); 1174 1170 } 1175 InitExpander _newsrcParam( arg2 );1171 InitExpander srcParam( arg2 ); 1176 1172 // cast away reference type and construct field. 1177 1173 ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences()); -
src/InitTweak/GenInit.cc
rdf8ba61a r8d182b1 29 29 #include "CompilationState.h" 30 30 #include "CodeGen/OperatorTable.h" 31 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort...32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/ToString.hpp" // for toCString … … 38 37 #include "InitTweak.h" // for isConstExpr, InitExpander, checkIn... 39 38 #include "ResolvExpr/Resolver.h" 40 #include "SymTab/Autogen.h" // for genImplicitCall41 39 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 42 40 #include "SymTab/Mangler.h" // for Mangler 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C44 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType45 #include "SynTree/Expression.h" // for VariableExpr, UntypedExpr, Address...46 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit, Initi...47 #include "SynTree/Label.h" // for Label48 #include "SynTree/Mutator.h" // for mutateAll49 #include "SynTree/Statement.h" // for CompoundStmt, ImplicitCtorDtorStmt50 #include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers51 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept52 41 #include "Tuples/Tuples.h" // for maybeImpure 53 42 #include "Validate/FindSpecialDecls.h" // for SizeType 54 43 55 44 namespace 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 value63 /// of a function so that anything which the resolver decides can be constructed64 /// 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 run78 /// so that the initializer expression is only removed if a constructor is found79 /// 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 objects86 // that need to be constructed or destructed87 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 thus97 // 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 single105 /// const variable of type size_t, so that side effecting array dimensions are only106 /// 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 objects113 // that need to be constructed or destructed114 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 single129 /// const variable of type size_t, so that side effecting array dimensions are only130 /// 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 objects137 // that need to be constructed or destructed138 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 address171 // is being returned172 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {173 // explicitly construct the return value using the return expression and the retVal object174 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 again179 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 object186 returnStmt->expr = new VariableExpr( returnVals.front() );187 } // if188 }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 var217 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 constexpr227 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );228 // array is variable-length when the dimension is not constexpr229 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 resolve232 // still try to detect constant expressions233 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 var270 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 resolve280 // still try to detect constant expressions281 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 }298 45 299 46 namespace { 300 47 301 # warning Remove the _New suffix after the conversion is complete.302 303 48 // Outer pass finds declarations, for their type could wrap a type that needs hoisting 304 struct HoistArrayDimension_NoResolve _Newfinal :49 struct HoistArrayDimension_NoResolve final : 305 50 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting, 306 51 public ast::WithGuards, public ast::WithConstTranslationUnit, 307 public ast::WithVisitorRef<HoistArrayDimension_NoResolve _New>,52 public ast::WithVisitorRef<HoistArrayDimension_NoResolve>, 308 53 public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> { 309 54 … … 312 57 public ast::WithShortCircuiting, public ast::WithGuards { 313 58 314 HoistArrayDimension_NoResolve _New* outer;315 HoistDimsFromTypes( HoistArrayDimension_NoResolve _New* outer ) : outer(outer) {}59 HoistArrayDimension_NoResolve * outer; 60 HoistDimsFromTypes( HoistArrayDimension_NoResolve * outer ) : outer(outer) {} 316 61 317 62 // Only intended for visiting through types. … … 464 209 465 210 466 struct ReturnFixer _Newfinal :211 struct ReturnFixer final : 467 212 public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting { 468 213 void previsit( const ast::FunctionDecl * decl ); … … 472 217 }; 473 218 474 void ReturnFixer _New::previsit( const ast::FunctionDecl * decl ) {219 void ReturnFixer::previsit( const ast::FunctionDecl * decl ) { 475 220 if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false; 476 221 GuardValue( funcDecl ) = decl; 477 222 } 478 223 479 const ast::ReturnStmt * ReturnFixer _New::previsit(224 const ast::ReturnStmt * ReturnFixer::previsit( 480 225 const ast::ReturnStmt * stmt ) { 481 226 auto & returns = funcDecl->returns; … … 518 263 519 264 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 ); 522 267 } 523 268 524 269 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 { 591 274 // references are never constructed 592 275 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false; … … 607 290 } 608 291 609 bool ManagedTypes _new::isManaged( const ast::ObjectDecl * objDecl ) const {292 bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const { 610 293 const ast::Type * type = objDecl->type; 611 294 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { … … 617 300 } 618 301 619 void ManagedTypes _new::handleDWT( const ast::DeclWithType * dwt ) {302 void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) { 620 303 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 621 304 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) { … … 628 311 } 629 312 630 void ManagedTypes _new::handleStruct( const ast::StructDecl * aggregateDecl ) {313 void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) { 631 314 // don't construct members, but need to take note if there is a managed member, 632 315 // because that means that this type is also managed … … 644 327 } 645 328 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(); } 659 331 660 332 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 661 333 assertf(objDecl, "genCtorDtor passed null objDecl"); 662 InitExpander _newsrcParam(arg);334 InitExpander srcParam(arg); 663 335 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/dtor668 // for each constructable object669 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 CompoundStmt678 // which wraps everything that needs to happen. As such, it's technically679 // possible to use a Statement ** in the above calls, but this is inherently680 // unsafe, so instead we take the slightly less efficient route, but will be681 // 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 genImplicitCall684 // itself. It is possible that genImplicitCall produces no statements (e.g. if685 // an array type does not have a dimension). In this case, it's fine to ignore686 // 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 exist690 // if ctor does exist, want to use ctor expression instead of init691 // push this decision to the resolver692 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 C702 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {703 // constructed objects cannot be designated704 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 deeply706 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 parameters714 GuardValue( inFunction );715 inFunction = true;716 717 managedTypes.handleDWT( functionDecl );718 719 GuardScope( managedTypes );720 // go through assertions and recursively add seen ctor/dtors721 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 members732 733 managedTypes.handleStruct( aggregateDecl );734 }735 736 void CtorDtor::previsit( CompoundStmt * ) {737 GuardScope( managedTypes );738 336 } 739 337 … … 741 339 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each 742 340 // constructable object 743 InitExpander _newsrcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };341 InitExpander srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr }; 744 342 ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl); 745 343 -
src/InitTweak/GenInit.h
rdf8ba61a r8d182b1 22 22 #include "Common/CodeLocation.h" 23 23 #include "GenPoly/ScopedSet.h" // for ScopedSet 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 namespace InitTweak { 27 26 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( std::list< Declaration * > & translationUnit );29 27 void genInit( ast::TranslationUnit & translationUnit ); 30 28 31 29 /// Converts return statements into copy constructor calls on the hidden return variable. 32 30 /// This pass must happen before auto-gen. 33 void fixReturnStatements( std::list< Declaration * > & translationUnit );34 31 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 35 32 36 33 /// 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 );38 34 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 39 35 40 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 41 ConstructorInit * genCtorInit( ObjectDecl * objDecl );42 37 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 43 38 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 { 59 40 public: 60 41 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed -
src/InitTweak/InitTweak.cc
rdf8ba61a r8d182b1 29 29 #include "AST/Type.hpp" 30 30 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 #include "Common/PassVisitor.h"32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/UniqueName.h" // for UniqueName … … 36 35 #include "InitTweak.h" 37 36 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 38 #include "SymTab/Autogen.h"39 #include "SymTab/Indexer.h" // for Indexer40 #include "SynTree/LinkageSpec.h" // for Spec, isBuiltin, Intrinsic41 #include "SynTree/Attribute.h" // for Attribute42 #include "SynTree/Constant.h" // for Constant43 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType44 #include "SynTree/Expression.h" // for Expression, UntypedExpr, Applicati...45 #include "SynTree/Initializer.h" // for Initializer, ListInit, Designation46 #include "SynTree/Label.h" // for Label47 #include "SynTree/Statement.h" // for CompoundStmt, ExprStmt, BranchStmt48 #include "SynTree/Type.h" // for FunctionType, ArrayType, PointerType49 #include "SynTree/Visitor.h" // for Visitor, maybeAccept50 37 #include "Tuples/Tuples.h" // for Tuples::isTtype 51 38 52 39 namespace InitTweak { 53 40 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 { 92 42 bool result = false; 93 43 … … 107 57 }; 108 58 109 struct InitDepthChecker _new{59 struct InitDepthChecker { 110 60 bool result = true; 111 61 const ast::Type * type; 112 62 int curDepth = 0, maxDepth = 0; 113 InitDepthChecker _new( const ast::Type * type ) : type( type ) {63 InitDepthChecker( const ast::Type * type ) : type( type ) { 114 64 const ast::Type * t = type; 115 65 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { … … 128 78 }; 129 79 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 { 139 81 std::vector< ast::ptr< ast::Expr > > argList; 140 82 … … 147 89 } // anonymous namespace 148 90 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 167 91 bool isDesignated( const ast::Init * init ) { 168 ast::Pass<HasDesignations _new> finder;92 ast::Pass<HasDesignations> finder; 169 93 maybe_accept( init, finder ); 170 94 return finder.core.result; … … 172 96 173 97 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 174 ast::Pass<InitDepthChecker _new> checker( objDecl->type );98 ast::Pass<InitDepthChecker> checker( objDecl->type ); 175 99 maybe_accept( objDecl->init.get(), checker ); 176 100 return checker.core.result; … … 178 102 179 103 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 180 ast::Pass< InitFlattener _new> flattener;104 ast::Pass< InitFlattener > flattener; 181 105 maybe_accept( init, flattener ); 182 106 return std::move( flattener.core.argList ); 183 107 } 184 108 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 { 109 class InitExpander::ExpanderImpl { 370 110 public: 371 111 virtual ~ExpanderImpl() = default; … … 397 137 template< typename Out > 398 138 void build( 399 ast::UntypedExpr * callExpr, const InitExpander _new::IndexList & indices,139 ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices, 400 140 const ast::Init * init, Out & out 401 141 ) { … … 443 183 } 444 184 445 class InitImpl _new final : public InitExpander_new::ExpanderImpl {185 class InitImpl final : public InitExpander::ExpanderImpl { 446 186 ast::ptr< ast::Init > init; 447 187 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 { 451 191 return makeInitList( init ); 452 192 } 453 193 454 194 ast::ptr< ast::Stmt > buildListInit( 455 ast::UntypedExpr * callExpr, InitExpander _new::IndexList & indices195 ast::UntypedExpr * callExpr, InitExpander::IndexList & indices 456 196 ) override { 457 197 // If array came with an initializer list, initialize each element. We may have more … … 475 215 }; 476 216 477 class ExprImpl _new final : public InitExpander_new::ExpanderImpl {217 class ExprImpl final : public InitExpander::ExpanderImpl { 478 218 ast::ptr< ast::Expr > arg; 479 219 public: 480 ExprImpl _new( const ast::Expr * a ) : arg( a ) {}220 ExprImpl( const ast::Expr * a ) : arg( a ) {} 481 221 482 222 std::vector< ast::ptr< ast::Expr > > next( 483 InitExpander _new::IndexList & indices223 InitExpander::IndexList & indices 484 224 ) override { 485 225 if ( ! arg ) return {}; … … 497 237 498 238 ast::ptr< ast::Stmt > buildListInit( 499 ast::UntypedExpr *, InitExpander _new::IndexList &239 ast::UntypedExpr *, InitExpander::IndexList & 500 240 ) override { 501 241 return {}; … … 504 244 } // anonymous namespace 505 245 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++ () {246 InitExpander::InitExpander( const ast::Init * init ) 247 : expander( new InitImpl{ init } ), crnt(), indices() {} 248 249 InitExpander::InitExpander( const ast::Expr * expr ) 250 : expander( new ExprImpl{ expr } ), crnt(), indices() {} 251 252 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; } 253 254 InitExpander & InitExpander::operator++ () { 515 255 crnt = expander->next( indices ); 516 256 return *this; … … 519 259 /// builds statement which has the same semantics as a C-style list initializer (for array 520 260 /// initializers) using callExpr as the base expression to perform initialization 521 ast::ptr< ast::Stmt > InitExpander _new::buildListInit( ast::UntypedExpr * callExpr ) {261 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) { 522 262 return expander->buildListInit( callExpr, indices ); 523 263 } 524 264 525 void InitExpander _new::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {265 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) { 526 266 indices.emplace_back( index ); 527 267 indices.emplace_back( dimension ); 528 268 } 529 269 530 void InitExpander _new::clearArrayIndices() { indices.clear(); }531 532 bool InitExpander _new::addReference() {270 void InitExpander::clearArrayIndices() { indices.clear(); } 271 272 bool InitExpander::addReference() { 533 273 for ( ast::ptr< ast::Expr > & expr : crnt ) { 534 274 expr = new ast::AddressExpr{ expr }; … … 536 276 return ! crnt.empty(); 537 277 } 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 }545 278 546 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { … … 554 287 } 555 288 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 563 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 564 290 assertf( func, "getParamThis: nullptr ftype" ); … … 566 292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 567 293 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_extern576 && 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 );581 294 } 582 295 … … 595 308 } 596 309 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 { 622 311 std::vector< const ast::Expr * > matches; 623 312 const std::vector< std::string > names; 624 313 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) ) {} 626 315 627 316 void handleCallExpr( const ast::Expr * expr ) { … … 636 325 }; 637 326 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 644 327 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 >{ "?{}", "^?{}" } }; 646 329 maybe_accept( stmt, finder ); 647 330 return std::move( finder.core.matches ); 648 331 } 649 332 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 657 333 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/dtor713 // 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 725 334 template <typename Predicate> 726 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { … … 728 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 729 338 } 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 });741 339 } 742 340 … … 751 349 return false; 752 350 }); 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 and829 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction830 // 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 } );878 351 } 879 352 … … 908 381 } 909 382 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 { 951 384 // most expressions are not const expr 952 385 void previsit( const ast::Expr * ) { result = false; visit_children = false; } … … 991 424 }; 992 425 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 } // if1008 // for all intents and purposes, no initializer means const expr1009 return true;1010 }1011 1012 426 bool isConstExpr( const ast::Expr * expr ) { 1013 427 if ( expr ) { 1014 ast::Pass<ConstExprChecker _new> checker;428 ast::Pass<ConstExprChecker> checker; 1015 429 expr->accept( checker ); 1016 430 return checker.core.result; … … 1021 435 bool isConstExpr( const ast::Init * init ) { 1022 436 if ( init ) { 1023 ast::Pass<ConstExprChecker _new> checker;437 ast::Pass<ConstExprChecker> checker; 1024 438 init->accept( checker ); 1025 439 return checker.core.result; … … 1029 443 } 1030 444 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 1049 445 bool isAssignment( const ast::FunctionDecl * decl ) { 1050 446 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl ); … … 1073 469 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 ); 1074 470 } 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 }1099 471 1100 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message … … 1105 477 static const char * const data_section = ".data" ASM_COMMENT; 1106 478 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 }1114 479 1115 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { … … 1121 486 } 1122 487 1123 } 488 } // namespace InitTweak -
src/InitTweak/InitTweak.h
rdf8ba61a r8d182b1 22 22 23 23 #include "AST/Fwd.hpp" // for AST nodes 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 // helper functions for initialization 27 26 namespace 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 );33 27 bool isAssignment( const ast::FunctionDecl * decl ); 34 28 bool isDestructor( const ast::FunctionDecl * decl ); … … 38 32 39 33 /// returns the base type of the first parameter to a constructor/destructor/assignment function 40 Type * getTypeofThis( FunctionType * ftype );41 34 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 42 35 43 36 /// returns the first parameter of a constructor/destructor/assignment function 44 ObjectDecl * getParamThis( FunctionType * ftype );45 37 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 46 38 47 39 /// generate a bitwise assignment operation. 48 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );49 50 40 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 51 41 52 42 /// transform Initializer into an argument list that can be passed to a call expression 53 std::list< Expression * > makeInitList( Initializer * init );54 43 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 55 44 56 45 /// True if the resolver should try to construct dwt 57 bool tryConstruct( DeclarationWithType * dwt );58 46 bool tryConstruct( const ast::DeclWithType * dwt ); 59 47 60 48 /// True if the type can have a user-defined constructor 61 bool isConstructable( Type * t );62 49 bool isConstructable( const ast::Type * t ); 63 50 64 51 /// True if the Initializer contains designations 65 bool isDesignated( Initializer * init );66 52 bool isDesignated( const ast::Init * init ); 67 53 68 54 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 69 55 /// type, where the depth of its type is the number of nested ArrayTypes + 1 70 bool checkInitDepth( ObjectDecl * objDecl );71 56 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 intrinsic78 ApplicationExpr * isIntrinsicCallExpr( Expression * expr );79 57 80 58 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 81 59 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 82 60 /// Currently has assertions that make it less than fully general. 83 bool isIntrinsicSingleArgCallStmt( Statement * stmt );84 61 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 85 62 86 /// True if stmt is a call statement where the function called is intrinsic.87 bool isIntrinsicCallStmt( Statement * stmt );88 89 63 /// get all Ctor/Dtor call expressions from a Statement 90 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );91 64 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 92 65 93 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call94 Expression * getCtorDtorCall( Statement * stmt );95 96 /// returns the name of the function being called97 std::string getFunctionName( Expression * expr );98 99 /// returns the argument to a call expression in position N indexed from 0100 Expression *& getCallArg( Expression * callExpr, unsigned int pos );101 102 /// returns the base type of a PointerType or ArrayType, else returns NULL103 Type * getPointerBase( Type * );104 105 /// returns the argument if it is a PointerType or ArrayType, else returns NULL106 Type * isPointerType( Type * );107 108 66 /// returns true if expr is trivially a compile-time constant 109 bool isConstExpr( Expression * expr );110 bool isConstExpr( Initializer * init );111 112 67 bool isConstExpr( const ast::Expr * expr ); 113 68 bool isConstExpr( const ast::Init * init ); … … 122 77 /// .section .data#,"a" 123 78 /// to avoid assembler warning "ignoring changed section attributes for .data" 124 void addDataSectionAttribute( ObjectDecl * objDecl );125 126 79 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 127 80 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 { 159 82 public: 160 83 using IndexList = std::vector< ast::ptr< ast::Expr > >; … … 169 92 public: 170 93 /// Expand by stepping through init to get each list of arguments 171 InitExpander _new( const ast::Init * init );94 InitExpander( const ast::Init * init ); 172 95 173 96 /// Always expand to expression 174 InitExpander _new( const ast::Expr * expr );97 InitExpander( const ast::Expr * expr ); 175 98 176 99 std::vector< ast::ptr< ast::Expr > > operator* (); 177 InitExpander _new& operator++ ();100 InitExpander & operator++ (); 178 101 179 102 /// builds statement which has the same semantics as a C-style list initializer (for array … … 188 111 bool addReference(); 189 112 }; 190 } // namespace 113 } // namespace InitTweak 191 114 192 115 // Local Variables: // -
src/InitTweak/module.mk
rdf8ba61a r8d182b1 24 24 InitTweak/FixGlobalInit.cc \ 25 25 InitTweak/FixGlobalInit.h \ 26 InitTweak/FixInit.cc \27 26 InitTweak/FixInit.h \ 28 27 InitTweak/FixInitNew.cpp -
src/MakeLibCfa.h
rdf8ba61a r8d182b1 24 24 25 25 namespace LibCfa { 26 void makeLibCfa( std::list< Declaration* > &prelude );27 26 void makeLibCfa( ast::TranslationUnit & translationUnit ); 28 27 } // namespace LibCfa -
src/Makefile.am
rdf8ba61a r8d182b1 22 22 CompilationState.cc \ 23 23 CompilationState.h \ 24 MakeLibCfa.cc \25 24 MakeLibCfaNew.cpp \ 26 25 MakeLibCfa.h … … 42 41 include AST/module.mk 43 42 include CodeGen/module.mk 44 include CodeTools/module.mk45 43 include Concurrency/module.mk 46 44 include Common/module.mk … … 51 49 include ResolvExpr/module.mk 52 50 include SymTab/module.mk 53 include SynTree/module.mk54 51 include Tuples/module.mk 55 52 include Validate/module.mk 56 53 include Virtual/module.mk 57 54 58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/ SynTree/Type.h55 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp 59 56 60 57 $(srcdir)/AST/Type.hpp : BasicTypes-gen.cc -
src/Parser/RunParser.cpp
rdf8ba61a r8d182b1 16 16 #include "RunParser.hpp" 17 17 18 #include "AST/Convert.hpp" // for convert19 18 #include "AST/TranslationUnit.hpp" // for TranslationUnit 20 #include "CodeTools/TrackLoc.h" // for fillLocations21 19 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 22 20 #include "Parser/DeclarationNode.h" // for DeclarationNode, buildList -
src/Parser/parser.yy
rdf8ba61a r8d182b1 57 57 #include "Common/SemanticError.h" // error_str 58 58 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 59 60 #include "SynTree/Attribute.h" // for Attribute61 59 62 60 // lex uses __null in a boolean context, it's fine. -
src/ResolvExpr/AdjustExprType.cc
rdf8ba61a r8d182b1 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "SymTab/Indexer.h" // for Indexer23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype24 #include "SynTree/Mutator.h" // for Mutator25 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type26 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment27 21 28 22 namespace ResolvExpr { 29 23 30 24 namespace { 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 { 103 26 const ast::SymbolTable & symtab; 104 27 public: 105 28 const ast::TypeEnvironment & tenv; 106 29 107 AdjustExprType _new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )30 AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 108 31 : symtab( syms ), tenv( e ) {} 109 32 … … 152 75 const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab 153 76 ) { 154 ast::Pass<AdjustExprType _new> adjuster{ env, symtab };77 ast::Pass<AdjustExprType> adjuster{ env, symtab }; 155 78 return type->accept( adjuster ); 156 79 } -
src/ResolvExpr/AdjustExprType.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 }22 18 namespace ast { 23 19 class SymbolTable; … … 27 23 28 24 namespace ResolvExpr { 29 30 class TypeEnvironment;31 32 /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function33 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 } // while43 }44 25 45 26 /// Replaces array types with equivalent pointer, -
src/ResolvExpr/CandidateFinder.cpp
rdf8ba61a r8d182b1 61 61 namespace { 62 62 /// 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 > >; 64 64 65 65 /// Returns a list of alternatives with the minimum cost in the given list … … 255 255 256 256 /// 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 { 258 258 return args[ nextArg-1 ][ explAlt ]; 259 259 } … … 281 281 bool instantiateArgument( 282 282 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, 284 284 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 285 285 unsigned nTuples = 0 … … 618 618 const CodeLocation & location, 619 619 const CandidateRef & func, const ast::FunctionType * funcType, 620 const ExplodedArgs _new& args, CandidateList & out );620 const ExplodedArgs & args, CandidateList & out ); 621 621 622 622 /// Adds implicit struct-conversions to the alternative list … … 737 737 const CodeLocation & location, 738 738 const CandidateRef & func, const ast::FunctionType * funcType, 739 const ExplodedArgs _new& args, CandidateList & out739 const ExplodedArgs & args, CandidateList & out 740 740 ) { 741 741 ast::OpenVarSet funcOpen; … … 997 997 998 998 // pre-explode arguments 999 ExplodedArgs _newargExpansions;999 ExplodedArgs argExpansions; 1000 1000 for ( const CandidateFinder & args : argCandidates ) { 1001 1001 argExpansions.emplace_back(); -
src/ResolvExpr/CastCost.cc
rdf8ba61a r8d182b1 26 26 #include "ResolvExpr/ConversionCost.h" // for conversionCost 27 27 #include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass29 #include "ResolvExpr/typeops.h" // for ptrsCastable30 28 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 31 #include "SymTab/Indexer.h" // for Indexer32 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl33 #include "SynTree/Type.h" // for PointerType, Type, TypeInstType34 29 35 30 #if 0 … … 40 35 41 36 namespace 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 );46 37 38 namespace { 39 struct CastCost : public ConversionCost { 47 40 using ConversionCost::previsit; 48 41 using ConversionCost::postvisit; 49 void postvisit( const BasicType * basicType );50 void postvisit( const PointerType * pointerType );51 };52 42 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( 149 44 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 150 45 const ast::TypeEnvironment & env, CostCalculation costFunc ) 151 : ConversionCost _new( dst, srcIsLvalue, symtab, env, costFunc ) {}46 : ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {} 152 47 153 48 void postvisit( const ast::BasicType * basicType ) { … … 189 84 }; 190 85 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 & env199 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }200 86 } // anonymous namespace 201 202 203 87 204 88 Cost castCost( … … 242 126 } else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) { 243 127 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; ) 244 #warning cast on ptrsCastable artifact of having two functions, remove when port done245 128 return convertToReferenceCost( 246 src, refType, srcIsLvalue, symtab, env, localPtrsCastable );129 src, refType, srcIsLvalue, symtab, env, ptrsCastable ); 247 130 } 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 ); 251 133 src->accept( converter ); 252 134 return converter.core.cost; -
src/ResolvExpr/CastCost.hpp
rdf8ba61a r8d182b1 18 18 #include "ResolvExpr/Cost.h" // for Cost 19 19 20 class Type;21 namespace SymTab {22 class Indexer;23 }24 20 namespace ast { 25 21 class SymbolTable; … … 30 26 namespace ResolvExpr { 31 27 32 class TypeEnvironment;33 34 Cost castCost(35 const Type * src, const Type * dest, bool srcIsLvalue,36 const SymTab::Indexer & indexer, const TypeEnvironment & env );37 28 Cost castCost( 38 29 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, -
src/ResolvExpr/CommonType.cc
rdf8ba61a r8d182b1 23 23 #include "AST/Pass.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h"26 #include "ResolvExpr/TypeEnvironment.h" // for OpenVarSet, AssertionSet27 #include "SymTab/Indexer.h" // for Indexer28 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl (ptr...29 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::...30 #include "SynTree/Visitor.h" // for Visitor31 25 #include "Unify.h" // for unifyExact, WidenMode 32 26 #include "typeops.h" // for isFtype … … 41 35 42 36 namespace 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; // inherited71 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 variables82 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 other112 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 left121 assert( ref1 );122 result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );123 } else {124 // deeper on the right125 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 reference130 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 declarations147 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 } // if161 type1->tq = tq1;162 type->get_base()->tq = Type::Qualifiers();163 } // if164 } // if165 } // if166 } // if167 } // if168 #ifdef DEBUG169 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 } // if179 std::cerr << std::endl;180 #endif181 return result;182 }183 37 184 38 // GENERATED START, DO NOT EDIT … … 489 343 ); 490 344 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 { 676 346 const ast::Type * type2; 677 347 WidenMode widen; … … 684 354 ast::ptr< ast::Type > result; 685 355 686 CommonType _new(356 CommonType( 687 357 const ast::Type * t2, WidenMode w, 688 358 ast::TypeEnvironment & env, const ast::OpenVarSet & o, … … 718 388 result = enumDecl->base.get(); 719 389 } else { 720 #warning remove casts when `commonTypes` moved to new AST721 390 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ]; 722 391 if ( … … 1069 738 }; 1070 739 1071 // size_t CommonType _new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");740 // size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType"); 1072 741 namespace { 1073 742 ast::ptr< ast::Type > handleReference( … … 1141 810 } 1142 811 // 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 }; 1144 813 type1->accept( visitor ); 1145 814 // ast::ptr< ast::Type > result = visitor.core.result; -
src/ResolvExpr/CommonType.hpp
rdf8ba61a r8d182b1 18 18 #include "AST/Fwd.hpp" 19 19 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 20 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet21 20 #include "WidenMode.h" // for WidenMode 22 23 class Type;24 namespace SymTab {25 class Indexer;26 }27 21 28 22 namespace ResolvExpr { 29 23 30 Type * commonType(31 Type * type1, Type * type2, bool widenFirst, bool widenSecond,32 const SymTab::Indexer & indexer, TypeEnvironment & env,33 const OpenVarSet & openVars );34 24 ast::ptr< ast::Type > commonType( 35 25 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, -
src/ResolvExpr/ConversionCost.cc
rdf8ba61a r8d182b1 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment24 23 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 25 24 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType29 30 25 31 26 namespace ResolvExpr { 32 #if 033 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 #endif43 27 44 28 #if 0 … … 47 31 #define PRINT(x) 48 32 #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 point64 assert( type );65 if ( type->base ) {66 return conversionCost( src, type->base, srcIsLvalue, indexer, env )67 + Cost::safe;68 } // if69 } // if70 PRINT( std::cerr << " not found" << std::endl; )71 } // if72 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 } // if101 } // if102 }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 this109 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 this116 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 references125 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 same132 return Cost::zero;133 } else {134 // types are the same, except otherPointer has more qualifiers135 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 } // if145 } // if146 } 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 } // if155 } 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 cast169 } if ( src->tq < destAsRef->base->tq ) {170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same171 } else {172 return Cost::unsafe;173 } // if174 } 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 } // if183 } // if184 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 }200 33 201 34 // GENERATED START, DO NOT EDIT … … 319 152 ); 320 153 321 void ConversionCost::postvisit( const VoidType * ) {322 cost = Cost::infinity;323 }324 325 // refactor for code resue326 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 } // if335 } // ConversionCost::conversionCostFromBasicToBasic336 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 } // if348 } else {349 cost = Cost::unsafe;350 } // if351 } // if352 // 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 same364 cost = Cost::zero;365 } else {366 // types are the same, except otherPointer has more qualifiers367 cost = Cost::safe;368 } // if369 } 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 } // if382 // assignResult == 0 means Cost::Infinity383 } // if384 // case case for zero_t because it should not be possible to convert pointers to zero_t.385 } // if386 }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 check392 assert( ! dynamic_cast< const ReferenceType * >( dest ) );393 // convert reference to rvalue: cv T1 & => T2394 // 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 qualifiers399 } else if ( refType->base->tq < dest->tq ) {400 cost.incSafe(); // then gaining qualifiers401 } else {402 cost.incUnsafe(); // lose qualifiers as last resort403 }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 enum412 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 >= int417 } // if418 if ( cost < Cost::unsafe ) {419 cost.incSafe();420 } // if421 }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 point435 assert( type );436 if ( type->base ) {437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;438 } // if439 } // if440 }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 } // if452 c += newCost;453 } // while454 if ( destIt != destAsTuple->types.end() ) {455 cost = Cost::infinity;456 } else {457 cost = c;458 } // if459 } // if460 }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 conversions473 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 } // if481 } else if ( dynamic_cast< const PointerType * >( dest ) ) {482 cost = Cost::zero;483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation484 } // if485 }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 conversions492 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 } // if500 } // if501 }502 503 154 namespace { 504 # warning For overload resolution between the two versions.505 155 int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 506 156 const ast::SymbolTable &, const ast::TypeEnvironment & env ) { 507 157 return ptrsAssignable( t1, t2, env ); 508 158 } 509 Cost localConversionCost(510 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,511 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env512 ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }513 159 } 514 160 … … 540 186 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable ); 541 187 } 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 ); 543 189 } 544 190 } … … 581 227 } 582 228 } 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 ); 584 230 } 585 231 } else { … … 613 259 } 614 260 615 void ConversionCost _new::postvisit( const ast::VoidType * voidType ) {261 void ConversionCost::postvisit( const ast::VoidType * voidType ) { 616 262 (void)voidType; 617 263 cost = Cost::infinity; 618 264 } 619 265 620 void ConversionCost _new::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {266 void ConversionCost::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) { 621 267 int tableResult = costMatrix[ src->kind ][ dest->kind ]; 622 268 if ( tableResult == -1 ) { … … 629 275 } 630 276 631 void ConversionCost _new::postvisit( const ast::BasicType * basicType ) {277 void ConversionCost::postvisit( const ast::BasicType * basicType ) { 632 278 if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) { 633 279 conversionCostFromBasicToBasic( basicType, dstAsBasic ); … … 635 281 const ast::EnumDecl * enumDecl = enumInst->base.get(); 636 282 if ( enumDecl->isTyped && !enumDecl->base.get() ) { 637 cost = Cost::infinity; 283 cost = Cost::infinity; 638 284 } else if ( const ast::Type * enumType = enumDecl->base.get() ) { 639 285 if ( const ast::BasicType * enumTypeAsBasic = dynamic_cast<const ast::BasicType *>(enumType) ) { … … 648 294 } 649 295 650 void ConversionCost _new::postvisit( const ast::PointerType * pointerType ) {296 void ConversionCost::postvisit( const ast::PointerType * pointerType ) { 651 297 if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) { 652 298 ast::CV::Qualifiers tq1 = pointerType->base->qualifiers; … … 694 340 } 695 341 696 void ConversionCost _new::postvisit( const ast::ArrayType * arrayType ) {342 void ConversionCost::postvisit( const ast::ArrayType * arrayType ) { 697 343 (void)arrayType; 698 344 } 699 345 700 void ConversionCost _new::postvisit( const ast::ReferenceType * refType ) {346 void ConversionCost::postvisit( const ast::ReferenceType * refType ) { 701 347 assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) ); 702 348 … … 716 362 } 717 363 718 void ConversionCost _new::postvisit( const ast::FunctionType * functionType ) {364 void ConversionCost::postvisit( const ast::FunctionType * functionType ) { 719 365 (void)functionType; 720 366 } 721 367 722 void ConversionCost _new::postvisit( const ast::EnumInstType * enumInstType ) {368 void ConversionCost::postvisit( const ast::EnumInstType * enumInstType ) { 723 369 const ast::EnumDecl * baseEnum = enumInstType->base; 724 370 if ( const ast::Type * baseType = baseEnum->base ) { … … 733 379 } 734 380 735 void ConversionCost _new::postvisit( const ast::TraitInstType * traitInstType ) {381 void ConversionCost::postvisit( const ast::TraitInstType * traitInstType ) { 736 382 (void)traitInstType; 737 383 } 738 384 739 void ConversionCost _new::postvisit( const ast::TypeInstType * typeInstType ) {385 void ConversionCost::postvisit( const ast::TypeInstType * typeInstType ) { 740 386 if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) { 741 387 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env ); … … 754 400 } 755 401 756 void ConversionCost _new::postvisit( const ast::TupleType * tupleType ) {402 void ConversionCost::postvisit( const ast::TupleType * tupleType ) { 757 403 Cost c = Cost::zero; 758 404 if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) { … … 776 422 } 777 423 778 void ConversionCost _new::postvisit( const ast::VarArgsType * varArgsType ) {424 void ConversionCost::postvisit( const ast::VarArgsType * varArgsType ) { 779 425 (void)varArgsType; 780 426 if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) { … … 783 429 } 784 430 785 void ConversionCost _new::postvisit( const ast::ZeroType * zeroType ) {431 void ConversionCost::postvisit( const ast::ZeroType * zeroType ) { 786 432 (void)zeroType; 787 433 if ( dynamic_cast< const ast::ZeroType * >( dst ) ) { … … 810 456 } 811 457 812 void ConversionCost _new::postvisit( const ast::OneType * oneType ) {458 void ConversionCost::postvisit( const ast::OneType * oneType ) { 813 459 (void)oneType; 814 460 if ( dynamic_cast< const ast::OneType * >( dst ) ) { 815 461 cost = Cost::zero; 816 462 } else if ( const ast::BasicType * dstAsBasic = 817 dynamic_cast< const ast::BasicType * >( dst ) ) { 463 dynamic_cast< const ast::BasicType * >( dst ) ) { 818 464 int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ]; 819 465 if ( -1 == tableResult ) { … … 824 470 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 825 471 } 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"); 831 476 832 477 } // namespace ResolvExpr -
src/ResolvExpr/ConversionCost.h
rdf8ba61a r8d182b1 22 22 #include "AST/Fwd.hpp" 23 23 #include "AST/Pass.hpp" // for WithShortCircuiting 24 #include "Common/PassVisitor.h"25 #include "SynTree/Visitor.h" // for Visitor26 #include "SynTree/SynTree.h" // for Visitor Nodes27 28 namespace SymTab {29 class Indexer;30 } // namespace SymTab31 24 32 25 namespace 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 resue73 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 );79 26 80 27 // Some function pointer types, differ in return type. … … 92 39 PtrsCalculation func ); 93 40 94 #warning when the old ConversionCost is removed, get ride of the _new suffix. 95 class ConversionCost_new : public ast::WithShortCircuiting { 41 class ConversionCost : public ast::WithShortCircuiting { 96 42 protected: 97 43 const ast::Type * dst; … … 105 51 Cost result() { return cost; } 106 52 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, 108 54 const ast::TypeEnvironment & env, CostCalculation costCalc ) : 109 55 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ), -
src/ResolvExpr/CurrentObject.cc
rdf8ba61a r8d182b1 33 33 #include "Common/utility.h" // for toString 34 34 #include "CurrentObject.h" 35 #include "SynTree/Constant.h" // for Constant36 #include "SynTree/Declaration.h" // for ObjectDecl, Declaration, Struc...37 #include "SynTree/Expression.h" // for InitAlternative, VariableExpr38 #include "SynTree/Initializer.h" // for Designation, operator<<39 #include "SynTree/Type.h" // for Type, StructInstType, UnionIns...40 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution41 35 42 36 #if 0 … … 45 39 #define PRINT(x) 46 40 #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 guide74 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 object77 virtual std::list<InitAlternative> operator*() const = 0;78 79 /// true if the iterator is not currently at the end80 virtual operator bool() const = 0;81 82 /// moves the iterator by one member in the current object83 virtual MemberIterator & bigStep() = 0;84 85 /// moves the iterator by one member in the current subobject86 virtual MemberIterator & smallStep() = 0;87 88 /// the type of the current object89 virtual Type * getType() = 0;90 91 /// the type of the current subobject92 virtual Type * getNext() = 0;93 94 /// printing for debug95 virtual void print( std::ostream & out, Indenter indent ) const = 0;96 97 /// helper for operator*; aggregates must add designator to each init alternative, but98 /// adding designators in operator* creates duplicates.99 virtual std::list<InitAlternative> first() const = 0; // should be protected100 };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 correctly109 MemberIterator * createMemberIterator( Type * type );110 111 /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry112 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 error118 }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 step124 virtual MemberIterator & bigStep() { return smallStep(); }125 virtual MemberIterator & smallStep() {126 type = nullptr; // type is nullified on increment since SimpleIterators do not have members127 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 expressions173 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 debug272 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 beginning277 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 types311 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 } // if333 } // for334 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 } // if338 } // if339 }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 structure375 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 member398 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's487 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 name501 // 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 } // if510 } // for511 } // if512 ++dit;513 } // for514 } 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 } // for526 } // if527 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 } // for533 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 } ) // for542 assertf( ! curTypes.empty(), "empty designator chosen");543 544 // set new designators545 assertf( ! objStack.empty(), "empty object stack when setting designation" );546 Designation * actualDesignation = new Designation( d );547 objStack.top()->setPosition( d ); // destroys d548 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 ResolvExpr593 41 594 42 namespace ast { -
src/ResolvExpr/FindOpenVars.cc
rdf8ba61a r8d182b1 16 16 #include "FindOpenVars.h" 17 17 18 #include <list> // for _List_const_iterator, list<>::const...19 #include <map> // for map<>::mapped_type20 21 18 #include "AST/Pass.hpp" 22 19 #include "AST/Type.hpp" 23 20 #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, ArrayType27 21 28 22 #include <iostream> 29 23 30 24 namespace 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 } // for74 } // if75 /// 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 }100 25 101 26 namespace { 102 struct FindOpenVars _newfinal : public ast::WithGuards {27 struct FindOpenVars final : public ast::WithGuards { 103 28 ast::OpenVarSet & open; 104 29 ast::OpenVarSet & closed; … … 108 33 bool nextIsOpen; 109 34 110 FindOpenVars _new(35 FindOpenVars( 111 36 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n, 112 37 ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen ) … … 148 73 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 149 74 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 }; 151 76 type->accept( finder ); 152 77 -
src/ResolvExpr/FindOpenVars.h
rdf8ba61a r8d182b1 17 17 18 18 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 19 #include "ResolvExpr/TypeEnvironment.h" // for AssertionSet, OpenVarSet20 19 21 class Type;22 20 namespace ast { 23 21 class Type; … … 25 23 26 24 namespace ResolvExpr { 27 // Updates open and closed variables and their associated assertions28 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );29 30 25 enum FirstMode { FirstClosed, FirstOpen }; 31 26 -
src/ResolvExpr/PolyCost.cc
rdf8ba61a r8d182b1 18 18 #include "AST/Type.hpp" 19 19 #include "AST/TypeEnvironment.hpp" 20 #include "Common/PassVisitor.h"21 #include "SymTab/Indexer.h" // for Indexer22 #include "SynTree/Type.h" // for TypeInstType, Type23 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment24 20 25 21 namespace ResolvExpr { 26 struct PolyCost {27 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );28 22 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 { 23 class PolyCost { 62 24 const ast::SymbolTable &symtab; 63 25 public: … … 65 27 const ast::TypeEnvironment &env_; 66 28 67 PolyCost _new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )29 PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 68 30 : symtab( symtab ), result( 0 ), env_( env ) {} 69 31 … … 86 48 const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 87 49 ) { 88 ast::Pass<PolyCost _new> costing( symtab, env );50 ast::Pass<PolyCost> costing( symtab, env ); 89 51 type->accept( costing ); 90 52 return (costing.core.result > 0) ? 1 : 0; -
src/ResolvExpr/PolyCost.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 }22 18 namespace ast { 23 19 class SymbolTable; … … 28 24 namespace ResolvExpr { 29 25 30 class TypeEnvironment;31 32 int polyCost( Type * type,33 const TypeEnvironment & env, const SymTab::Indexer & indexer );34 26 int polyCost( const ast::Type * type, 35 27 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); -
src/ResolvExpr/PtrsAssignable.cc
rdf8ba61a r8d182b1 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment23 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType24 #include "SynTree/Visitor.h" // for Visitor25 26 21 27 22 namespace ResolvExpr { 28 struct PtrsAssignable : public WithShortCircuiting {29 PtrsAssignable( const Type * dest, const TypeEnvironment &env );30 23 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 { 24 struct PtrsAssignable : public ast::WithShortCircuiting { 116 25 const ast::Type * dst; 117 26 const ast::TypeEnvironment & typeEnv; 118 27 int result; 119 28 120 PtrsAssignable _new( const ast::Type * dst, const ast::TypeEnvironment & env ) :29 PtrsAssignable( const ast::Type * dst, const ast::TypeEnvironment & env ) : 121 30 dst( dst ), typeEnv( env ), result( 0 ) {} 122 31 123 void previsit( Type * ) { visit_children = false; }32 void previsit( ast::Type * ) { visit_children = false; } 124 33 125 34 void postvisit( const ast::EnumInstType * ) { … … 153 62 return -1; 154 63 } else { 155 ast::Pass<PtrsAssignable _new> visitor( dst, env );64 ast::Pass<PtrsAssignable> visitor( dst, env ); 156 65 src->accept( visitor ); 157 66 return visitor.core.result; -
src/ResolvExpr/PtrsAssignable.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 18 namespace ast { 20 19 class Type; … … 24 23 namespace ResolvExpr { 25 24 26 class TypeEnvironment;27 28 int ptrsAssignable( const Type * src, const Type * dest,29 const TypeEnvironment & env );30 25 int ptrsAssignable( const ast::Type * src, const ast::Type * dst, 31 26 const ast::TypeEnvironment & env ); -
src/ResolvExpr/PtrsCastable.cc
rdf8ba61a r8d182b1 20 20 #include "AST/Type.hpp" 21 21 #include "AST/TypeEnvironment.hpp" 22 #include "Common/PassVisitor.h"23 22 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 24 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment25 #include "SymTab/Indexer.h" // for Indexer26 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype27 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType28 #include "SynTree/Visitor.h" // for Visitor29 23 30 24 namespace 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 } // if70 } //if71 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {72 if ( eqvClass->data.kind == TypeDecl::Ftype ) {73 return -1;74 } // if75 } // if76 } //if77 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 objectCast81 }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 } // if90 } // if91 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 } // if98 }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 }169 25 170 26 namespace { … … 199 55 } 200 56 201 class PtrsCastable _new: public ast::WithShortCircuiting {57 class PtrsCastable : public ast::WithShortCircuiting { 202 58 const ast::Type * dst; 203 59 const ast::TypeEnvironment & env; … … 206 62 int result; 207 63 208 PtrsCastable _new(64 PtrsCastable( 209 65 const ast::Type * d, const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 210 66 : dst( d ), env( e ), symtab( syms ), result( 0 ) {} … … 293 149 return objectCast( src, env, symtab ); 294 150 } else { 295 return ast::Pass<PtrsCastable _new>::read( src, dst, env, symtab );151 return ast::Pass<PtrsCastable>::read( src, dst, env, symtab ); 296 152 } 297 153 } -
src/ResolvExpr/PtrsCastable.hpp
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 }22 18 namespace ast { 23 19 class SymbolTable; … … 28 24 namespace ResolvExpr { 29 25 30 class TypeEnvironment;31 32 int ptrsCastable(33 const Type * src, const Type * dst,34 const TypeEnvironment & env, const SymTab::Indexer & indexer );35 26 int ptrsCastable( 36 27 const ast::Type * src, const ast::Type * dst, -
src/ResolvExpr/RenameVars.cc
rdf8ba61a r8d182b1 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 23 #include "Common/ScopedMap.h" 25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "RenameVars.h" 27 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...28 #include "SynTree/Expression.h" // for Expression29 #include "SynTree/Type.h" // for Type, TypeInstType, TraitInstType30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept31 26 32 27 #include "AST/Copy.hpp" … … 49 44 } 50 45 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 58 46 void nextUsage() { 59 47 ++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 in73 level++;74 }75 }76 }77 78 void closeLevel( Type * type ) {79 if ( !type->forall.empty() ) {80 nameMap.endScope();81 }82 48 } 83 49 … … 135 101 RenamingData renaming; 136 102 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*/ { 151 104 RenameMode mode; 152 105 … … 178 131 } // namespace 179 132 180 void renameTyVars( Type * t ) {181 PassVisitor<RenameVars_old> renamer;182 t->accept( renamer );183 }184 185 133 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { 186 ast::Pass<RenameVars _new> renamer;134 ast::Pass<RenameVars> renamer; 187 135 renamer.core.mode = mode; 188 136 if (mode == GEN_USAGE && reset) { -
src/ResolvExpr/RenameVars.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 #include <map> // for map20 #include <string> // for string21 22 #include "SynTree/SynTree.h" // for Visitor Nodes23 #include "SynTree/Visitor.h" // for Visitor24 25 18 namespace ast { 26 19 class Type; … … 28 21 29 22 namespace ResolvExpr { 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID31 void renameTyVars( Type * );32 33 23 enum RenameMode { 34 24 GEN_USAGE, // for type in VariableExpr -
src/ResolvExpr/ResolveTypeof.cc
rdf8ba61a r8d182b1 24 24 #include "AST/Type.hpp" 25 25 #include "AST/TypeEnvironment.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/utility.h" // for copy 28 27 #include "InitTweak/InitTweak.h" // for isConstExpr … … 30 29 #include "Resolver.h" // for resolveInVoidContext 31 30 #include "SymTab/Mangler.h" 32 #include "SynTree/Expression.h" // for Expression33 #include "SynTree/Mutator.h" // for Mutator34 #include "SynTree/Type.h" // for TypeofType, Type35 36 namespace SymTab {37 class Indexer;38 } // namespace SymTab39 31 40 32 namespace ResolvExpr { 41 namespace {42 #if 043 void44 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 #endif52 }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 075 std::cerr << "resolving typeof: ";76 typeofType->print( std::cerr );77 std::cerr << std::endl;78 #endif79 // pass on null expression80 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 type88 newType = tyExpr->type;89 tyExpr->type = nullptr;90 delete tyExpr;91 } else {92 // typeof wrapping expression93 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 case102 if ( isBasetypeof ) {103 // replace basetypeof(<enum>) by int104 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().val112 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;113 } else {114 newType->get_qualifiers().val |= oldQuals;115 }116 117 return newType;118 }119 33 120 34 namespace { 121 struct ResolveTypeof _new: public ast::WithShortCircuiting {35 struct ResolveTypeof : public ast::WithShortCircuiting { 122 36 const ResolveContext & context; 123 37 124 ResolveTypeof _new( const ResolveContext & context ) :38 ResolveTypeof( const ResolveContext & context ) : 125 39 context( context ) {} 126 40 … … 164 78 165 79 const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) { 166 ast::Pass< ResolveTypeof _new> mutator( context );80 ast::Pass< ResolveTypeof > mutator( context ); 167 81 return type->accept( mutator ); 168 82 } -
src/ResolvExpr/ResolveTypeof.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 class Type;19 namespace SymTab {20 class Indexer;21 } // namespace SymTab22 18 namespace ast { 23 19 class Type; … … 28 24 struct ResolveContext; 29 25 30 Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );31 26 const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & ); 32 27 const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & ); 33 28 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 & ); 35 30 } // namespace ResolvExpr 36 31 -
src/ResolvExpr/Resolver.cc
rdf8ba61a r8d182b1 19 19 #include <vector> // for vector 20 20 21 #include "Alternative.h" // for Alternative, AltList22 #include "AlternativeFinder.h" // for AlternativeFinder, resolveIn...23 21 #include "Candidate.hpp" 24 22 #include "CandidateFinder.hpp" … … 40 38 #include "Common/Eval.h" // for eval 41 39 #include "Common/Iterate.hpp" // for group_iterate 42 #include "Common/PassVisitor.h" // for PassVisitor43 40 #include "Common/SemanticError.h" // for SemanticError 44 41 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 45 42 #include "Common/ToString.hpp" // for toCString 43 #include "Common/UniqueName.h" // for UniqueName 46 44 #include "InitTweak/GenInit.h" 47 45 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt 48 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment49 #include "SymTab/Autogen.h" // for SizeType50 #include "SymTab/Indexer.h" // for Indexer51 46 #include "SymTab/Mangler.h" // for Mangler 52 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar...53 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr54 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit55 #include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt56 #include "SynTree/Type.h" // for Type, BasicType, PointerType57 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution58 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept59 47 #include "Tuples/Tuples.h" 60 48 #include "Validate/FindSpecialDecls.h" // for SizeType … … 63 51 64 52 namespace 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 it153 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 expression171 }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 it177 expr = castExpr->arg;178 castExpr->arg = nullptr;179 std::swap( expr->env, castExpr->env );180 delete castExpr;181 }182 }183 }184 } // namespace185 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 resolver191 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 0200 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 } // for207 } // if208 #endif209 210 // produce filtered list of alternatives211 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 candidates219 if ( candidates.empty() ) {220 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );221 }222 223 // search for cheapest candidate224 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 winner230 231 if ( c < 0 ) {232 // reset on new cheapest233 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 not238 if ( seen_undeleted ) continue;239 } else if ( ! seen_undeleted ) {240 // replace list of equivalent-cost deleted expressions with one non-deleted241 winners.clear();242 seen_undeleted = true;243 }244 }245 246 winners.emplace_back( std::move( candidates[i] ) );247 }248 249 // promote alternative.cvtCost to .cost250 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost251 for ( Alternative& winner : winners ) {252 winner.cost = winner.cvtCost;253 }254 255 // produce ambiguous errors, if applicable256 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 choice266 Alternative& choice = winners.front();267 268 // fail on only expression deleted269 if ( ! seen_undeleted ) {270 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );271 }272 273 // xxx - check for ambiguous expressions274 275 // output selected choice276 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 messages280 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 expressions293 return true;294 }295 } // namespace296 297 // used in resolveTypeof298 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 0305 // interpretations, an exception has already been thrown.306 assertf( expr, "expected a non-null expression." );307 308 CastExpr * untyped = new CastExpr( expr ); // cast to void309 untyped->location = expr->location;310 311 // set up and resolve expression cast to void312 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 expression319 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 program323 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 purposes343 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 } // if362 }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 candidates383 findKindExpression( expr, indexer, "with statement", isStructOrUnion );384 385 // if with expression might be impure, create a temporary so that it is evaluated once386 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 them393 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 the407 // 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 that422 // 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 object424 // declarations in the return and parameter types. So each value of initContext is425 // 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, since430 // the enum type is still incomplete at this point. Use signed int instead.431 // TODO: BasicType::SignedInt may not longer be true432 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 0453 std::cerr << "resolver visiting functiondecl ";454 functionDecl->print( std::cerr );455 std::cerr << std::endl;456 #endif457 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 up463 // later passes.464 // xxx - it might be necessary to somehow keep the information from this environment, but I465 // 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 enums478 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 } // if515 516 if ( forStmt->increment ) {517 findVoidExpression( forStmt->increment, indexer );518 } // if519 }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 goto550 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement551 if ( branchStmt->computedTarget ) {552 // computed goto argument is void *553 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );554 } // if555 } // if556 }557 558 void Resolver_old::previsit( ReturnStmt * returnStmt ) {559 visit_children = false;560 if ( returnStmt->expr ) {561 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );562 } // if563 }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 604 53 template< typename iterator_t > 605 54 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) { … … 611 60 } 612 61 613 void Resolver_old::previsit( WaitForStmt * stmt ) {614 visit_children = false;615 616 // Resolve all clauses first617 for( auto& clause : stmt->clauses ) {618 619 TypeEnvironment env;620 AlternativeFinder funcFinder( indexer, env );621 622 // Find all alternatives for a function in canonical form623 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 form638 std::vector< AlternativeFinder > argAlternatives;639 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );640 641 // List all combinations of arguments642 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 parameters650 // not the other way around because we have more arguments than parameters651 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 function676 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 alternative679 for ( auto & argsList : possibilities ) {680 681 try {682 // Declare data structures need for resolution683 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 parameter688 // list are still considered open.689 resultEnv.add( function->forall );690 691 // Load type variables from arguemnts into one shared space692 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );693 694 // Make sure we don't widen any existing bindings695 resultEnv.forbidWidening();696 697 // Find any unbound type variables698 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 parameter706 // The order is important707 for( auto & arg : argsList ) {708 709 // Ignore non-mutex arguments710 if( !advance_to_mutex( param, param_end ) ) {711 // We ran out of parameters but still have arguments712 // this function doesn't match713 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 scope719 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {720 // Type doesn't match721 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 missing738 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 left745 // this function doesn't match746 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 environments752 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 later758 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 arguments773 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 destruction781 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 IfStmt787 // Resolve the statments normally788 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 now795 // Resolve the conditions as if it were an IfStmt796 // Resolve the statments normally797 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 IfStmt804 // Resolve the statments normally805 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 cursor821 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 initialized826 currentObject.setNext( initExpr->get_designation() );827 828 // discard InitExpr wrapper and retain relevant pieces829 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 function833 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not834 // 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 resolver839 // 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 express864 singleInit->value = newExpr;865 866 // move cursor to next object in preparation for next initializer867 currentObject.increment();868 }869 870 void Resolver_old::previsit( ListInit * listInit ) {871 visit_children = false;872 // move cursor into brace-enclosed initializer-list873 currentObject.enterListInit();874 // xxx - fix this so that the list isn't copied, iterator should be used to change current875 // element876 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 current879 // 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-list886 listInit->get_designations() = newDesignations; // xxx - memory management887 currentObject.exitListInit();888 889 // xxx - this part has not be folded into CurrentObject yet890 // } 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 initContext894 // 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 context899 // Parent::visit( listInit );900 // }901 // } else {902 }903 904 // ConstructorInit - fall back on C-style initializer905 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {906 // could not find valid constructor, or found an intrinsic constructor907 // fall back on C-style initializer908 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 function916 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 ConstructorInit933 maybeAccept( ctorInit->ctor, *visitor );934 maybeAccept( ctorInit->dtor, *visitor );935 936 // found a constructor - can get rid of C-style initializer937 delete ctorInit->init;938 ctorInit->init = nullptr;939 940 // intrinsic single parameter constructors and destructors do nothing. Since this was941 // implicitly generated, there's no way for it to have side effects, so get rid of it942 // 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 the956 // // second argument from the ctor call, since957 // 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 971 62 namespace { 972 63 /// 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> { 974 65 const ast::DeletedExpr * result = nullptr; 975 66 … … 989 80 }; 990 81 991 struct ResolveDesignators _newfinal : public ast::WithShortCircuiting {82 struct ResolveDesignators final : public ast::WithShortCircuiting { 992 83 ResolveContext& context; 993 84 bool result = false; 994 85 995 ResolveDesignators _new( ResolveContext& _context ): context{_context} {};86 ResolveDesignators( ResolveContext& _context ): context{_context} {}; 996 87 997 88 void previsit( const ast::Node * ) { … … 1022 113 /// Check if this expression is or includes a deleted expression 1023 114 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) { 1024 return ast::Pass<DeleteFinder _new>::read( expr );115 return ast::Pass<DeleteFinder>::read( expr ); 1025 116 } 1026 117 … … 1112 203 1113 204 /// Strips extraneous casts out of an expression 1114 struct StripCasts _newfinal {205 struct StripCasts final { 1115 206 const ast::Expr * postvisit( const ast::CastExpr * castExpr ) { 1116 207 if ( … … 1126 217 1127 218 static void strip( ast::ptr< ast::Expr > & expr ) { 1128 ast::Pass< StripCasts _new> stripper;219 ast::Pass< StripCasts > stripper; 1129 220 expr = expr->accept( stripper ); 1130 221 } … … 1160 251 expr.get_and_mutate()->env = std::move( newenv ); 1161 252 // remove unncecessary casts 1162 StripCasts _new::strip( expr );253 StripCasts::strip( expr ); 1163 254 } 1164 255 … … 1277 368 } 1278 369 1279 class Resolver _newfinal370 class Resolver final 1280 371 : public ast::WithSymbolTable, public ast::WithGuards, 1281 public ast::WithVisitorRef<Resolver _new>, public ast::WithShortCircuiting,372 public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting, 1282 373 public ast::WithStmtsToAdd<> { 1283 374 … … 1285 376 ast::CurrentObject currentObject; 1286 377 // for work previously in GenInit 1287 static InitTweak::ManagedTypes _newmanagedTypes;378 static InitTweak::ManagedTypes managedTypes; 1288 379 ResolveContext context; 1289 380 … … 1292 383 public: 1293 384 static size_t traceId; 1294 Resolver _new( const ast::TranslationGlobal & global ) :385 Resolver( const ast::TranslationGlobal & global ) : 1295 386 ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd), 1296 387 context{ symtab, global } {} 1297 Resolver _new( const ResolveContext & context ) :388 Resolver( const ResolveContext & context ) : 1298 389 ast::WithSymbolTable{ context.symtab }, 1299 390 context{ symtab, context.global } {} … … 1336 427 bool on_error(ast::ptr<ast::Decl> & decl); 1337 428 }; 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; 1341 432 1342 433 void resolve( ast::TranslationUnit& translationUnit ) { 1343 ast::Pass< Resolver _new>::run( translationUnit, translationUnit.global );434 ast::Pass< Resolver >::run( translationUnit, translationUnit.global ); 1344 435 } 1345 436 … … 1348 439 ) { 1349 440 assert( ctorInit ); 1350 ast::Pass< Resolver _new> resolver( context );441 ast::Pass< Resolver > resolver( context ); 1351 442 return ctorInit->accept( resolver ); 1352 443 } … … 1356 447 ) { 1357 448 assert( stmtExpr ); 1358 ast::Pass< Resolver _new> resolver( context );449 ast::Pass< Resolver > resolver( context ); 1359 450 auto ret = mutate(stmtExpr->accept(resolver)); 1360 451 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult(); … … 1398 489 } 1399 490 1400 const ast::FunctionDecl * Resolver _new::previsit( const ast::FunctionDecl * functionDecl ) {491 const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) { 1401 492 GuardValue( functionReturn ); 1402 493 … … 1472 563 } 1473 564 1474 const ast::FunctionDecl * Resolver _new::postvisit( const ast::FunctionDecl * functionDecl ) {565 const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) { 1475 566 // default value expressions have an environment which shouldn't be there and trips up 1476 567 // later passes. … … 1500 591 } 1501 592 1502 const ast::ObjectDecl * Resolver _new::previsit( const ast::ObjectDecl * objectDecl ) {593 const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) { 1503 594 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()], 1504 595 // class-variable `initContext` is changed multiple times because the LHS is analyzed … … 1539 630 // constructed objects cannot be designated 1540 631 if ( InitTweak::isDesignated( mutDecl->init ) ) { 1541 ast::Pass<ResolveDesignators _new> res( context );632 ast::Pass<ResolveDesignators> res( context ); 1542 633 maybe_accept( mutDecl->init.get(), res ); 1543 634 if ( !res.core.result ) { … … 1559 650 } 1560 651 1561 void Resolver _new::previsit( const ast::AggregateDecl * _aggDecl ) {652 void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) { 1562 653 auto aggDecl = mutate(_aggDecl); 1563 654 assertf(aggDecl == _aggDecl, "type declarations must be unique"); … … 1571 662 } 1572 663 1573 void Resolver _new::previsit( const ast::StructDecl * structDecl ) {664 void Resolver::previsit( const ast::StructDecl * structDecl ) { 1574 665 previsit(static_cast<const ast::AggregateDecl *>(structDecl)); 1575 666 managedTypes.handleStruct(structDecl); 1576 667 } 1577 668 1578 void Resolver _new::previsit( const ast::EnumDecl * ) {669 void Resolver::previsit( const ast::EnumDecl * ) { 1579 670 // in case we decide to allow nested enums 1580 671 GuardValue( inEnumDecl ); … … 1583 674 } 1584 675 1585 const ast::StaticAssertDecl * Resolver _new::previsit(676 const ast::StaticAssertDecl * Resolver::previsit( 1586 677 const ast::StaticAssertDecl * assertDecl 1587 678 ) { … … 1603 694 } 1604 695 1605 const ast::ArrayType * Resolver _new::previsit( const ast::ArrayType * at ) {696 const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) { 1606 697 return handlePtrType( at, context ); 1607 698 } 1608 699 1609 const ast::PointerType * Resolver _new::previsit( const ast::PointerType * pt ) {700 const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) { 1610 701 return handlePtrType( pt, context ); 1611 702 } 1612 703 1613 const ast::ExprStmt * Resolver _new::previsit( const ast::ExprStmt * exprStmt ) {704 const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) { 1614 705 visit_children = false; 1615 706 assertf( exprStmt->expr, "ExprStmt has null expression in resolver" ); … … 1619 710 } 1620 711 1621 const ast::AsmExpr * Resolver _new::previsit( const ast::AsmExpr * asmExpr ) {712 const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) { 1622 713 visit_children = false; 1623 714 … … 1628 719 } 1629 720 1630 const ast::AsmStmt * Resolver _new::previsit( const ast::AsmStmt * asmStmt ) {721 const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) { 1631 722 visitor->maybe_accept( asmStmt, &ast::AsmStmt::input ); 1632 723 visitor->maybe_accept( asmStmt, &ast::AsmStmt::output ); … … 1635 726 } 1636 727 1637 const ast::IfStmt * Resolver _new::previsit( const ast::IfStmt * ifStmt ) {728 const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) { 1638 729 return ast::mutate_field( 1639 730 ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) ); 1640 731 } 1641 732 1642 const ast::WhileDoStmt * Resolver _new::previsit( const ast::WhileDoStmt * whileDoStmt ) {733 const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) { 1643 734 return ast::mutate_field( 1644 735 whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) ); 1645 736 } 1646 737 1647 const ast::ForStmt * Resolver _new::previsit( const ast::ForStmt * forStmt ) {738 const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) { 1648 739 if ( forStmt->cond ) { 1649 740 forStmt = ast::mutate_field( … … 1659 750 } 1660 751 1661 const ast::SwitchStmt * Resolver _new::previsit( const ast::SwitchStmt * switchStmt ) {752 const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) { 1662 753 GuardValue( currentObject ); 1663 754 switchStmt = ast::mutate_field( … … 1668 759 } 1669 760 1670 const ast::CaseClause * Resolver _new::previsit( const ast::CaseClause * caseStmt ) {761 const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) { 1671 762 if ( caseStmt->cond ) { 1672 763 std::deque< ast::InitAlternative > initAlts = currentObject.getOptions(); … … 1689 780 } 1690 781 1691 const ast::BranchStmt * Resolver _new::previsit( const ast::BranchStmt * branchStmt ) {782 const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) { 1692 783 visit_children = false; 1693 784 // must resolve the argument of a computed goto … … 1702 793 } 1703 794 1704 const ast::ReturnStmt * Resolver _new::previsit( const ast::ReturnStmt * returnStmt ) {795 const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) { 1705 796 visit_children = false; 1706 797 if ( returnStmt->expr ) { … … 1712 803 } 1713 804 1714 const ast::ThrowStmt * Resolver _new::previsit( const ast::ThrowStmt * throwStmt ) {805 const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) { 1715 806 visit_children = false; 1716 807 if ( throwStmt->expr ) { … … 1727 818 } 1728 819 1729 const ast::CatchClause * Resolver _new::previsit( const ast::CatchClause * catchClause ) {820 const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) { 1730 821 // Until we are very sure this invarent (ifs that move between passes have then) 1731 822 // holds, check it. This allows a check for when to decode the mangling. … … 1743 834 } 1744 835 1745 const ast::CatchClause * Resolver _new::postvisit( const ast::CatchClause * catchClause ) {836 const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) { 1746 837 // Decode the catchStmt so everything is stored properly. 1747 838 const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>(); … … 1758 849 } 1759 850 1760 const ast::WaitForStmt * Resolver _new::previsit( const ast::WaitForStmt * stmt ) {851 const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) { 1761 852 visit_children = false; 1762 853 … … 2023 1114 } 2024 1115 2025 const ast::WithStmt * Resolver _new::previsit( const ast::WithStmt * withStmt ) {1116 const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) { 2026 1117 auto mutStmt = mutate(withStmt); 2027 1118 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore); … … 2029 1120 } 2030 1121 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) { 2032 1123 for (auto & expr : exprs) { 2033 1124 // only struct- and union-typed expressions are viable candidates … … 2055 1146 2056 1147 2057 const ast::SingleInit * Resolver _new::previsit( const ast::SingleInit * singleInit ) {1148 const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) { 2058 1149 visit_children = false; 2059 1150 // resolve initialization using the possibilities as determined by the `currentObject` … … 2104 1195 } 2105 1196 2106 const ast::ListInit * Resolver _new::previsit( const ast::ListInit * listInit ) {1197 const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) { 2107 1198 // move cursor into brace-enclosed initializer-list 2108 1199 currentObject.enterListInit( listInit->location ); … … 2127 1218 } 2128 1219 2129 const ast::ConstructorInit * Resolver _new::previsit( const ast::ConstructorInit * ctorInit ) {1220 const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) { 2130 1221 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor ); 2131 1222 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor ); … … 2149 1240 2150 1241 // 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) { 2152 1243 if (auto functionDecl = decl.as<ast::FunctionDecl>()) { 2153 1244 // xxx - can intrinsic gen ever fail? -
src/ResolvExpr/Resolver.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 18 #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 SymTab31 19 32 20 namespace ast { … … 45 33 46 34 namespace ResolvExpr { 47 /// Checks types and binds syntactic constructs to typed representations48 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 nullptr57 DeletedExpr * findDeletedExpr( Expression * expr );58 /// Resolves with-stmts and with-clauses on functions59 void resolveWithExprs( std::list< Declaration * > & translationUnit );60 35 61 36 /// Helper Type: Passes around information between various sub-calls. -
src/ResolvExpr/SatisfyAssertions.cpp
rdf8ba61a r8d182b1 46 46 #include "SymTab/Mangler.h" 47 47 48 49 50 48 namespace ResolvExpr { 51 49 -
src/ResolvExpr/SpecCost.cc
rdf8ba61a r8d182b1 16 16 #include <cassert> 17 17 #include <limits> 18 #include <list>19 18 #include <type_traits> 20 19 21 20 #include "AST/Pass.hpp" 22 21 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Expression.h"26 #include "SynTree/Type.h"27 22 28 23 namespace ResolvExpr { 29 24 30 /// Counts specializations in a type 31 class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> { 32 int count = -1; ///< specialization count (-1 for none) 25 namespace { 33 26 34 public: 35 int get_count() const { return count >= 0 ? count : 0; } 27 const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) { 28 return expr->result.get(); 29 } 36 30 37 // mark specialization of base type 38 void postvisit(PointerType*) { if ( count >= 0 ) ++count; } 31 const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) { 32 return type.get(); 33 } 39 34 40 // mark specialization of base type41 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }42 43 // mark specialization of base type44 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 list51 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 ->parameters61 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 set66 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;67 // already visited children68 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 parameters85 void previsit(StructInstType* sty) {86 count = minover( sty->parameters );87 }88 89 // look for polymorphic parameters90 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 variables96 void postvisit(TypeInstType*) { count = 0; }97 98 // take minimal specialization over elements99 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize100 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 type113 int specCost( Type* ty ) {114 PassVisitor<CountSpecs> counter;115 maybeAccept( ty, *counter.pass.visitor );116 return counter.pass.get_count();117 }118 119 namespace {120 35 /// The specialization counter inner class. 121 36 class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> { … … 131 46 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 132 47 133 #warning Should use a standard maybe_accept134 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 141 48 // Update the minimum to the new lowest non-none value. 142 49 template<typename T> … … 144 51 for ( const auto & node : list ) { 145 52 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 147 59 if ( count != -1 && count < minimum ) minimum = count; 148 60 } … … 157 69 } 158 70 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 170 71 public: 171 int get_count() const { return 0 <= count ? count : 0; }72 int result() const { return 0 <= count ? count : 0; } 172 73 173 74 // Mark specialization of base type. … … 215 116 216 117 int 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 ); 223 119 } 224 120 -
src/ResolvExpr/Unify.cc
rdf8ba61a r8d182b1 33 33 #include "AST/TypeEnvironment.hpp" 34 34 #include "Common/Eval.h" // for eval 35 #include "Common/PassVisitor.h" // for PassVisitor36 35 #include "CommonType.hpp" // for commonType 37 36 #include "FindOpenVars.h" // for findOpenVars 38 37 #include "SpecCost.hpp" // for SpecCost 39 #include "SynTree/LinkageSpec.h" // for C40 #include "SynTree/Constant.h" // for Constant41 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Declarati...42 #include "SynTree/Expression.h" // for TypeExpr, Expression, ConstantExpr43 #include "SynTree/Mutator.h" // for Mutator44 #include "SynTree/Type.h" // for Type, TypeInstType, FunctionType45 #include "SynTree/Visitor.h" // for Visitor46 38 #include "Tuples/Tuples.h" // for isTtype 47 #include "TypeEnvironment.h" // for EqvClass, AssertionSet, OpenVarSet48 39 #include "typeops.h" // for flatten, occurs 49 40 … … 52 43 } 53 44 54 namespace SymTab {55 class Indexer;56 } // namespace SymTab57 58 45 // #define DEBUG 59 46 60 47 namespace 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 } // if70 commonTypes.push_back( commonType );71 } // for72 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 } // if84 }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; // inherited115 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 closedVars136 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 they142 // have free variables that can unify143 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 }151 48 152 49 bool typesCompatible( … … 165 62 166 63 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;183 64 } 184 65 … … 220 101 } 221 102 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 } // if231 return true;232 } else {233 return false;234 } // if235 }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 DEBUG246 TypeEnvironment debugEnv( env );247 #endif248 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 } // if259 if ( var2 ) {260 entry2 = openVars.find( var2->get_name() );261 } // if262 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 } // if282 #ifdef DEBUG283 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 #endif296 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 DEBUG309 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 #endif315 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {316 #ifdef DEBUG317 std::cerr << "unifyInexact: no exact unification found" << std::endl;318 #endif319 if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {320 common->tq = tq1.unify( tq2 );321 #ifdef DEBUG322 std::cerr << "unifyInexact: common type is ";323 common->print( std::cerr );324 std::cerr << std::endl;325 #endif326 result = true;327 } else {328 #ifdef DEBUG329 std::cerr << "unifyInexact: no common type found" << std::endl;330 #endif331 result = false;332 } // if333 } 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 } // if342 } else {343 common = type1->clone();344 common->tq = tq1.unify( tq2 );345 result = true;346 } // if347 } // if348 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 } // if365 }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 } // if372 }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 } // for380 } // for381 }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 } // if389 }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 } // if397 }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 VLA402 // and must both have a dimension expression or not have a dimension403 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.6410 // two array types with size specifiers that are integer constant expressions are411 // compatible if both size specifiers have the same constant value412 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 different418 return;419 }420 }421 }422 423 result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );424 } // if425 }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 tuple432 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 parameter446 // 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 unify449 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 unify452 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 } // if456 } // for457 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype458 if ( list1Begin != list1End ) {459 // try unifying empty tuple type with ttype460 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 ttype466 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 } // if473 }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 different478 /// 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 type486 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 structure519 // 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 errors526 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 used536 markAssertions( haveAssertions, needAssertions, functionType );537 markAssertions( haveAssertions, needAssertions, otherFunction );538 539 result = true;540 } // if541 } // if542 } // if543 } // if544 }545 546 template< typename RefType >547 void Unify_old::handleRefType( RefType *inst, Type *other ) {548 // check that other type is compatible and named the same549 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 same556 handleRefType( inst, other );557 if ( ! result ) return;558 // Check that parameters of types unify, if any559 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 break577 } else if ( tupleParam ) {578 // bundle other parameters into tuple to match579 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 break593 } else if ( otherTupleParam ) {594 // bundle parameters into tuple to match other595 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 break609 }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 last617 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 } // if653 }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 parameter664 // 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 unify667 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 unify670 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 } // if674 675 } // for676 if ( list1Begin != list1End ) {677 // try unifying empty tuple type with ttype678 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 ttype684 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 } // if691 }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 } // if708 }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 } // for732 return new TupleType( Type::Qualifiers(), types );733 }734 }735 736 103 namespace { 737 104 /// Replaces ttype variables with their bound types. 738 105 /// If this isn't done when satifying ttype assertions, then argument lists can have 739 106 /// 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 { 741 108 ast::TypeEnvironment & tenv; 742 109 743 TtypeExpander _new( ast::TypeEnvironment & env ) : tenv( env ) {}110 TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {} 744 111 745 112 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) { … … 761 128 dst.reserve( src.size() ); 762 129 for ( const auto & d : src ) { 763 ast::Pass<TtypeExpander _new> expander{ env };130 ast::Pass<TtypeExpander> expander{ env }; 764 131 // TtypeExpander pass is impure (may mutate nodes in place) 765 132 // need to make nodes shared to prevent accidental mutation … … 901 268 } 902 269 903 class Unify _newfinal : public ast::WithShortCircuiting {270 class Unify final : public ast::WithShortCircuiting { 904 271 const ast::Type * type2; 905 272 ast::TypeEnvironment & tenv; … … 912 279 bool result; 913 280 914 Unify _new(281 Unify( 915 282 const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need, 916 283 ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen ) … … 1239 606 if ( ! tuple2 ) return; 1240 607 1241 ast::Pass<TtypeExpander _new> expander{ tenv };608 ast::Pass<TtypeExpander> expander{ tenv }; 1242 609 1243 610 const ast::Type * flat = tuple->accept( expander ); … … 1267 634 }; 1268 635 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 1270 638 bool unify( 1271 639 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, … … 1311 679 return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen ); 1312 680 } else { 1313 return ast::Pass<Unify _new>::read(681 return ast::Pass<Unify>::read( 1314 682 type1, type2, env, need, have, open, widen ); 1315 683 } -
src/ResolvExpr/Unify.h
rdf8ba61a r8d182b1 20 20 #include "AST/Node.hpp" // for ptr 21 21 #include "AST/TypeEnvironment.hpp" // for TypeEnvironment, AssertionSet, OpenVarSet 22 #include "Common/utility.h" // for deleteAll23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data24 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet25 22 #include "WidenMode.h" // for WidenMode 26 27 class Type;28 class TypeInstType;29 namespace SymTab {30 class Indexer;31 }32 23 33 24 namespace ast { … … 37 28 38 29 namespace 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 }57 30 58 31 bool unify( … … 85 58 const ast::TypeEnvironment & env = {} ); 86 59 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 );90 60 /// Creates or extracts the type represented by returns in a `FunctionType`. 91 61 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ); -
src/ResolvExpr/module.mk
rdf8ba61a r8d182b1 18 18 ResolvExpr/AdjustExprType.cc \ 19 19 ResolvExpr/AdjustExprType.hpp \ 20 ResolvExpr/Alternative.cc \21 ResolvExpr/AlternativeFinder.cc \22 ResolvExpr/AlternativeFinder.h \23 ResolvExpr/Alternative.h \24 20 ResolvExpr/Candidate.cpp \ 25 21 ResolvExpr/CandidateFinder.cpp \ … … 35 31 ResolvExpr/CurrentObject.cc \ 36 32 ResolvExpr/CurrentObject.h \ 37 ResolvExpr/ExplodedActual.cc \38 ResolvExpr/ExplodedActual.h \39 33 ResolvExpr/ExplodedArg.cpp \ 40 34 ResolvExpr/ExplodedArg.hpp \ 41 35 ResolvExpr/FindOpenVars.cc \ 42 36 ResolvExpr/FindOpenVars.h \ 43 ResolvExpr/Occurs.cc \44 37 ResolvExpr/PolyCost.cc \ 45 38 ResolvExpr/PolyCost.hpp \ … … 50 43 ResolvExpr/RenameVars.cc \ 51 44 ResolvExpr/RenameVars.h \ 52 ResolvExpr/ResolveAssertions.cc \53 ResolvExpr/ResolveAssertions.h \54 45 ResolvExpr/Resolver.cc \ 55 46 ResolvExpr/Resolver.h \ … … 61 52 ResolvExpr/SpecCost.cc \ 62 53 ResolvExpr/SpecCost.hpp \ 63 ResolvExpr/TypeEnvironment.cc \64 ResolvExpr/TypeEnvironment.h \65 54 ResolvExpr/typeops.h \ 66 55 ResolvExpr/Unify.cc \ … … 69 58 70 59 SRC += $(SRC_RESOLVEXPR) \ 71 ResolvExpr/AlternativePrinter.cc \72 ResolvExpr/AlternativePrinter.h \73 60 ResolvExpr/CandidatePrinter.cpp \ 74 61 ResolvExpr/CandidatePrinter.hpp \ -
src/ResolvExpr/typeops.h
rdf8ba61a r8d182b1 19 19 20 20 #include "AST/Type.hpp" 21 #include "SynTree/Type.h"22 23 namespace SymTab {24 class Indexer;25 }26 21 27 22 namespace ResolvExpr { … … 52 47 std::copy( i.begin(), i.end(), inserter ); 53 48 *out++ = result; 54 }55 }56 57 // in Occurs.cc58 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 types71 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();79 49 } 80 50 } … … 120 90 return tupleFromTypes( tys.begin(), tys.end() ); 121 91 } 122 123 // in TypeEnvironment.cc124 bool isFtype( const Type * type );125 92 } // namespace ResolvExpr 126 93 -
src/SymTab/Demangle.cc
rdf8ba61a r8d182b1 17 17 #include <sstream> 18 18 19 #include "AST/Pass.hpp" 20 #include "AST/Type.hpp" 19 21 #include "CodeGen/GenType.h" 20 22 #include "CodeGen/OperatorTable.h" 21 #include "Common/PassVisitor.h"22 23 #include "Common/utility.h" // isPrefix 23 24 #include "Mangler.h" 24 #include "SynTree/Type.h"25 #include "SynTree/Declaration.h"26 25 27 26 #define DEBUG … … 32 31 #endif 33 32 33 namespace Mangle { 34 34 35 namespace { 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 37 struct Demangler { 38 private: 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; 43 public: 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 70 Demangler::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 108 bool 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 121 bool 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 131 bool 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 141 bool 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 163 ast::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 184 ast::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 200 ast::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 207 ast::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 221 ast::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 228 ast::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 235 ast::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 242 ast::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 250 ast::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; 228 272 } 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 295 bool 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 304 std::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 616 318 617 319 extern "C" { 618 320 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); 620 322 return strdup(demangleName.c_str()); 621 323 } -
src/SymTab/FixFunction.cc
rdf8ba61a r8d182b1 22 22 #include "AST/Type.hpp" 23 23 #include "Common/utility.h" // for copy 24 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarati...25 #include "SynTree/Expression.h" // for Expression26 #include "SynTree/Type.h" // for ArrayType, PointerType, Type, Basic...27 24 28 25 namespace 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 object58 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 error69 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 }103 26 104 27 namespace { 105 struct FixFunction _newfinal : public ast::WithShortCircuiting {28 struct FixFunction final : public ast::WithShortCircuiting { 106 29 bool isVoid = false; 107 30 … … 147 70 148 71 const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) { 149 ast::Pass< FixFunction _new> fixer;72 ast::Pass< FixFunction > fixer; 150 73 dwt = dwt->accept( fixer ); 151 74 isVoid |= fixer.core.isVoid; … … 154 77 155 78 const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ) { 156 ast::Pass< FixFunction _new> fixer;79 ast::Pass< FixFunction > fixer; 157 80 type = type->accept( fixer ); 158 81 isVoid |= fixer.core.isVoid; -
src/SymTab/FixFunction.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include "Common/PassVisitor.h" // for PassVisitor19 #include "SynTree/SynTree.h" // for Types20 21 18 namespace ast { 22 19 class DeclWithType; … … 25 22 26 23 namespace SymTab { 27 /// Replaces function and array types by equivalent pointer types. Returns true if type is28 /// void29 bool fixFunction( DeclarationWithType *& );30 31 24 /// Returns declaration with function and array types replaced by equivalent pointer types. 32 25 /// Sets isVoid to true if type is void -
src/SymTab/GenImplicitCall.cpp
rdf8ba61a r8d182b1 32 32 template< typename OutIter > 33 33 ast::ptr< ast::Stmt > genCall( 34 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,34 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 35 35 const CodeLocation & loc, const std::string & fname, OutIter && out, 36 36 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward ); … … 42 42 template< typename OutIter > 43 43 ast::ptr< ast::Stmt > genScalarCall( 44 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,44 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 45 45 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 46 46 const ast::Type * addCast = nullptr … … 98 98 template< typename OutIter > 99 99 void genArrayCall( 100 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,100 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 101 101 const CodeLocation & loc, const std::string & fname, OutIter && out, 102 102 const ast::ArrayType * array, const ast::Type * addCast = nullptr, … … 167 167 template< typename OutIter > 168 168 ast::ptr< ast::Stmt > genCall( 169 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,169 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 170 170 const CodeLocation & loc, const std::string & fname, OutIter && out, 171 171 const ast::Type * type, const ast::Type * addCast, LoopDirection forward … … 185 185 186 186 ast::ptr< ast::Stmt > genImplicitCall( 187 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,187 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 188 188 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 189 189 LoopDirection forward -
src/SymTab/GenImplicitCall.hpp
rdf8ba61a r8d182b1 26 26 /// dstParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. 27 27 ast::ptr<ast::Stmt> genImplicitCall( 28 InitTweak::InitExpander _new& srcParam, const ast::Expr * dstParam,28 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam, 29 29 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 30 30 LoopDirection forward = LoopForward -
src/SymTab/Mangler.cc
rdf8ba61a r8d182b1 24 24 #include "AST/Pass.hpp" 25 25 #include "CodeGen/OperatorTable.h" // for OperatorInfo, operatorLookup 26 #include "Common/PassVisitor.h"27 26 #include "Common/ToString.hpp" // for toCString 28 27 #include "Common/SemanticError.h" // for SemanticError 29 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment30 #include "SynTree/LinkageSpec.h" // for Spec, isOverridable, AutoGen, Int...31 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType32 #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 identifier39 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 constructed69 typedef std::map< std::string, std::pair< int, int > > VarMapType;70 VarMapType varNums; ///< Map of type variables to indices71 int nextVarNum; ///< Next type variable index72 bool isTopLevel; ///< Is the Mangler at the top level73 bool mangleOverridable; ///< Specially mangle overridable built-in methods74 bool typeMode; ///< Produce a unique mangled name for a type75 bool mangleGenericParams; ///< Include generic parameters in name mangling if true76 bool inFunctionType = false; ///< Include type qualifiers if false.77 bool inQualifiedType = false; ///< Add start/end delimiters around qualified type78 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_old89 } // namespace90 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 } // if128 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 } // if135 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 mangling139 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 change145 assert( false && "unknown overrideable linkage" );146 } // if147 }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 pointers173 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 dimension179 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 different209 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 they261 // 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 } // if265 }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 type296 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 type303 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 be310 // 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 deeply312 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed313 // 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 } // for323 }324 325 void Mangler_old::printQualifiers( const Type * type ) {326 // skip if not including qualifiers327 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 } // switch346 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 } // for354 } // for355 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 } // if360 if ( ! inFunctionType ) {361 // these qualifiers do not distinguish the outermost type of a function parameter362 if ( type->get_const() ) {363 mangleName += Encoding::qualifiers.at(Type::Const);364 } // if365 if ( type->get_volatile() ) {366 mangleName += Encoding::qualifiers.at(Type::Volatile);367 } // if368 // Removed due to restrict not affecting function compatibility in GCC369 // if ( type->get_isRestrict() ) {370 // mangleName += "E";371 // } // if372 if ( type->get_atomic() ) {373 mangleName += Encoding::qualifiers.at(Type::Atomic);374 } // if375 }376 if ( type->get_mutex() ) {377 mangleName += Encoding::qualifiers.at(Type::Mutex);378 } // if379 if ( inFunctionType ) {380 // turn off inFunctionType so that types can be differentiated for nested qualifiers381 GuardValue( inFunctionType );382 inFunctionType = false;383 }384 }385 } // namespace386 } // namespace Mangler387 } // namespace SymTab388 28 389 29 namespace Mangle { 390 30 namespace { 391 31 /// 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; 395 35 396 36 void previsit( const ast::Node * ) { visit_children = false; } … … 432 72 433 73 private: 434 Mangler _new( bool mangleOverridable, bool typeMode, bool mangleGenericParams,74 Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 435 75 int nextVarNum, const VarMapType& varNums ); 436 friend class ast::Pass<Mangler _new>;76 friend class ast::Pass<Mangler>; 437 77 438 78 private: … … 441 81 442 82 void printQualifiers( const ast::Type *type ); 443 }; // Mangler _new83 }; // Mangler 444 84 } // namespace 445 85 446 86 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 ); 448 88 } 449 89 450 90 namespace { 451 Mangler _new::Mangler_new( Mangle::Mode mode )91 Mangler::Mangler( Mangle::Mode mode ) 452 92 : nextVarNum( 0 ), isTopLevel( true ), 453 93 mangleOverridable ( ! mode.no_overrideable ), … … 455 95 mangleGenericParams( ! mode.no_generic_params ) {} 456 96 457 Mangler _new::Mangler_new( bool mangleOverridable, bool typeMode, bool mangleGenericParams,97 Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 458 98 int nextVarNum, const VarMapType& varNums ) 459 99 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), … … 461 101 mangleGenericParams( mangleGenericParams ) {} 462 102 463 void Mangler _new::mangleDecl( const ast::DeclWithType * decl ) {103 void Mangler::mangleDecl( const ast::DeclWithType * decl ) { 464 104 bool wasTopLevel = isTopLevel; 465 105 if ( isTopLevel ) { … … 491 131 } 492 132 493 void Mangler _new::postvisit( const ast::ObjectDecl * decl ) {133 void Mangler::postvisit( const ast::ObjectDecl * decl ) { 494 134 mangleDecl( decl ); 495 135 } 496 136 497 void Mangler _new::postvisit( const ast::FunctionDecl * decl ) {137 void Mangler::postvisit( const ast::FunctionDecl * decl ) { 498 138 mangleDecl( decl ); 499 139 } 500 140 501 void Mangler _new::postvisit( const ast::VoidType * voidType ) {141 void Mangler::postvisit( const ast::VoidType * voidType ) { 502 142 printQualifiers( voidType ); 503 143 mangleName += Encoding::void_t; 504 144 } 505 145 506 void Mangler _new::postvisit( const ast::BasicType * basicType ) {146 void Mangler::postvisit( const ast::BasicType * basicType ) { 507 147 printQualifiers( basicType ); 508 148 assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind ); … … 510 150 } 511 151 512 void Mangler _new::postvisit( const ast::PointerType * pointerType ) {152 void Mangler::postvisit( const ast::PointerType * pointerType ) { 513 153 printQualifiers( pointerType ); 514 154 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers … … 517 157 } 518 158 519 void Mangler _new::postvisit( const ast::ArrayType * arrayType ) {159 void Mangler::postvisit( const ast::ArrayType * arrayType ) { 520 160 // TODO: encode dimension 521 161 printQualifiers( arrayType ); … … 524 164 } 525 165 526 void Mangler _new::postvisit( const ast::ReferenceType * refType ) {166 void Mangler::postvisit( const ast::ReferenceType * refType ) { 527 167 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload. 528 168 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.), … … 534 174 } 535 175 536 void Mangler _new::postvisit( const ast::FunctionType * functionType ) {176 void Mangler::postvisit( const ast::FunctionType * functionType ) { 537 177 printQualifiers( functionType ); 538 178 mangleName += Encoding::function; … … 549 189 } 550 190 551 void Mangler _new::mangleRef(191 void Mangler::mangleRef( 552 192 const ast::BaseInstType * refType, const std::string & prefix ) { 553 193 printQualifiers( refType ); … … 566 206 } 567 207 568 void Mangler _new::postvisit( const ast::StructInstType * aggregateUseType ) {208 void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) { 569 209 mangleRef( aggregateUseType, Encoding::struct_t ); 570 210 } 571 211 572 void Mangler _new::postvisit( const ast::UnionInstType * aggregateUseType ) {212 void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) { 573 213 mangleRef( aggregateUseType, Encoding::union_t ); 574 214 } 575 215 576 void Mangler _new::postvisit( const ast::EnumInstType * aggregateUseType ) {216 void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) { 577 217 mangleRef( aggregateUseType, Encoding::enum_t ); 578 218 } 579 219 580 void Mangler _new::postvisit( const ast::TypeInstType * typeInst ) {220 void Mangler::postvisit( const ast::TypeInstType * typeInst ) { 581 221 VarMapType::iterator varNum = varNums.find( typeInst->name ); 582 222 if ( varNum == varNums.end() ) { … … 594 234 } 595 235 596 void Mangler _new::postvisit( const ast::TraitInstType * inst ) {236 void Mangler::postvisit( const ast::TraitInstType * inst ) { 597 237 printQualifiers( inst ); 598 238 mangleName += std::to_string( inst->name.size() ) + inst->name; 599 239 } 600 240 601 void Mangler _new::postvisit( const ast::TupleType * tupleType ) {241 void Mangler::postvisit( const ast::TupleType * tupleType ) { 602 242 printQualifiers( tupleType ); 603 243 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() ); … … 605 245 } 606 246 607 void Mangler _new::postvisit( const ast::VarArgsType * varArgsType ) {247 void Mangler::postvisit( const ast::VarArgsType * varArgsType ) { 608 248 printQualifiers( varArgsType ); 609 249 static const std::string vargs = "__builtin_va_list"; … … 611 251 } 612 252 613 void Mangler _new::postvisit( const ast::ZeroType * ) {253 void Mangler::postvisit( const ast::ZeroType * ) { 614 254 mangleName += Encoding::zero; 615 255 } 616 256 617 void Mangler _new::postvisit( const ast::OneType * ) {257 void Mangler::postvisit( const ast::OneType * ) { 618 258 mangleName += Encoding::one; 619 259 } 620 260 621 void Mangler _new::postvisit( const ast::QualifiedType * qualType ) {261 void Mangler::postvisit( const ast::QualifiedType * qualType ) { 622 262 bool inqual = inQualifiedType; 623 263 if ( !inqual ) { … … 635 275 } 636 276 637 void Mangler _new::postvisit( const ast::TypeDecl * decl ) {277 void Mangler::postvisit( const ast::TypeDecl * decl ) { 638 278 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be 639 279 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa. … … 641 281 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed 642 282 // aside from the assert false. 643 assertf(false, "Mangler _newshould not visit typedecl: %s", toCString(decl));283 assertf(false, "Mangler should not visit typedecl: %s", toCString(decl)); 644 284 assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind ); 645 285 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name; … … 653 293 } 654 294 655 void Mangler _new::printQualifiers( const ast::Type * type ) {295 void Mangler::printQualifiers( const ast::Type * type ) { 656 296 // skip if not including qualifiers 657 297 if ( typeMode ) return; … … 678 318 } // for 679 319 for ( auto & assert : funcType->assertions ) { 680 assertionNames.push_back( ast::Pass<Mangler _new>::read(320 assertionNames.push_back( ast::Pass<Mangler>::read( 681 321 assert->var.get(), 682 322 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) ); -
src/SymTab/Mangler.h
rdf8ba61a r8d182b1 22 22 23 23 #include "AST/Bitfield.hpp" 24 #include "SynTree/SynTree.h" // for Types25 #include "SynTree/Visitor.h" // for Visitor, maybeAccept26 24 27 25 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling … … 35 33 class Node; 36 34 } 37 namespace ResolvExpr {38 class TypeEnvironment;39 }40 35 41 36 namespace SymTab { 42 37 namespace Mangler { 43 /// Mangle syntax tree object; primary interface to clients44 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );45 46 /// Mangle a type name; secondary interface47 std::string mangleType( const Type * ty );48 /// Mangle ignoring generic type parameters49 std::string mangleConcrete( const Type * ty );50 51 38 namespace Encoding { 52 39 extern const std::string manglePrefix; -
src/SymTab/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC_SYMTAB = \ 18 SymTab/Autogen.cc \19 SymTab/Autogen.h \20 18 SymTab/FixFunction.cc \ 21 19 SymTab/FixFunction.h \ 22 20 SymTab/GenImplicitCall.cpp \ 23 21 SymTab/GenImplicitCall.hpp \ 24 SymTab/Indexer.cc \25 SymTab/Indexer.h \26 22 SymTab/Mangler.cc \ 27 23 SymTab/ManglerCommon.cc \ 28 SymTab/Mangler.h \ 29 SymTab/ValidateType.cc \ 30 SymTab/ValidateType.h 24 SymTab/Mangler.h 31 25 32 SRC += $(SRC_SYMTAB) \ 33 SymTab/Validate.cc \ 34 SymTab/Validate.h 26 SRC += $(SRC_SYMTAB) 35 27 36 28 SRCDEMANGLE += $(SRC_SYMTAB) \ -
src/Tuples/Explode.cc
rdf8ba61a r8d182b1 15 15 16 16 #include "Explode.h" 17 #include <list> // for list18 17 19 18 #include "AST/Pass.hpp" // for Pass 20 #include "SynTree/Mutator.h" // for Mutator21 #include "Common/PassVisitor.h" // for PassVisitor22 19 23 20 namespace 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 exprs45 exprs.push_back( applyCast( expr, false ) );46 }47 // want the top-level expression to be cast to reference type, but not nested48 // tuple expressions49 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 type59 return expr->clone();60 } else {61 // anything else should be cast to reference as normal62 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 than69 // type T. In particular, this transformation helps with generating the70 // correct code for reference-cast member tuple expressions, since the result71 // 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 reference77 // than it had coming into this function. To ensure types still match correctly, need to cast78 // 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 the89 // field is consistent with the type of the tuple expr, since the field90 // 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 } // namespace99 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 appropriate105 expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );106 }107 return expr;108 }109 21 110 22 namespace { -
src/Tuples/Explode.h
rdf8ba61a r8d182b1 20 20 21 21 #include "AST/Expr.hpp" 22 #include "ResolvExpr/Alternative.h" // for Alternative, AltList23 22 #include "ResolvExpr/Candidate.hpp" // for Candidate, CandidateList 24 #include "ResolvExpr/ExplodedActual.h" // for ExplodedActual25 23 #include "ResolvExpr/ExplodedArg.hpp" // for ExplodedArg 26 #include "SynTree/Expression.h" // for Expression, UniqueExpr, AddressExpr27 #include "SynTree/Type.h" // for TupleType, Type28 24 #include "Tuples.h" // for maybeImpure 29 25 … … 32 28 } 33 29 34 namespace SymTab {35 class Indexer;36 } // namespace SymTab37 38 30 namespace 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 Alternatives51 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 ExplodedActual59 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 explode67 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 components72 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 components78 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 components89 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 type95 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 explosion101 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 alternative113 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-type119 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 alternatives126 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 }139 31 140 32 const ast::Expr * distributeReference( const ast::Expr * ); -
src/Tuples/TupleAssignment.cc
rdf8ba61a r8d182b1 28 28 #include "AST/TypeEnvironment.hpp" 29 29 #include "CodeGen/OperatorTable.h" 30 #include "Common/PassVisitor.h"31 30 #include "Common/UniqueName.h" // for UniqueName 32 31 #include "Common/utility.h" // for splice, zipWith … … 34 33 #include "InitTweak/GenInit.h" // for genCtorInit 35 34 #include "InitTweak/InitTweak.h" // for getPointerBase, isAssignment 36 #include "ResolvExpr/Alternative.h" // for AltList, Alternative37 #include "ResolvExpr/AlternativeFinder.h" // for AlternativeFinder, simpleC...38 35 #include "ResolvExpr/Cost.h" // for Cost 39 36 #include "ResolvExpr/Resolver.h" // for resolveCtorInit 40 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment41 37 #include "ResolvExpr/typeops.h" // for combos 42 #include "SynTree/LinkageSpec.h" // for Cforall43 #include "SynTree/Declaration.h" // for ObjectDecl44 #include "SynTree/Expression.h" // for Expression, CastExpr, Name...45 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit46 #include "SynTree/Statement.h" // for ExprStmt47 #include "SynTree/Type.h" // for Type, Type::Qualifiers48 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution49 #include "SynTree/Visitor.h" // for Visitor50 38 51 39 #if 0 … … 56 44 57 45 namespace Tuples { 58 class TupleAssignSpotter_old {59 public:60 // dispatcher for Tuple (multiple and mass) assignment operations61 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 ¤tFinder;110 std::string fname;111 std::unique_ptr< Matcher > matcher;112 };113 114 /// true if expr is an expression of tuple type115 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 if124 // the alternative is a tuple125 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 types133 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 legal157 if ( args.size() == 0 ) return;158 159 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote160 // the function, in which case AlternativeFinder will handle it normally161 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;162 163 // look over all possible left-hand-sides164 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {165 // skip non-tuple LHS166 if ( ! refToTuple(lhsAlt.expr) ) continue;167 168 // explode is aware of casts - ensure every LHS expression is sent into explode169 // with a reference cast170 // xxx - this seems to change the alternatives before the normal171 // 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 assigned179 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 here184 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/destruction193 ResolvExpr::AltList rhs{};194 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );195 match();196 } else if ( args.size() > 2 ) {197 // expand all possible RHS possibilities198 // TODO build iterative version of this instead of using combos199 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 assignment204 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 assignment215 explode( rhsAlt, currentFinder.get_indexer(),216 std::back_inserter(rhs), true );217 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );218 } else {219 // mass assignment220 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 assignments244 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 valid258 }259 // prune expressions that don't coincide with260 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 assignments267 // that together form a single alternative268 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_front275 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 compositeEnv306 // 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 object328 PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs329 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 assert340 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 references343 // probably should not reference local variable - see MultipleAssignMatcher::match344 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 rhs347 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 calls360 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 environment375 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 }384 46 385 47 namespace { … … 403 65 404 66 /// Dispatcher for tuple (multiple and mass) assignment operations 405 class TupleAssignSpotter _newfinal {67 class TupleAssignSpotter final { 406 68 /// Actually finds tuple assignment operations, by subclass 407 69 struct Matcher { 408 70 ResolvExpr::CandidateList lhs, rhs; 409 TupleAssignSpotter _new& spotter;71 TupleAssignSpotter & spotter; 410 72 CodeLocation location; 411 73 ResolvExpr::Cost baseCost; … … 422 84 423 85 Matcher( 424 TupleAssignSpotter _new& s, const CodeLocation & loc,86 TupleAssignSpotter & s, const CodeLocation & loc, 425 87 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 426 88 : lhs( l ), rhs( r ), spotter( s ), location( loc ), … … 499 161 struct MassAssignMatcher final : public Matcher { 500 162 MassAssignMatcher( 501 TupleAssignSpotter _new& s, const CodeLocation & loc,163 TupleAssignSpotter & s, const CodeLocation & loc, 502 164 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 503 165 : Matcher( s, loc, l, r ) {} … … 529 191 struct MultipleAssignMatcher final : public Matcher { 530 192 MultipleAssignMatcher( 531 TupleAssignSpotter _new& s, const CodeLocation & loc,193 TupleAssignSpotter & s, const CodeLocation & loc, 532 194 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 533 195 : Matcher( s, loc, l, r ) {} … … 578 240 579 241 public: 580 TupleAssignSpotter _new( ResolvExpr::CandidateFinder & f )242 TupleAssignSpotter( ResolvExpr::CandidateFinder & f ) 581 243 : crntFinder( f ), fname(), matcher() {} 582 244 … … 715 377 std::vector< ResolvExpr::CandidateFinder > & args 716 378 ) { 717 TupleAssignSpotter _newspotter{ finder };379 TupleAssignSpotter spotter{ finder }; 718 380 spotter.spot( assign, args ); 719 381 } -
src/Tuples/TupleExpansion.cc
rdf8ba61a r8d182b1 23 23 #include "AST/Node.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu...26 25 #include "Common/ScopedMap.h" // for ScopedMap 27 26 #include "Common/utility.h" // for CodeLocation 28 27 #include "InitTweak/InitTweak.h" // for getFunction 29 #include "SynTree/LinkageSpec.h" // for Spec, C, Intrinsic30 #include "SynTree/Constant.h" // for Constant31 #include "SynTree/Declaration.h" // for StructDecl, DeclarationWithType32 #include "SynTree/Expression.h" // for UntypedMemberExpr, Expression, Uniq...33 #include "SynTree/Label.h" // for operator==, Label34 #include "SynTree/Mutator.h" // for Mutator35 #include "SynTree/Type.h" // for Type, Type::Qualifiers, TupleType36 #include "SynTree/Visitor.h" // for Visitor37 28 #include "Tuples.h" 38 29 39 class CompoundStmt; 40 class TypeSubstitution; 30 namespace Tuples { 41 31 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 order53 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 precedence111 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 recursively114 // 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 return125 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 expressions136 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 aggregate146 // xxx - this is a memory leak147 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 now163 declsToAddBefore.push_back( unqExpr->get_object() );164 unqExpr->set_object( nullptr );165 // steal the expr from the unqExpr166 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 FixInit170 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 StmtExpr195 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 tuple205 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 deleted249 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 exprs266 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 expressions276 // as a distinct part of its initializer - the produced compound literal may be used as part of277 // another expression278 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 it295 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 exprs305 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 void311 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 types316 qualifiers &= type->get_qualifiers();317 } // for318 if ( exprs.empty() ) qualifiers = Type::Qualifiers();319 return new TupleType( qualifiers, types );320 }321 32 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) { 322 33 // produce the TupleType which aggregates the types of the exprs … … 341 52 } 342 53 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 361 54 const ast::TypeInstType * isTtype( const ast::Type * type ) { 362 55 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { -
src/Tuples/Tuples.cc
rdf8ba61a r8d182b1 19 19 #include "AST/Inspect.hpp" 20 20 #include "AST/LinkageSpec.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "InitTweak/InitTweak.h" 23 22 … … 25 24 26 25 namespace { 27 /// Checks if impurity (read: side-effects) may exist in a piece of code.28 /// Currently gives a very crude approximation, wherein any function29 /// 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 impurity46 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 }75 26 76 27 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives … … 110 61 } 111 62 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 120 63 } // namespace Tuples 121 64 -
src/Tuples/Tuples.h
rdf8ba61a r8d182b1 21 21 #include "AST/Fwd.hpp" 22 22 #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"28 23 #include "ResolvExpr/CandidateFinder.hpp" 29 24 30 25 namespace Tuples { 31 26 // TupleAssignment.cc 32 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,33 std::vector< ResolvExpr::AlternativeFinder >& args );34 27 void handleTupleAssignment( 35 28 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, … … 38 31 // TupleExpansion.cc 39 32 /// 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 );41 33 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 42 34 43 35 /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 44 void expandTuples( std::list< Declaration * > & translationUnit );45 36 void expandTuples( ast::TranslationUnit & translaionUnit ); 46 37 47 38 /// replaces UniqueExprs with a temporary variable and one call 48 void expandUniqueExpr( std::list< Declaration * > & translationUnit );49 39 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 50 40 51 41 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 52 Type * makeTupleType( const std::list< Expression * > & exprs );53 42 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 54 43 55 44 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 56 TypeInstType * isTtype( Type * type );57 const TypeInstType * isTtype( const Type * type );58 45 const ast::TypeInstType * isTtype( const ast::Type * type ); 59 46 60 47 /// returns true if the expression may contain side-effects. 61 bool maybeImpure( const Expression * expr );62 48 bool maybeImpure( const ast::Expr * expr ); 63 49 64 50 /// Returns true if the expression may contain side-effect, 65 51 /// ignoring the presence of unique expressions. 66 bool maybeImpureIgnoreUnique( const Expression * expr );67 52 bool maybeImpureIgnoreUnique( const ast::Expr * expr ); 68 53 } // namespace Tuples -
src/Validate/Autogen.cpp
rdf8ba61a r8d182b1 49 49 50 50 // -------------------------------------------------------------------------- 51 struct AutogenerateRoutines _newfinal :51 struct AutogenerateRoutines final : 52 52 public ast::WithDeclsToAdd<>, 53 53 public ast::WithShortCircuiting { … … 232 232 233 233 // -------------------------------------------------------------------------- 234 void AutogenerateRoutines _new::previsit( const ast::EnumDecl * enumDecl ) {234 void AutogenerateRoutines::previsit( const ast::EnumDecl * enumDecl ) { 235 235 // Must visit children (enum constants) to add them to the symbol table. 236 236 if ( !enumDecl->body ) return; … … 249 249 } 250 250 251 void AutogenerateRoutines _new::previsit( const ast::StructDecl * structDecl ) {251 void AutogenerateRoutines::previsit( const ast::StructDecl * structDecl ) { 252 252 visit_children = false; 253 253 if ( !structDecl->body ) return; … … 265 265 } 266 266 267 void AutogenerateRoutines _new::previsit( const ast::UnionDecl * unionDecl ) {267 void AutogenerateRoutines::previsit( const ast::UnionDecl * unionDecl ) { 268 268 visit_children = false; 269 269 if ( !unionDecl->body ) return; … … 282 282 283 283 /// Generate ctor/dtors/assign for typedecls, e.g., otype T = int *; 284 void AutogenerateRoutines _new::previsit( const ast::TypeDecl * typeDecl ) {284 void AutogenerateRoutines::previsit( const ast::TypeDecl * typeDecl ) { 285 285 if ( !typeDecl->base ) return; 286 286 … … 290 290 } 291 291 292 void AutogenerateRoutines _new::previsit( const ast::TraitDecl * ) {292 void AutogenerateRoutines::previsit( const ast::TraitDecl * ) { 293 293 // Ensure that we don't add assignment ops for types defined as part of the trait 294 294 visit_children = false; 295 295 } 296 296 297 void AutogenerateRoutines _new::previsit( const ast::FunctionDecl * ) {297 void AutogenerateRoutines::previsit( const ast::FunctionDecl * ) { 298 298 // Track whether we're currently in a function. 299 299 // Can ignore function type idiosyncrasies, because function type can never … … 302 302 } 303 303 304 void AutogenerateRoutines _new::postvisit( const ast::FunctionDecl * ) {304 void AutogenerateRoutines::postvisit( const ast::FunctionDecl * ) { 305 305 functionNesting -= 1; 306 306 } … … 521 521 const ast::Expr * src, const ast::ObjectDecl * field, 522 522 ast::FunctionDecl * func, SymTab::LoopDirection direction ) { 523 InitTweak::InitExpander _newsrcParam( src );523 InitTweak::InitExpander srcParam( src ); 524 524 // Assign to destination. 525 525 ast::MemberExpr * dstSelect = new ast::MemberExpr( … … 795 795 796 796 void autogenerateRoutines( ast::TranslationUnit & translationUnit ) { 797 ast::Pass<AutogenerateRoutines _new>::run( translationUnit );797 ast::Pass<AutogenerateRoutines>::run( translationUnit ); 798 798 } 799 799 -
src/Validate/FindSpecialDecls.h
rdf8ba61a r8d182b1 16 16 #pragma once 17 17 18 #include <list> // for list19 20 class Declaration;21 class FunctionDecl;22 class StructDecl;23 class Type;24 25 18 namespace ast { 26 19 class TranslationUnit; … … 28 21 29 22 namespace Validate { 30 /// size_t type - set when size_t typedef is seen. Useful in a few places,31 /// such as in determining array dimension type32 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 generation39 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 );44 23 45 24 /// Find and remember some of the special declarations that are useful for -
src/Validate/module.mk
rdf8ba61a r8d182b1 16 16 17 17 SRC_VALIDATE = \ 18 Validate/FindSpecialDecls.cc \19 18 Validate/FindSpecialDecls.h 20 19 … … 37 36 Validate/GenericParameter.cpp \ 38 37 Validate/GenericParameter.hpp \ 39 Validate/HandleAttributes.cc \40 Validate/HandleAttributes.h \41 38 Validate/HoistStruct.cpp \ 42 39 Validate/HoistStruct.hpp \ -
src/Virtual/ExpandCasts.cc
rdf8ba61a r8d182b1 24 24 #include "AST/Expr.hpp" 25 25 #include "AST/Pass.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/ScopedMap.h" // for ScopedMap 28 27 #include "Common/SemanticError.h" // for SemanticError 29 28 #include "SymTab/Mangler.h" // for mangleType 30 #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl31 #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address...32 #include "SynTree/Mutator.h" // for mutateAll33 #include "SynTree/Type.h" // for Type, PointerType, StructInstType34 #include "SynTree/Visitor.h" // for acceptAll35 29 36 30 namespace Virtual { … … 43 37 } 44 38 45 bool is_type_id_object( const ObjectDecl * objectDecl ) {46 const std::string & objectName = objectDecl->name;47 return is_prefix( "__cfatid_", objectName );48 }49 50 39 bool is_type_id_object( const ast::ObjectDecl * decl ) { 51 40 return is_prefix( "__cfatid_", decl->name ); … … 55 44 56 45 /// 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 }272 46 273 47 /// Better error locations for generated casts. … … 494 268 } // namespace 495 269 496 void expandCasts( std::list< Declaration * > & translationUnit ) {497 PassVisitor<VirtualCastCore> translator;498 mutateAll( translationUnit, translator );499 }500 501 270 void expandCasts( ast::TranslationUnit & translationUnit ) { 502 271 ast::Pass<ExpandCastsCore>::run( translationUnit ); -
src/Virtual/Tables.cc
rdf8ba61a r8d182b1 21 21 #include "AST/Stmt.hpp" 22 22 #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>28 23 29 24 namespace Virtual { … … 65 60 return 17 < name.size() && '_' == name[0] && 66 61 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 init83 );84 62 } 85 63 … … 101 79 } 102 80 103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {104 assert( type );105 return makeVtableDeclaration( name, type, nullptr );106 }107 108 81 ast::ObjectDecl * makeVtableForward( 109 82 CodeLocation const & location, std::string const & name, … … 111 84 assert( vtableType ); 112 85 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 initialization122 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, the149 // size-of and align-of fields. These should be inserted.150 } else {151 assert(false);152 }153 return makeVtableDeclaration( name, vtableType, init );154 86 } 155 87 … … 224 156 } 225 157 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 nullptr256 );257 }258 259 158 ast::FunctionDecl * makeGetExceptionForward( 260 159 CodeLocation const & location, … … 284 183 } 285 184 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 298 185 ast::FunctionDecl * makeGetExceptionFunction( 299 186 CodeLocation const & location, … … 307 194 } ); 308 195 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 noFuncSpecifiers327 );328 196 } 329 197 -
src/Virtual/Tables.h
rdf8ba61a r8d182b1 18 18 #include <string> 19 19 #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;28 20 29 21 namespace Virtual { … … 37 29 bool isVTableInstanceName( std::string const & name ); 38 30 39 ObjectDecl * makeVtableForward(40 std::string const & name, StructInstType * vtableType );41 31 /* Create a forward declaration of a vtable of the given type. 42 32 * vtableType node is consumed. … … 46 36 ast::StructInstType const * vtableType ); 47 37 48 ObjectDecl * makeVtableInstance(49 std::string const & name,50 StructInstType * vtableType, Type * objectType,51 Initializer * init = nullptr );52 38 /* Create an initialized definition of a vtable. 53 39 * vtableType and init (if provided) nodes are consumed. … … 61 47 62 48 // Some special code for how exceptions interact with virtual tables. 63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType ); 49 64 50 /* Create a forward declaration of the exception virtual function 65 51 * linking the vtableType to the exceptType. Both nodes are consumed. … … 70 56 ast::Type const * exceptType ); 71 57 72 FunctionDecl * makeGetExceptionFunction(73 ObjectDecl * vtableInstance, Type * exceptType );74 58 /* Create the definition of the exception virtual function. 75 59 * exceptType node is consumed. … … 79 63 ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ); 80 64 81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );82 65 /* Build an instance of the type-id from the type of the type-id. 83 66 * TODO: Should take the parent type. Currently locked to the exception_t. -
src/main.cc
rdf8ba61a r8d182b1 29 29 #include <string> // for char_traits, operator<< 30 30 31 #include "AST/Convert.hpp"32 31 #include "AST/Pass.hpp" // for pass_visitor_stats 33 32 #include "AST/Print.hpp" // for printAll … … 40 39 #include "CodeGen/Generate.h" // for generate 41 40 #include "CodeGen/LinkOnce.h" // for translateLinkOnce 42 #include "CodeTools/TrackLoc.h" // for fillLocations43 41 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 44 42 #include "Common/DeclStats.hpp" // for printDeclStats … … 66 64 #include "ResolvExpr/EraseWith.hpp" // for eraseWith 67 65 #include "ResolvExpr/Resolver.h" // for resolve 68 #include "SynTree/LinkageSpec.h" // for Spec, Cforall, Intrinsic69 #include "SynTree/Declaration.h" // for Declaration70 66 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 71 67 #include "Validate/Autogen.hpp" // for autogenerateRoutines … … 101 97 ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 102 98 } 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 }108 99 } 109 100 … … 259 250 260 251 parse_cmdline( argc, argv ); // process command-line arguments 261 CodeGen::FixMain::setReplaceMain( !nomainp );262 252 263 253 if ( waiting_for_gdb ) { … … 403 393 PASS( "Translate Tries", ControlStruct::translateTries, transUnit ); 404 394 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit ); 395 PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp ); 405 396 406 397 // Needs to happen before tuple types are expanded. … … 430 421 431 422 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 434 425 if ( output != &cout ) { 435 426 delete output; -
tests/concurrency/waitfor/parse.cfa
rdf8ba61a r8d182b1 10 10 // Created On : Wed Aug 30 17:53:29 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 22:52:18202313 // Update Count : 6 412 // Last Modified On : Wed Nov 1 07:28:19 2023 13 // Update Count : 65 14 14 // 15 15 … … 258 258 // Local Variables: // 259 259 // tab-width: 4 // 260 // compile-command: "cfa waitfor.cfa" //260 // compile-command: "cfa parse.cfa" // 261 261 // End: // -
tests/io/.expect/manipulatorsInput.arm64.txt
rdf8ba61a r8d182b1 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 aaaaaaaa26 5 27 27 6 aabbccbb 28 28 7 dddwww 29 8 dddwww30 9 dddwww29 8 30 9 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 wwwwwwww34 13 wwwwwwww33 12 34 13 35 35 14 cccc 36 15 q36 15 37 37 a 38 38 a -
tests/io/.expect/manipulatorsInput.x64.txt
rdf8ba61a r8d182b1 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 aaaaaaaa26 5 27 27 6 aabbccbb 28 28 7 dddwww 29 8 dddwww30 9 dddwww29 8 30 9 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 wwwwwwww34 13 wwwwwwww33 12 34 13 35 35 14 cccc 36 15 q36 15 37 37 a 38 38 a -
tests/io/.expect/manipulatorsInput.x86.txt
rdf8ba61a r8d182b1 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 aaaaaaaa26 5 27 27 6 aabbccbb 28 28 7 dddwww 29 8 dddwww30 9 dddwww29 8 30 9 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 wwwwwwww34 13 wwwwwwww33 12 34 13 35 35 14 cccc 36 15 q36 15 37 37 a 38 38 a
Note:
See TracChangeset
for help on using the changeset viewer.