Changes in / [af746cc:dc58e5d]
- Files:
-
- 1 deleted
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/mike_brooks_MMath/background.tex
raf746cc rdc58e5d 1 1 \chapter{Background} 2 2 3 Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string ,3 Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string. 4 4 5 5 … … 45 45 Hence, in all cases, @sizeof@ is informing about type information. 46 46 47 So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up the type system.48 This misguided analogue can be forced onto single-dimension arraysbut there is no advantage other than possibly teaching beginning programmers about basic runtime array-access.49 50 Continuing, a short ened form for declaring local variables exists, provided that length information is given in the initializer:47 So, thinking of an array as a pointer to its first element is too simplistic an analogue and it is not backed up by the type system. 48 This misguided analogue works for a single-dimension array but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access. 49 50 Continuing, a short form for declaring array variables exists using length information provided implicitly by an initializer. 51 51 \lstinput{59-62}{bkgd-carray-arrty.c} 52 In these declarations, the resulting types are both arrays, but their lengths are inferred. 53 54 My contribution is enabled by recognizing 52 The compiler counts the number of initializer elements and uses this value as the first dimension. 53 Unfortunately, the implicit element counting does not extend to dimensions beyond the first. 54 \lstinput{64-67}{bkgd-carray-arrty.c} 55 56 My contribution is recognizing: 55 57 \begin{itemize} 56 \item There is value in using a type that knows how big the whole thing is.58 \item There is value in using a type that knows its size. 57 59 \item The type pointer to (first) element does not. 58 60 \item C \emph{has} a type that knows the whole picture: array, e.g. @T[10]@. 59 \item This type has all the usual derived forms, which also know the whole picture. A usefully noteworthy example is pointer to array, e.g. @T(*)[10]@. 61 \item This type has all the usual derived forms, which also know the whole picture. 62 A usefully noteworthy example is pointer to array, e.g. @T (*)[10]@.\footnote{ 63 The parenthesis are necessary because subscript has higher priority than pointer in C declarations. 64 (Subscript also has higher priority than dereference in C expressions.)} 60 65 \end{itemize} 61 66 62 Each of these sections, which introduces another layer of of the C arrays' story, 63 concludes with an \emph{Unfortunate Syntactic Reference}. 64 It shows how to spell the types under discussion, 65 along with interactions with orthogonal (but easily confused) language features. 66 Alternate spellings are listed within a row. 67 68 \section{Reading Declarations} 69 70 A significant area of confusion for reading C declarations results from embedding a declared variable in a declaration, mimicking the way the variable is used in executable statements. 71 \begin{cquote} 72 \begin{tabular}{@{}ll@{}} 73 \multicolumn{1}{@{}c}{\textbf{Array}} & \multicolumn{1}{c@{}}{\textbf{Function Pointer}} \\ 74 \begin{cfa} 75 int @(*@ar@)[@5@]@; // definition 76 ... @(*@ar@)[@3@]@ += 1; // usage 77 \end{cfa} 78 & 79 \begin{cfa} 80 int @(*@f@())[@5@]@ { ... }; // definition 81 ... @(*@f@())[@3@]@ += 1; // usage 82 \end{cfa} 83 \end{tabular} 84 \end{cquote} 85 Essentially, the type is wrapped around the name in successive layers (like an \Index{onion}). 86 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise: 87 \begin{quote} 88 In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93} 89 \end{quote} 90 After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right! 91 92 \CFA provides its own type, variable and routine declarations, using a simpler syntax. 93 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type. 94 The qualifiers have the same meaning in \CFA as in C. 95 Then, a \CFA declaration is read left to right, where a function return type is enclosed in brackets @[@\,@]@. 96 \begin{cquote} 97 \begin{tabular}{@{}l@{\hspace{3em}}ll@{}} 98 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}} & \multicolumn{1}{c}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{read left to right}} \\ 99 \begin{cfa} 100 int @*@ x1 @[5]@; 101 int @(*@x2@)[5]@; 102 int @(*@f( int p )@)[5]@; 103 \end{cfa} 104 & 105 \begin{cfa} 106 @[5] *@ int x1; 107 @* [5]@ int x2; 108 @[ * [5] int ]@ f( int p ); 109 \end{cfa} 110 & 111 \begin{cfa} 112 // array of 5 pointers to int 113 // pointer to array of 5 int 114 // function returning pointer to array of 5 ints 115 \end{cfa} 116 \\ 117 & & 118 \LstCommentStyle{//\ \ \ and taking an int argument} 119 \end{tabular} 120 \end{cquote} 121 As declaration complexity increases, it becomes corresponding difficult to read and understand the C declaration form. 122 Note, writing declarations left to right is common in other programming languages, where the function return-type is often placed after the parameter declarations. 123 124 \VRef[Table]{bkgd:ar:usr:avp} introduces the many layers of the C and \CFA array story, where the \CFA story is discussion in \VRef{XXX}. 125 The \CFA-thesis column shows the new array declaration form, which is my contributed improvements for safety and ergonomics. 126 The table shows there are multiple yet equivalent forms for the array types under discussion, and subsequent discussion shows interactions with orthogonal (but easily confused) language features. 127 Each row of the table shows alternate syntactic forms. 67 128 The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$. 68 The Type column gives the spelling used in a cast or error message (though note Section TODO points out that some types cannot be casted to). 69 The Declaration column gives the spelling used in an object declaration, such as variable or aggregate member; parameter declarations (section TODO) follow entirely different rules. 70 71 After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right! 72 73 74 \CFA-specific spellings (not yet introduced) are also included here for referenceability; these can be skipped on linear reading. 75 The \CFA-C column gives the, more fortunate, ``new'' syntax of section TODO, for spelling \emph{exactly the same type}. 76 This fortunate syntax does not have different spellings for types vs declarations; 77 a declaration is always the type followed by the declared identifier name; 78 for the example of letting @x@ be a \emph{pointer to array}, the declaration is spelled: 79 \begin{cfa} 80 [ * [10] T ] x; 81 \end{cfa} 82 The \CFA-Full column gives the spelling of a different type, introduced in TODO, which has all of my contributed improvements for safety and ergonomics. 83 84 \VRef[Figure]{bkgd:ar:usr:avp} gives this reference for the discussion so far. 85 86 \begin{figure} 129 Removing the declared variable @x@, gives the type used for variable, structure field, cast or error messages \PAB{(though note Section TODO points out that some types cannot be casted to)}. 130 Unfortunately, parameter declarations \PAB{(section TODO)} have more syntactic forms and rules. 131 132 \begin{table} 87 133 \centering 88 \setlength{\tabcolsep}{3pt} 89 \begin{tabular}{llllll} 90 & Description & Type & Declaration & \CFA-C & \CFA-Full \\ \hline 91 $\triangleright$ & val. 92 & @T@ 93 & @T x;@ 94 & @[ T ]@ 95 & 96 \\ \hline 97 & \pbox{20cm}{ \vspace{2pt} val.\\ \footnotesize{no writing the val.\ in \lstinline{x}} }\vspace{2pt} 98 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T} \\ \lstinline{T const} } 99 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x;} \\ \lstinline{T const x;} } 100 & @[ const T ]@ 101 & 102 \\ \hline \hline 103 $\triangleright$ & ptr.\ to val. 104 & @T *@ 105 & @T * x;@ 106 & @[ * T ]@ 107 & 108 \\ \hline 109 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}} }\vspace{2pt} 110 & @T * const@ 111 & @T * const x;@ 112 & @[ const * T ]@ 113 & 114 \\ \hline 115 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}} }\vspace{2pt} 116 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *} } 117 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x;} \\ \lstinline{T const * x;} } 118 & @[ * const T ]@ 119 & 120 \\ \hline \hline 121 $\triangleright$ & ar.\ of val. 122 & @T[10]@ 123 & @T x[10];@ 124 & @[ [10] T ]@ 125 & @[ array(T, 10) ]@ 126 \\ \hline 127 & \pbox{20cm}{ \vspace{2pt} ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{x[5]}} }\vspace{2pt} 128 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T[10]} \\ \lstinline{T const[10]} } 129 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T x[10];} \\ \lstinline{T const x[10];} } 130 & @[ [10] const T ]@ 131 & @[ const array(T, 10) ]@ 132 \\ \hline 133 & ar.\ of ptr.\ to val. 134 & @T*[10]@ 135 & @T *x[10];@ 136 & @[ [10] * T ]@ 137 & @[ array(* T, 10) ]@ 138 \\ \hline 139 & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x[5]}} }\vspace{2pt} 140 & @T * const [10]@ 141 & @T * const x[10];@ 142 & @[ [10] const * T ]@ 143 & @[ array(const * T, 10) ]@ 144 \\ \hline 145 & \pbox{20cm}{ \vspace{2pt} ar.\ of ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*(x[5])}} }\vspace{2pt} 146 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * [10]} \\ \lstinline{T const * [10]} } 147 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x[10];} \\ \lstinline{T const * x[10];} } 148 & @[ [10] * const T ]@ 149 & @[ array(* const T, 10) ]@ 150 \\ \hline \hline 151 $\triangleright$ & ptr.\ to ar.\ of val. 152 & @T(*)[10]@ 153 & @T (*x)[10];@ 154 & @[ * [10] T ]@ 155 & @[ * array(T, 10) ]@ 156 \\ \hline 157 & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}} }\vspace{2pt} 158 & @T(* const)[10]@ 159 & @T (* const x)[10];@ 160 & @[ const * [10] T ]@ 161 & @[ const * array(T, 10) ]@ 162 \\ \hline 163 & \pbox{20cm}{ \vspace{2pt} ptr.\ to ar.\ of val.\\ \footnotesize{no writing the val.\ in \lstinline{(*x)[5]}} }\vspace{2pt} 164 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T(*)[10]} \\ \lstinline{T const (*) [10]} } 165 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T (*x)[10];} \\ \lstinline{T const (*x)[10];} } 166 & @[ * [10] const T ]@ 167 & @[ * const array(T, 10) ]@ 168 \\ \hline 169 & ptr.\ to ar.\ of ptr.\ to val. 170 & @T*(*)[10]@ 171 & @T *(*x)[10];@ 172 & @[ * [10] * T ]@ 173 & @[ * array(* T, 10) ]@ 174 \\ \hline 134 \caption{Syntactic Reference for Array vs Pointer. Includes interaction with \lstinline{const}ness.} 135 \label{bkgd:ar:usr:avp} 136 \begin{tabular}{ll|l|l|l} 137 & Description & \multicolumn{1}{c|}{C} & \multicolumn{1}{c|}{\CFA} & \multicolumn{1}{c}{\CFA-thesis} \\ 138 \hline 139 $\triangleright$ & value & @T x;@ & @T x;@ & \\ 140 \hline 141 & immutable value & @const T x;@ & @const T x;@ & \\ 142 & & @T const x;@ & @T const x;@ & \\ 143 \hline \hline 144 $\triangleright$ & pointer to value & @T * x;@ & @* T x;@ & \\ 145 \hline 146 & immutable ptr. to val. & @T * const x;@ & @const * T x;@ & \\ 147 \hline 148 & ptr. to immutable val. & @const T * x;@ & @* const T x;@ & \\ 149 & & @T const * x;@ & @* T const x;@ & \\ 150 \hline \hline 151 $\triangleright$ & array of value & @T x[10];@ & @[10] T x@ & @array(T, 10) x@ \\ 152 \hline 153 & ar.\ of immutable val. & @const T x[10];@ & @[10] const T x@ & @const array(T, 10) x@ \\ 154 & & @T const x[10];@ & @[10] T const x@ & @array(T, 10) const x@ \\ 155 \hline 156 & ar.\ of ptr.\ to value & @T * x[10];@ & @[10] * T x@ & @array(T *, 10) x@ \\ 157 & & & & @array(* T, 10) x@ \\ 158 \hline 159 & ar.\ of imm. ptr.\ to val. & @T * const x[10];@ & @[10] const * T x@ & @array(* const T, 10) x@ \\ 160 & & & & @array(const * T, 10) x@ \\ 161 \hline 162 & ar.\ of ptr.\ to imm. val. & @const T * x[10];@ & @[10] * const T x@ & @array(const T *, 10) x@ \\ 163 & & @T const * x[10];@ & @[10] * T const x@ & @array(* const T, 10) x@ \\ 164 \hline \hline 165 $\triangleright$ & ptr.\ to ar.\ of value & @T (*x)[10];@ & @* [10] T x@ & @* array(T, 10) x@ \\ 166 \hline 167 & imm. ptr.\ to ar.\ of val. & @T (* const x)[10];@ & @const * [10] T x@ & @const * array(T, 10) x@ \\ 168 \hline 169 & ptr.\ to ar.\ of imm. val. & @const T (*x)[10];@ & @* [10] const T x@ & @* const array(T, 10) x@ \\ 170 & & @T const (*x)[10];@ & @* [10] T const x@ & @* array(T, 10) const x@ \\ 171 \hline 172 & ptr.\ to ar.\ of ptr.\ to val. & @T *(*x)[10];@ & @* [10] * T x@ & @* array(T *, 10) x@ \\ 173 & & & & @* array(* T, 10) x@ \\ 174 \hline 175 175 \end{tabular} 176 \caption{Unfortunate Syntactic Reference for Array vs Pointer. Includes interaction with constness.} 177 \label{bkgd:ar:usr:avp} 178 \end{figure} 179 180 181 182 176 \end{table} 183 177 184 178 TODO: Address these parked unfortunate syntaxes … … 186 180 \item static 187 181 \item star as dimension 188 \item under pointer decay: int p1[const 3] being int const *p1182 \item under pointer decay: @int p1[const 3]@ being @int const *p1@ 189 183 \end{itemize} 190 184 … … 203 197 \lstinput{10-10}{bkgd-carray-decay.c} 204 198 205 So, C provides an implicit conversion from @float[10]@ to @float *@, as described in ARM-6.3.2.1.3:199 So, C provides an implicit conversion from @float[10]@ to @float *@. 206 200 \begin{quote} 207 Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a 208 string literal used to initialize an array 209 an expression that has type ``array of type'' is 210 converted to an expression with type ``pointer to type'' that points to the initial element of 211 the array object 201 Except when it is the operand of the @sizeof@ operator, or the unary @&@ operator, or is a string literal used to 202 initialize an array an expression that has type ``array of \emph{type}'' is converted to an expression with type 203 ``pointer to \emph{type}'' that points to the initial element of the array object~\cite[\S~6.3.2.1.3]{C11} 212 204 \end{quote} 213 214 205 This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one. 215 216 206 It is worthy to note that the list of exception cases does not feature the occurrence of @ar@ in @ar[i]@. 217 Thus, subscripting happens on pointers, not arrays. 218 219 Subscripting proceeds first with pointer decay, if needed. Next, ARM-6.5.2.1.2 explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@. 220 ARM-6.5.6.8 explains that the addition, of a pointer with an integer type, is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough. 221 Finally, ARM-6.5.3.2.4 explains that the @*@ operator's result is the referenced element. 222 223 Taken together, these rules also happen to illustrate that @ar[i]@ and @i[a]@ mean the same thing. 207 Thus, subscripting happens on pointers not arrays. 208 209 Subscripting proceeds first with pointer decay, if needed. Next, \cite[\S~6.5.2.1.2]{C11} explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@. 210 \cite[\S~6.5.6.8]{C11} explains that the addition, of a pointer with an integer type, is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough. 211 Finally, \cite[\S~6.5.3.2.4]{C11} explains that the @*@ operator's result is the referenced element. 212 Taken together, these rules illustrate that @ar[i]@ and @i[a]@ mean the same thing! 224 213 225 214 Subscripting a pointer when the target is standard-inappropriate is still practically well-defined. … … 233 222 fs[5] = 3.14; 234 223 \end{cfa} 235 The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (ARM-7.22.3.4.2). 236 But program says \emph{nothing} more about this pointer value, that might cause its referent to \emph{be} an array, before doing the subscript. 237 238 Under this assumption, a pointer being subscripted (or added to, then dereferenced) 239 by any value (positive, zero, or negative), gives a view of the program's entire address space, 240 centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks, 241 each potentially (re)interpreted as @typeof(*p)@. 242 243 I call this phenomenon ``array diffraction,'' which is a diffraction of a single-element pointer 244 into the assumption that its target is in the middle of an array whose size is unlimited in both directions. 245 224 The @malloc@ behaviour is specified as returning a pointer to ``space for an object whose size is'' as requested (\cite[\S~7.22.3.4.2]{C11}). 225 But \emph{nothing} more is said about this pointer value, specifically that its referent might \emph{be} an array allowing subscripting. 226 227 Under this assumption, a pointer being subscripted (or added to, then dereferenced) by any value (positive, zero, or negative), gives a view of the program's entire address space, centred around the @p@ address, divided into adjacent @sizeof(*p)@ chunks, each potentially (re)interpreted as @typeof(*p)@. 228 I call this phenomenon ``array diffraction,'' which is a diffraction of a single-element pointer into the assumption that its target is in the middle of an array whose size is unlimited in both directions. 246 229 No pointer is exempt from array diffraction. 247 248 230 No array shows its elements without pointer decay. 249 231 250 232 A further pointer--array confusion, closely related to decay, occurs in parameter declarations. 251 ARM-6.7.6.3.7explains that when an array type is written for a parameter,252 the parameter's type becomes a type that I summarize as beingthe array-decayed type.253 The respective handling sof the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer.233 \cite[\S~6.7.6.3.7]{C11} explains that when an array type is written for a parameter, 234 the parameter's type becomes a type that can be summarized as the array-decayed type. 235 The respective handling of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer. 254 236 \lstinput{12-16}{bkgd-carray-decay.c} 255 237 As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variable declaration, 256 GCC also gives this code the warning: ```sizeof' on array function parameter `x' will return size of `float *'.'' 257 258 The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it's spelled: 238 @gcc@ also gives this code the warning for the first assertion: 239 \begin{cfa} 240 warning: 'sizeof' on array function parameter 'x' will return size of 'float *' 241 \end{cfa} 242 The caller of such a function is left with the reality that a pointer parameter is a pointer, no matter how it is spelled: 259 243 \lstinput{18-21}{bkgd-carray-decay.c} 260 244 This fragment gives no warnings. … … 272 256 depending on whether the object is a local variable or a parameter. 273 257 274 275 258 In summary, when a function is written with an array-typed parameter, 276 259 \begin{itemize} … … 283 266 As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does: 284 267 \lstinput{32-42}{bkgd-carray-decay.c} 285 286 \VRef[Figure]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter decalarations. 287 288 \begin{figure} 268 \VRef[Table]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter declarations. 269 270 \begin{table} 271 \caption{Syntactic Reference for Decay during Parameter-Passing. 272 Includes interaction with \lstinline{const}ness, where ``immutable'' refers to a restriction on the callee's ability.} 273 \label{bkgd:ar:usr:decay-parm} 289 274 \centering 290 275 \begin{tabular}{llllll} 291 & Description & Type & Param. Decl & \CFA-C \\ \hline 292 $\triangleright$ & ptr.\ to val. 293 & @T *@ 294 & \pbox{20cm}{ \vspace{2pt} \lstinline{T * x,} \\ \lstinline{T x[10],} \\ \lstinline{T x[],} }\vspace{2pt} 295 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * T ]} \\ \lstinline{[ [10] T ]} \\ \lstinline{[ [] T ]} } 296 \\ \hline 297 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the ptr.\ in \lstinline{x}} }\vspace{2pt} 298 & @T * const@ 299 & \pbox{20cm}{ \vspace{2pt} \lstinline{T * const x,} \\ \lstinline{T x[const 10],} \\ \lstinline{T x[const],} }\vspace{2pt} 300 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ const * T ]} \\ \lstinline{[ [const 10] T ]} \\ \lstinline{[ [const] T ]} } 301 \\ \hline 302 & \pbox{20cm}{ \vspace{2pt} ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{*x}} }\vspace{2pt} 303 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T *} \\ \lstinline{T const *} } 304 & \pbox{20cm}{ \vspace{2pt} \lstinline{const T * x,} \\ \lstinline{T const * x,} \\ \lstinline{const T x[10],} \\ \lstinline{T const x[10],} \\ \lstinline{const T x[],} \\ \lstinline{T const x[],} }\vspace{2pt} 305 & \pbox{20cm}{ \vspace{2pt} \lstinline{[* const T]} \\ \lstinline{[ [10] const T ]} \\ \lstinline{[ [] const T ]} } 306 \\ \hline \hline 307 $\triangleright$ & ptr.\ to ar.\ of val. 308 & @T(*)[10]@ 309 & \pbox{20cm}{ \vspace{2pt} \lstinline{T (*x)[10],} \\ \lstinline{T x[3][10],} \\ \lstinline{T x[][10],} }\vspace{2pt} 310 & \pbox{20cm}{ \vspace{2pt} \lstinline{[* [10] T]} \\ \lstinline{[ [3] [10] T ]} \\ \lstinline{[ [] [10] T ]} } 311 \\ \hline 312 & ptr.\ to ptr.\ to val. 313 & @T **@ 314 & \pbox{20cm}{ \vspace{2pt} \lstinline{T ** x,} \\ \lstinline{T *x[10],} \\ \lstinline{T *x[],} }\vspace{2pt} 315 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ * * T ]} \\ \lstinline{[ [10] * T ]} \\ \lstinline{[ [] * T ]} } 316 \\ \hline 317 & \pbox{20cm}{ \vspace{2pt} ptr.\ to ptr.\ to val.\\ \footnotesize{no writing the val.\ in \lstinline{**argv}} }\vspace{2pt} 318 & @const char **@ 319 & \pbox{20cm}{ \vspace{2pt} \lstinline{const char *argv[],} \\ \footnotesize{(others elided)} }\vspace{2pt} 320 & \pbox{20cm}{ \vspace{2pt} \lstinline{[ [] * const char ]} \\ \footnotesize{(others elided)} } 321 \\ \hline 276 & Description & Type & Parameter Declaration & \CFA \\ 277 \hline 278 & & & @T * x,@ & @* T x,@ \\ 279 $\triangleright$ & pointer to value & @T *@ & @T x[10],@ & @[10] T x,@ \\ 280 & & & @T x[],@ & @[] T x,@ \\ 281 \hline 282 & & & @T * const x,@ & @const * T x@ \\ 283 & immutable ptr.\ to val. & @T * const@ & @T x[const 10],@ & @[const 10] T x,@ \\ 284 & & & @T x[const],@ & @[const] T x,@\\ 285 \hline 286 & & & @const T * x,@ & @ * const T x,@ \\ 287 & & & @T const * x,@ & @ * T const x,@ \\ 288 & ptr.\ to immutable val. & @const T *@ & @const T x[10],@ & @[10] const T x,@ \\ 289 & & @T const *@ & @T const x[10],@ & @[10] T const x,@ \\ 290 & & & @const T x[],@ & @[] const T x,@ \\ 291 & & & @T const x[],@ & @[] T const x,@ \\ 292 \hline \hline 293 & & & @T (*x)[10],@ & @* [10] T x,@ \\ 294 $\triangleright$ & ptr.\ to ar.\ of val. & @T(*)[10]@ & @T x[3][10],@ & @[3][10] T x,@ \\ 295 & & & @T x[][10],@ & @[][10] T x,@ \\ 296 \hline 297 & & & @T ** x,@ & @** T x,@ \\ 298 & ptr.\ to ptr.\ to val. & @T **@ & @T * x[10],@ & @[10] * T x,@ \\ 299 & & & @T * x[],@ & @[] * T x,@ \\ 300 \hline 301 & ptr.\ to ptr.\ to imm.\ val. & @const char **@ & @const char * argv[],@ & @[] * const char argv,@ \\ 302 & & & \emph{others elided} & \emph{others elided} \\ 303 \hline 322 304 \end{tabular} 323 \caption{Unfortunate Syntactic Reference for Decay during Parameter-Passing. Includes interaction with constness, where ``no writing'' refers to a restriction on the callee's ability.} 324 \label{bkgd:ar:usr:decay-parm} 325 \end{figure} 305 \end{table} 326 306 327 307 328 308 \subsection{Lengths may vary, checking does not} 329 309 330 When the desired number of elements is unknown at compile time, 331 a variable-length array is a solution: 332 \begin{cfa} 333 int main( int argc, const char *argv[] ) { 310 When the desired number of elements is unknown at compile time, a variable-length array is a solution: 311 \begin{cfa} 312 int main( int argc, const char * argv[] ) { 334 313 assert( argc == 2 ); 335 314 size_t n = atol( argv[1] ); 336 assert( 0 < n && n < 1000 ); 337 315 assert( 0 < n ); 338 316 float ar[n]; 339 317 float b[10]; 340 341 318 // ... discussion continues here 342 319 } 343 320 \end{cfa} 344 This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, just as it puts 10 elements on the @main@ stack frame for @b@. 345 The variable-sized allocation of @ar@ is provided by @alloca@. 346 347 In a situation where the array sizes are not known to be small enough for stack allocation to be sensible, corresponding heap allocations are achievable as: 348 \begin{cfa} 349 float *ax1 = malloc( sizeof( float[n] ) ); 350 float *ax2 = malloc( n * sizeof( float ) ); 351 float *bx1 = malloc( sizeof( float[1000000] ) ); 352 float *bx2 = malloc( 1000000 * sizeof( float ) ); 353 \end{cfa} 354 355 356 VLA 321 This arrangement allocates @n@ elements on the @main@ stack frame for @ar@, called a \newterm{variable length array} (VLA), as well as 10 elements in the same stack frame for @b@. 322 The variable-sized allocation of @ar@ is provided by the @alloca@ routine, which bumps the stack pointer. 323 Note, the C standard supports VLAs~\cite[\S~6.7.6.2.4]{C11} as a conditional feature, but the \CC standard does not; 324 both @gcc@ and @g++@ support VLAs. 325 As well, there is misinformation about VLAs, \eg VLAs cause stack failures or are inefficient. 326 VLAs exist as far back as Algol W~\cite[\S~5.2]{AlgolW} and are a sound and efficient data type. 327 328 For high-performance applications, the stack size can be fixed and small (coroutines or user-level threads). 329 Here, VLAs can overflow the stack, so a heap allocation is used. 330 \begin{cfa} 331 float * ax1 = malloc( sizeof( float[n] ) ); 332 float * ax2 = malloc( n * sizeof( float ) ); 333 float * bx1 = malloc( sizeof( float[1000000] ) ); 334 float * bx2 = malloc( 1000000 * sizeof( float ) ); 335 \end{cfa} 357 336 358 337 Parameter dependency … … 363 342 364 343 365 366 \subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)} 344 \subsection{Dynamically sized, multidimensional arrays} 367 345 368 346 In C and \CC, ``multidimensional array'' means ``array of arrays.'' Other meanings are discussed in TODO. … … 416 394 \section{Linked List} 417 395 396 Linked-lists are blocks of storage connected using one or more pointers. 397 The storage block is logically divided into data and links (pointers), where the links are the only component used by the list structure. 398 Since the data is opaque, list structures are often polymorphic over the data, which is normally homogeneous. 399 418 400 419 401 \section{String} 402 403 A string is a logical sequence of symbols, where the form of the symbols can vary significantly: 7/8-bit characters (ASCII/Latin-1), or 2/4/8-byte (UNICODE) characters/symbols or variable length (UTF-8/16/32) characters. 404 A string can be read left-to-right, right-to-left, top-to-bottom, and have stacked elements (Arabic). 405 406 An integer character constant is a sequence of one or more multibyte characters enclosed in single-quotes, as in @'x'@. 407 A wide character constant is the same, except prefixed by the letter @L@, @u@, or @U@. 408 With a few exceptions detailed later, the elements of the sequence are any members of the source character set; 409 they are mapped in an implementation-defined manner to members of the execution character set. 410 411 A C character-string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in @"xyz"@. 412 A UTF-8 string literal is the same, except prefixed by @u8@. 413 A wide string literal is the same, except prefixed by the letter @L@, @u@, or @U@. 414 415 For UTF-8 string literals, the array elements have type @char@, and are initialized with the characters of the multibyte character sequence, as encoded in UTF-8. 416 For wide string literals prefixed by the letter @L@, the array elements have type @wchar_t@ and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by the @mbstowcs@ function with an implementation-defined current locale. 417 For wide string literals prefixed by the letter @u@ or @U@, the array elements have type @char16_t@ or @char32_t@, respectively, and are initialized with the sequence of wide characters corresponding to the multibyte character sequence, as defined by successive calls to the @mbrtoc16@, or @mbrtoc32@ function as appropriate for its type, with an implementation-defined current locale. 418 The value of a string literal containing a multibyte character or escape sequence not represented in the executioncharacter set is implementation-defined. 419 420 421 Another bad C design decision is to have null-terminated strings rather than maintaining a separate string length. 422 \begin{quote} 423 Technically, a string is an array whose elements are single characters. 424 The compiler automatically places the null character @\0@ at the end of each such string, so programs can conveniently find the end. 425 This representation means that there is no real limit to how long a string can be, but programs have to scan one completely to determine its length. 426 \end{quote} -
doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c
raf746cc rdc58e5d 57 57 f( &ar ); 58 58 59 float fs[] = {3.14, 1.7 07};59 float fs[] = {3.14, 1.77}; 60 60 char cs[] = "hello"; 61 61 static_assert( sizeof(fs) == 2 * sizeof(float) ); 62 62 static_assert( sizeof(cs) == 6 * sizeof(char) ); $\C{// 5 letters + 1 null terminator}$ 63 63 64 float fm[][2] = { {3.14, 1.77}, {12.4, 0.01}, {7.8, 1.23} }; $\C{// brackets define structuring}$ 65 char cm[][sizeof("hello")] = { "hello", "hello", "hello" }; 66 static_assert( sizeof(fm) == 3 * 2 * sizeof(float) ); 67 static_assert( sizeof(cm) == 3 * 6 * sizeof(char) ); 64 68 } 65 69 -
doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c
raf746cc rdc58e5d 4 4 float (*pa)[10] = &a; $\C{// pointer to array}$ 5 5 float a0 = a[0]; $\C{// element}$ 6 float * pa0 = &(a[0]); $\C{// pointer to element}$6 float * pa0 = &(a[0]); $\C{// pointer to element}$ 7 7 8 float * pa0x = a; $\C{// (ok)}$8 float * pa0x = a; $\C{// (ok)}$ 9 9 assert( pa0 == pa0x ); 10 10 assert( sizeof(pa0x) != sizeof(a) ); 11 11 12 void f( float x[10], float * y ) {13 static_assert( sizeof(x) == sizeof(void *) );14 static_assert( sizeof(y) == sizeof(void *) );12 void f( float x[10], float * y ) { 13 static_assert( sizeof(x) == sizeof(void *) ); 14 static_assert( sizeof(y) == sizeof(void *) ); 15 15 } 16 16 f(0,0); … … 22 22 23 23 char ca[] = "hello"; $\C{// array on stack, initialized from read-only data}$ 24 char * cp = "hello";$\C{// pointer to read-only data [decay here]}$25 void edit( char c[] ) { $\C{// param is pointer}$24 char * cp = "hello"; $\C{// pointer to read-only data [decay here]}$ 25 void edit( char c[] ) { $\C{// parameter is pointer}$ 26 26 c[3] = 'p'; 27 27 } 28 28 edit( ca ); $\C{// ok [decay here]}$ 29 edit( c p );$\C{// Segmentation fault}$29 edit( cp ); $\C{// Segmentation fault}$ 30 30 edit( "hello" ); $\C{// Segmentation fault [decay here]}$ 31 31 32 32 void decay( float x[10] ) { 33 static_assert( sizeof(x) == sizeof(void *) );33 static_assert( sizeof(x) == sizeof(void *) ); 34 34 } 35 35 static_assert( sizeof(a) == 10 * sizeof(float) ); -
libcfa/src/concurrency/kernel/cluster.cfa
raf746cc rdc58e5d 341 341 // Make sure that everything is consistent 342 342 /* paranoid */ check_readyQ( cltr ); 343 /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );343 // /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) ); 344 344 345 345 __cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue done\n"); … … 416 416 fix_times(readyQ.tscs, ncount); 417 417 } 418 418 419 cltr->sched.caches = alloc( target, cltr->sched.caches`realloc ); 419 420 … … 428 429 429 430 // Make sure that everything is consistent 430 /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );431 // /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) ); 431 432 /* paranoid */ check_readyQ( cltr ); 432 433 -
libcfa/src/concurrency/kernel/startup.cfa
raf746cc rdc58e5d 672 672 uint_fast32_t last_size = ready_mutate_lock(); 673 673 674 675 674 // Adjust the ready queue size 675 ready_queue_shrink( &this ); 676 676 677 677 // Unlock the RWlock … … 682 682 /* paranoid */ verify( this.sched.readyQ.tscs == 0p ); 683 683 /* paranoid */ verify( this.sched.readyQ.count == 0 ); 684 /* paranoid */ verify( this.sched.io.tscs == 0p );685 /* paranoid */ verify( this.sched.caches == 0p );684 // /* paranoid */ verify( this.sched.io.tscs == 0p ); 685 // /* paranoid */ verify( this.sched.caches == 0p ); 686 686 687 687 enable_interrupts( false ); // Don't poll, could be in main cluster -
libcfa/src/heap.cfa
raf746cc rdc58e5d 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jan 3 21:30:54202413 // Update Count : 16 1912 // Last Modified On : Sun Apr 7 21:54:29 2024 13 // Update Count : 1644 14 14 // 15 15 … … 114 114 115 115 116 // generic Bsearchl does not inline, so substitute with hand-coded binary-search.116 // CFA generic Bsearchl does not inline, so substitute with hand-coded binary-search. 117 117 inline __attribute__((always_inline)) 118 118 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) { … … 190 190 unsigned int realloc_calls, realloc_0_calls; 191 191 unsigned long long int realloc_storage_request, realloc_storage_alloc; 192 unsigned int free_calls, free_null_ calls;192 unsigned int free_calls, free_null_0_calls; 193 193 unsigned long long int free_storage_request, free_storage_alloc; 194 194 unsigned int return_pulls, return_pushes; … … 232 232 struct Header { // header 233 233 union Kind { 234 struct RealHeader { 234 struct RealHeader { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 235 235 union { 236 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 237 union { 238 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped 239 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 240 void * home; // allocated block points back to home locations (must overlay alignment) 241 size_t blockSize; // size for munmap (must overlay alignment) 242 Storage * next; // freed block points to next freed block of same size 243 }; 244 size_t size; // allocation size in bytes 245 }; 236 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped 237 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 238 void * home; // allocated block points back to home locations (must overlay alignment) 239 size_t blockSize; // size for munmap (must overlay alignment) 240 Storage * next; // freed block points to next freed block of same size 246 241 }; 242 size_t size; // allocation size in bytes 247 243 } real; // RealHeader 248 244 … … 261 257 262 258 struct CALIGN FreeHeader { 263 size_t blockSize CALIGN; // size of allocations on this list264 259 #ifdef OWNERSHIP 265 260 #ifdef RETURNSPIN … … 271 266 Storage * freeList; // thread free list 272 267 Heap * homeManager; // heap owner (free storage to bucket, from bucket to heap) 268 size_t blockSize; // size of allocations on this list 273 269 }; // FreeHeader 274 270 … … 369 365 static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing 370 366 static __thread Heap * heapManager CALIGN TLSMODEL; 371 static 367 static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false; 372 368 static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing 373 369 … … 595 591 596 592 #ifdef __STATISTICS__ 597 static HeapStatistics stats; // zero filled598 599 593 #define prtFmt \ 600 594 "\nHeap statistics: (storage request / allocation)\n" \ … … 607 601 " resize >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \ 608 602 " realloc >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \ 609 " free !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \603 " free !null calls %'u; null/0 calls %'u; storage %'llu / %'llu bytes\n" \ 610 604 " return pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \ 611 605 " sbrk calls %'u; storage %'llu bytes\n" \ … … 627 621 resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc, 628 622 realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc, 629 free_calls, free_null_ calls, free_storage_request, free_storage_alloc,623 free_calls, free_null_0_calls, free_storage_request, free_storage_alloc, 630 624 return_pulls, return_pushes, return_storage_request, return_storage_alloc, 631 625 sbrk_calls, sbrk_storage, … … 650 644 "<total type=\"resize\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 651 645 "<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 652 "<total type=\"free\" !null=\"%'u;\" 0 null =\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \646 "<total type=\"free\" !null=\"%'u;\" 0 null/0=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 653 647 "<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 654 648 "<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \ … … 670 664 resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc, 671 665 realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc, 672 free_calls, free_null_ calls, free_storage_request, free_storage_alloc,666 free_calls, free_null_0_calls, free_storage_request, free_storage_alloc, 673 667 return_pulls, return_pushes, return_storage_request, return_storage_alloc, 674 668 sbrk_calls, sbrk_storage, … … 799 793 } else { 800 794 fakeHeader( header, alignment ); 801 if ( unlikely( MmappedBit( header ) ) ) { // mmapped ?795 if ( unlikely( MmappedBit( header ) ) ) { // mmapped storage ? 802 796 verify( addr < heapBegin || heapEnd < addr ); 803 797 size = ClearStickyBits( header->kind.real.blockSize ); // mmap size 798 freeHead = 0p; // prevent uninitialized warning 804 799 return true; 805 800 } // if … … 904 899 905 900 906 #define BOOT_HEAP_MANAGER \907 if ( unlikely( ! heapMasterBootFlag ) ) { \908 heapManagerCtor(); /* trigger for first heap */ \909 } /* if */910 911 901 #ifdef __STATISTICS__ 912 902 #define STAT_NAME __counter 913 903 #define STAT_PARM , unsigned int STAT_NAME 914 904 #define STAT_ARG( name ) , name 915 #define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1905 #define STAT_0_CNT( counter ) heapManager->stats.counters[counter].calls_0 += 1 916 906 #else 917 907 #define STAT_NAME … … 921 911 #endif // __STATISTICS__ 922 912 923 // Uncomment to get allocation addresses for a 0-sized allocation rather than a null pointer. 924 //#define __NONNULL_0_ALLOC__ 925 #if ! defined( __NONNULL_0_ALLOC__ ) 926 #define __NULL_0_ALLOC__ unlikely( size == 0 ) || /* 0 BYTE ALLOCATION RETURNS NULL POINTER */ 913 #define BOOT_HEAP_MANAGER \ 914 if ( unlikely( ! heapMasterBootFlag ) ) { \ 915 heapManagerCtor(); /* trigger for first heap */ \ 916 } /* if */ \ 917 verify( heapManager ); 918 919 #define __NONNULL_0_ALLOC__ /* Uncomment to return non-null address for malloc( 0 ). */ 920 #ifndef __NONNULL_0_ALLOC__ 921 #define __NULL_0_ALLOC__( counter, ... ) /* 0 byte allocation returns null pointer */ \ 922 if ( unlikely( size == 0 ) ) { \ 923 STAT_0_CNT( counter ); \ 924 __VA_ARGS__; /* call routine, if specified */ \ 925 return 0p; \ 926 } /* if */ 927 927 #else 928 #define __NULL_0_ALLOC__ 928 #define __NULL_0_ALLOC__( counter, ... ) 929 929 #endif // __NONNULL_0_ALLOC__ 930 931 #ifdef __DEBUG__ 932 #define __OVERFLOW_MALLOC__( ... ) \ 933 if ( unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \ 934 __VA_ARGS__; /* call routine, if specified */ \ 935 return 0p; \ 936 } /* if */ 937 #else 938 #define __OVERFLOW_MALLOC__( ... ) 939 #endif // __DEBUG__ 930 940 931 941 #define PROLOG( counter, ... ) \ 932 942 BOOT_HEAP_MANAGER; \ 933 if ( \ 934 __NULL_0_ALLOC__ \ 935 unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \ 936 STAT_0_CNT( counter ); \ 937 __VA_ARGS__; \ 938 return 0p; \ 939 } /* if */ 940 943 __NULL_0_ALLOC__( counter, __VA_ARGS__ ) \ 944 __OVERFLOW_MALLOC__( __VA_ARGS__ ) 941 945 942 946 #define SCRUB_SIZE 1024lu … … 948 952 PROLOG( STAT_NAME ); 949 953 950 verify( heapManager );951 954 Heap.Storage * block; // pointer to new block of storage 952 955 … … 956 959 957 960 #ifdef __STATISTICS__ 958 stats.counters[STAT_NAME].calls += 1; 961 #ifdef __NONNULL_0_ALLOC__ 962 if ( unlikely( size == 0 ) ) // malloc( 0 ) ? 963 stats.counters[STAT_NAME].calls_0 += 1; 964 else 965 #endif // __NONNULL_0_ALLOC__ 966 stats.counters[STAT_NAME].calls += 1; 959 967 stats.counters[STAT_NAME].request += size; 960 968 #endif // __STATISTICS__ … … 1078 1086 1079 1087 static void doFree( void * addr ) libcfa_nopreempt with( *heapManager ) { 1088 // char buf[64]; 1089 // int len = sprintf( buf, "doFree addr %p\n", addr ); 1090 // write( 2, buf, len ); 1091 1080 1092 verify( addr ); 1081 1093 … … 1091 1103 #endif // __STATISTICS__ || __CFA_DEBUG__ 1092 1104 1105 // Do not move these down because heap can be null! 1093 1106 #ifdef __STATISTICS__ 1107 #ifdef __NONNULL_0_ALLOC__ 1108 if ( unlikely( rsize == 0 ) ) // malloc( 0 ) ? 1109 stats.free_null_0_calls += 1; 1110 else 1111 #endif // __NONNULL_0_ALLOC__ 1112 heapManager->stats.free_calls += 1; // count free amd implicit frees from resize/realloc 1094 1113 stats.free_storage_request += rsize; 1095 1114 stats.free_storage_alloc += size; … … 1117 1136 } // if 1118 1137 } else { 1138 assert( freeHead ); 1119 1139 #ifdef __CFA_DEBUG__ 1120 1140 // memset is NOT always inlined! … … 1321 1341 // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done. 1322 1342 void * resize( void * oaddr, size_t size ) libcfa_public { 1323 if ( unlikely( oaddr == 0p ) ) { // => malloc( size )1343 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1324 1344 return doMalloc( size STAT_ARG( RESIZE ) ); 1325 1345 } // if … … 1333 1353 1334 1354 size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket 1335 // same size, DO NOT preserveSTICKY PROPERTIES.1355 // same size, DO NOT PRESERVE STICKY PROPERTIES. 1336 1356 if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size 1337 1357 ClearZeroFillBit( header ); // no alignment and turn off 0 fill … … 1346 1366 } // if 1347 1367 1348 // change size, DO NOT preserveSTICKY PROPERTIES.1368 // change size, DO NOT PRESERVE STICKY PROPERTIES. 1349 1369 doFree( oaddr ); // free previous storage 1350 1370 … … 1356 1376 // the old and new sizes. 1357 1377 void * realloc( void * oaddr, size_t size ) libcfa_public { 1378 // char buf[64]; 1379 // int len = sprintf( buf, "realloc1 oaddr %p size %d\n", oaddr, size ); 1380 // write( 2, buf, len ); 1358 1381 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1359 1382 return doMalloc( size STAT_ARG( REALLOC ) ); … … 1498 1521 } // if 1499 1522 1500 #ifdef __STATISTICS__1501 incCalls( FREE );1502 #endif // __STATISTICS__1503 1504 1523 doFree( addr ); // handles heapManager == nullptr 1505 1524 } // free … … 1579 1598 #endif // __STATISTICS__ 1580 1599 } // malloc_stats_clear 1581 1582 1600 1583 1601 // Changes the file descriptor where malloc_stats() writes statistics. … … 1700 1718 } // if 1701 1719 1702 // change size, DO NOT preserveSTICKY PROPERTIES.1720 // change size, DO NOT PRESERVE STICKY PROPERTIES. 1703 1721 doFree( oaddr ); // free previous storage 1704 1722 return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); // create new aligned area … … 1707 1725 1708 1726 void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public { 1727 // char buf[64]; 1728 // int len = sprintf( buf, "realloc2 oaddr %p size %d\n", oaddr, size ); 1729 // write( 2, buf, len ); 1709 1730 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1710 1731 return memalignNoStats( nalign, size STAT_ARG( REALLOC ) ); -
libcfa/src/heap.hfa
raf746cc rdc58e5d 10 10 // Created On : Tue May 26 11:23:55 2020 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Sep 11 11:18:18 202313 // Update Count : 2 412 // Last Modified On : Mon Apr 1 09:36:20 2024 13 // Update Count : 25 14 14 // 15 15 … … 46 46 } // extern "C" 47 47 48 // New allocation operations. 48 49 void * resize( void * oaddr, size_t alignment, size_t size ); 49 50 void * realloc( void * oaddr, size_t alignment, size_t size ); … … 51 52 52 53 // Local Variables: // 53 // mode: c //54 54 // tab-width: 4 // 55 55 // End: // -
libcfa/src/stdlib.hfa
raf746cc rdc58e5d 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Mar 17 08:25:31202413 // Update Count : 79612 // Last Modified On : Fri Apr 12 07:39:15 2024 13 // Update Count : 812 14 14 // 15 15 … … 109 109 1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following: 110 110 forall( T & | sized(T) ) { 111 union U_fill 112 struct S_fill 113 struct S_realloc 111 union U_fill { char c; T * a; T t; }; 112 struct S_fill { char tag; U_fill(T) fill; }; 113 struct S_realloc { inline T *; }; 114 114 } 115 115 116 116 2. Replace all current postfix-fill functions with following for updated S_fill: 117 S_fill(T) ?`fill( char a ) 118 S_fill(T) ?`fill( T a ){ S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; }119 S_fill(T) ?`fill( T a[], size_t nmemb ){ S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }117 S_fill(T) ?`fill( char a ) { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; } 118 S_fill(T) ?`fill( T a ) { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; } 119 S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; } 120 120 121 121 3. Replace the alloc_internal$ function which is outside ttype forall-block with following function: … … 148 148 */ 149 149 150 typedef struct S_align 151 typedef struct S_resize 150 typedef struct S_align { inline size_t; } T_align; 151 typedef struct S_resize { inline void *; } T_resize; 152 152 153 153 forall( T & ) { 154 struct S_fill 155 struct S_realloc 154 struct S_fill { char tag; char c; size_t size; T * at; char t[50]; }; 155 struct S_realloc { inline T *; }; 156 156 } 157 157 158 static inline T_align ?`align ( size_t a ) { return (T_align){a}; } 159 static inline T_resize ?`resize ( void * a ) { return (T_resize){a}; } 160 158 static inline T_align ?`align( size_t a ) { return (T_align){a}; } 159 static inline T_resize ?`resize( void * a ) { return (T_resize){a}; } 160 161 extern "C" ssize_t write(int fd, const void *buf, size_t count); 161 162 static inline forall( T & | sized(T) ) { 162 163 S_fill(T) ?`fill ( T t ) { … … 169 170 return ret; 170 171 } 171 S_fill(T) 172 S_fill(T) ?`fill ( T * a ){ return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved173 S_fill(T) ?`fill ( char c ){ return (S_fill(T)){ 'c', c }; }174 S_fill(T) ?`fill ( T a[], size_t nmemb ){ return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }175 176 S_realloc(T) ?`realloc ( T * a ){ return (S_realloc(T)){a}; }172 S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved 173 S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved 174 S_fill(T) ?`fill ( char c ) { return (S_fill(T)){ 'c', c }; } 175 S_fill(T) ?`fill ( T a[], size_t nmemb ) { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; } 176 177 S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; } 177 178 178 179 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) { … … 182 183 183 184 if ( Resize ) { 184 ptr = (T*) (void *)resize( (void *)Resize, Align, Dim * size );185 ptr = (T*)(void *)resize( (void *)Resize, Align, Dim * size ); 185 186 } else if ( Realloc ) { 186 187 if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size ); 187 ptr = (T *) (void *)realloc( (void *)Realloc, Align, Dim * size );188 ptr = (T *)(void *)realloc( (void *)Realloc, Align, Dim * size ); 188 189 } else { 189 ptr = (T *) 190 ptr = (T *)(void *) memalign( Align, Dim * size ); 190 191 } 191 192 -
src/AST/Pass.hpp
raf746cc rdc58e5d 252 252 private: 253 253 254 __pass::result1<ast::Stmt> call_accept( const ast::Stmt * ); 255 __pass::result1<ast::Expr> call_accept( const ast::Expr * ); 256 257 /// This has a `type` member that is the return type for the 258 /// generic call_accept if the generic call_accept is defined. 254 /// The return type of the general call_accept function. 259 255 template< typename node_t > 260 using generic_call_accept_result = 261 std::enable_if< 262 !std::is_base_of<ast::Expr, node_t>::value && 263 !std::is_base_of<ast::Stmt, node_t>::value 264 , __pass::result1< 265 typename std::remove_pointer< typename std::result_of< 266 decltype(&node_t::accept)(node_t*, type&) >::type >::type 267 > 256 using call_accept_result_t = __pass::result1< 257 typename std::remove_pointer< typename std::result_of< 258 decltype(&node_t::accept)(node_t*, type&) >::type >::type 268 259 >; 269 260 270 261 template< typename node_t > 271 auto call_accept( const node_t * node ) 272 -> typename generic_call_accept_result<node_t>::type; 262 auto call_accept( const node_t * node ) -> call_accept_result_t<node_t>; 273 263 274 264 // requests WithStmtsToAdd directly add to this statement, as if it is a compound. -
src/AST/Pass.impl.hpp
raf746cc rdc58e5d 109 109 return val; 110 110 } 111 112 //------------------------------113 /// Check if value was mutated, different for pointers and containers114 template<typename lhs_t, typename rhs_t>115 bool differs( const lhs_t * old_val, const rhs_t * new_val ) {116 return old_val != new_val;117 }118 119 template< template <class...> class container_t, typename node_t >120 bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {121 return !new_val.empty();122 }123 111 } 124 112 … … 126 114 template< typename node_t > 127 115 auto ast::Pass< core_t >::call_accept( const node_t * node ) -> 128 typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type 129 { 116 ast::Pass< core_t >::call_accept_result_t<node_t> { 130 117 __pedantic_pass_assert( __visit_children() ); 131 118 __pedantic_pass_assert( node ); 132 119 133 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" );134 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" );135 136 120 auto nval = node->accept( *this ); 137 __pass::result1< 138 typename std::remove_pointer< decltype( node->accept(*this) ) >::type 139 > res; 140 res.differs = nval != node; 141 res.value = nval; 142 return res; 143 } 144 145 template< typename core_t > 146 ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 147 __pedantic_pass_assert( __visit_children() ); 148 __pedantic_pass_assert( expr ); 149 150 auto nval = expr->accept( *this ); 151 return { nval != expr, nval }; 152 } 153 154 template< typename core_t > 155 ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 156 __pedantic_pass_assert( __visit_children() ); 157 __pedantic_pass_assert( stmt ); 158 159 const ast::Stmt * nval = stmt->accept( *this ); 160 return { nval != stmt, nval }; 121 return { nval != node, nval }; 161 122 } 162 123 … … 230 191 ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 231 192 __pedantic_pass_assert( __visit_children() ); 232 if ( statements.empty() ) return {};193 __pedantic_pass_assert( !statements.empty() ); 233 194 234 195 // We are going to aggregate errors for all these statements … … 263 224 const ast::Stmt * new_stmt = stmt->accept( *this ); 264 225 assert( new_stmt ); 265 if ( new_stmt != stmt ) { new_kids.differs = true; }266 226 267 227 // Make sure that it is either adding statements or declartions but not both … … 276 236 // Now add the statement if there is one 277 237 if ( new_stmt != stmt ) { 278 new_kids.values.emplace_back( new_stmt, i, false ); 238 new_kids.differs = true; 239 new_kids.values.emplace_back( new_stmt ); 279 240 } else { 280 new_kids.values.emplace_back( nullptr, i, true);241 new_kids.values.emplace_back( i ); 281 242 } 282 243 … … 298 259 ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 299 260 __pedantic_pass_assert( __visit_children() ); 300 if ( container.empty() ) return {}; 261 __pedantic_pass_assert( !container.empty() ); 262 263 // Collect errors from processing all these nodes. 301 264 SemanticErrorException errors; 302 265 … … 342 305 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 343 306 344 auto new_val = call_accept( old_val ); 345 346 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" ); 347 348 if ( new_val.differs ) { 307 auto result = call_accept( old_val ); 308 if ( result.differs ) { 349 309 auto new_parent = __pass::mutate<core_t>(parent); 350 new_val.apply(new_parent, field);310 result.apply( new_parent, field ); 351 311 parent = new_parent; 352 312 } … … 366 326 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 367 327 368 auto new_val = call_accept_top( old_val ); 369 370 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" ); 371 372 if ( new_val.differs ) { 328 auto result = call_accept_top( old_val ); 329 if ( result.differs ) { 373 330 auto new_parent = __pass::mutate<core_t>(parent); 374 new_val.apply(new_parent, field);331 result.apply( new_parent, field ); 375 332 parent = new_parent; 376 333 } … … 390 347 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 391 348 392 auto new_val = call_accept_as_compound( old_val ); 393 394 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" ); 395 396 if ( new_val.differs ) { 349 auto result = call_accept_as_compound( old_val ); 350 if ( result.differs ) { 397 351 auto new_parent = __pass::mutate<core_t>(parent); 398 new_val.apply( new_parent, child );352 result.apply( new_parent, child ); 399 353 parent = new_parent; 400 354 } … … 452 406 template< typename core_t > 453 407 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) { 454 if ( auto ptr = __pass::translation _unit::get_cptr( visitor.core, 0 ) ) {408 if ( auto ptr = __pass::translationUnit( visitor.core, 0 ) ) { 455 409 ValueGuard<const TranslationUnit *> guard( *ptr ); 456 410 *ptr = &unit; -
src/AST/Pass.proto.hpp
raf746cc rdc58e5d 154 154 bool is_old; 155 155 156 delta(const Stmt * s, ssize_t i, bool old) :157 new_val(s), old_idx(i), is_old(old) {}156 explicit delta(const Stmt * s) : new_val(s), old_idx(-1), is_old(false) {} 157 explicit delta(ssize_t i) : new_val(nullptr), old_idx(i), is_old(true) {} 158 158 }; 159 159 … … 188 188 std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ), 189 189 [](ast::ptr<ast::Stmt>& stmt) -> delta { 190 return delta( stmt.release() , -1, false);190 return delta( stmt.release() ); 191 191 }); 192 192 stmts->clear(); … … 201 201 [](ast::ptr<ast::Decl>& decl) -> delta { 202 202 ast::Decl const * d = decl.release(); 203 return delta( new DeclStmt( d->location, d ) , -1, false);203 return delta( new DeclStmt( d->location, d ) ); 204 204 }); 205 205 decls->clear(); … … 226 226 // Now the original containers should still have the unchanged values 227 227 // but also contain the new values. 228 }229 };230 231 /// Used by previsit implementation232 /// We need to reassign the result to 'node', unless the function233 /// returns void, then we just leave 'node' unchanged234 template<bool is_void>235 struct __assign;236 237 template<>238 struct __assign<true> {239 template<typename core_t, typename node_t>240 static inline void result( core_t & core, const node_t * & node ) {241 core.previsit( node );242 }243 };244 245 template<>246 struct __assign<false> {247 template<typename core_t, typename node_t>248 static inline void result( core_t & core, const node_t * & node ) {249 node = core.previsit( node );250 assertf(node, "Previsit must not return NULL");251 }252 };253 254 /// Used by postvisit implementation255 /// We need to return the result unless the function256 /// returns void, then we just return the original node257 template<bool is_void>258 struct __return;259 260 template<>261 struct __return<true> {262 template<typename core_t, typename node_t>263 static inline const node_t * result( core_t & core, const node_t * & node ) {264 core.postvisit( node );265 return node;266 }267 };268 269 template<>270 struct __return<false> {271 template<typename core_t, typename node_t>272 static inline auto result( core_t & core, const node_t * & node ) {273 return core.postvisit( node );274 228 } 275 229 }; … … 297 251 ); 298 252 299 __assign< 300 std::is_void< 301 decltype( core.previsit( node ) ) 302 >::value 303 >::result( core, node ); 253 // We need to reassign the result to 'node', unless the function 254 // returns void, then we just leave 'node' unchanged 255 if constexpr ( std::is_void_v<decltype( core.previsit( node ) )> ) { 256 core.previsit( node ); 257 } else { 258 node = core.previsit( node ); 259 assertf( node, "Previsit must not return nullptr." ); 260 } 304 261 } 305 262 … … 312 269 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 313 270 { 314 return __return< 315 std::is_void< 316 decltype( core.postvisit( node ) ) 317 >::value 318 >::result( core, node ); 271 // We need to return the result unless the function 272 // returns void, then we just return the original node 273 if constexpr ( std::is_void_v<decltype( core.postvisit( node ) )> ) { 274 core.postvisit( node ); 275 return node; 276 } else { 277 return core.postvisit( node ); 278 } 319 279 } 320 280 … … 350 310 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 351 311 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 312 FIELD_PTR( translationUnit, const TranslationUnit * ) 352 313 353 314 // Remove the macro to make sure we don't clash … … 546 507 } // namespace forall 547 508 548 // For passes that need access to the global context. Searches `translationUnit`549 namespace translation_unit {550 template<typename core_t>551 static inline auto get_cptr( core_t & core, int )552 -> decltype( &core.translationUnit ) {553 return &core.translationUnit;554 }555 556 template<typename core_t>557 static inline const TranslationUnit ** get_cptr( core_t &, long ) {558 return nullptr;559 }560 }561 562 509 // For passes, usually utility passes, that have a result. 563 510 namespace result { -
src/Parser/StatementNode.cc
raf746cc rdc58e5d 122 122 ast::Expr * cond = nullptr; 123 123 if ( ctl->condition ) { 124 // compare the provided condition against 0 125 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) ); 124 cond = maybeMoveBuild( ctl->condition ); 126 125 } else { 127 126 for ( ast::ptr<ast::Stmt> & stmt : inits ) { … … 129 128 auto declStmt = stmt.strict_as<ast::DeclStmt>(); 130 129 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>(); 131 ast::Expr * nze = n otZeroExpr( new ast::VariableExpr( dwt->location, dwt ));130 ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt ); 132 131 cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze; 133 132 } … … 200 199 // do-while cannot have declarations in the contitional, so init is always empty 201 200 return new ast::WhileDoStmt( location, 202 notZeroExpr( maybeMoveBuild( ctl )),201 maybeMoveBuild( ctl ), 203 202 buildMoveSingle( stmt ), 204 203 buildMoveOptional( else_ ), … … 213 212 214 213 ast::Expr * astcond = nullptr; // maybe empty 215 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ));214 astcond = maybeMoveBuild( forctl->condition ); 216 215 217 216 ast::Expr * astincr = nullptr; // maybe empty … … 330 329 clause->target = maybeBuild( targetExpr ); 331 330 clause->stmt = maybeMoveBuild( stmt ); 332 clause->when_cond = notZeroExpr( maybeMoveBuild( when ));331 clause->when_cond = maybeMoveBuild( when ); 333 332 334 333 ExpressionNode * next = targetExpr->next; … … 345 344 ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) { 346 345 existing->else_stmt = maybeMoveBuild( stmt ); 347 existing->else_cond = notZeroExpr( maybeMoveBuild( when ));346 existing->else_cond = maybeMoveBuild( when ); 348 347 349 348 (void)location; … … 354 353 existing->timeout_time = maybeMoveBuild( timeout ); 355 354 existing->timeout_stmt = maybeMoveBuild( stmt ); 356 existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ));355 existing->timeout_cond = maybeMoveBuild( when ); 357 356 358 357 (void)location; … … 362 361 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { 363 362 ast::WhenClause * clause = new ast::WhenClause( loc ); 364 clause->when_cond = notZeroExpr( maybeMoveBuild( when ));363 clause->when_cond = maybeMoveBuild( when ); 365 364 clause->stmt = maybeMoveBuild( stmt ); 366 365 clause->target = maybeMoveBuild( targetExpr ); … … 369 368 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) { 370 369 ast::WhenClause * clause = new ast::WhenClause( loc ); 371 clause->when_cond = notZeroExpr( maybeMoveBuild( when ));370 clause->when_cond = maybeMoveBuild( when ); 372 371 clause->stmt = maybeMoveBuild( stmt ); 373 372 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause ); … … 508 507 509 508 ast::Expr * astcond = nullptr; // maybe empty 510 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ));509 astcond = maybeMoveBuild( forctl->condition ); 511 510 512 511 ast::Expr * astincr = nullptr; // maybe empty -
src/Parser/module.mk
raf746cc rdc58e5d 31 31 Parser/parser.yy \ 32 32 Parser/ParserTypes.h \ 33 Parser/parserutility.cc \34 33 Parser/parserutility.h \ 35 34 Parser/RunParser.cpp \ -
src/Parser/parserutility.h
raf746cc rdc58e5d 17 17 18 18 #include "AST/Copy.hpp" // for shallowCopy 19 namespace ast {20 class Expr;21 }22 23 ast::Expr * notZeroExpr( const ast::Expr *orig );24 19 25 20 template< typename T > -
src/ResolvExpr/CandidateFinder.cpp
raf746cc rdc58e5d 46 46 #include "AST/Type.hpp" 47 47 #include "Common/utility.h" // for move, copy 48 #include "Parser/parserutility.h" // for notZeroExpr49 48 #include "SymTab/Mangler.h" 50 49 #include "Tuples/Tuples.h" // for handleTupleAssignment … … 1514 1513 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1515 1514 CandidateFinder finder1( context, tenv ); 1516 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 );1515 ast::ptr<ast::Expr> arg1 = createCondExpr( logicalExpr->arg1 ); 1517 1516 finder1.find( arg1, ResolveMode::withAdjustment() ); 1518 1517 if ( finder1.candidates.empty() ) return; 1519 1518 1520 1519 CandidateFinder finder2( context, tenv ); 1521 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 );1520 ast::ptr<ast::Expr> arg2 = createCondExpr( logicalExpr->arg2 ); 1522 1521 finder2.find( arg2, ResolveMode::withAdjustment() ); 1523 1522 if ( finder2.candidates.empty() ) return; … … 1545 1544 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1546 1545 // candidates for condition 1547 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );1546 ast::ptr<ast::Expr> arg1 = createCondExpr( conditionalExpr->arg1 ); 1548 1547 CandidateFinder finder1( context, tenv ); 1549 1548 finder1.find( arg1, ResolveMode::withAdjustment() ); … … 2166 2165 CandidateRef & choice = winners.front(); 2167 2166 return choice->expr; 2168 // return std::move( choice->expr.get() ); 2167 } 2168 2169 const ast::Expr * createCondExpr( const ast::Expr * expr ) { 2170 assert( expr ); 2171 return new ast::CastExpr( expr->location, 2172 ast::UntypedExpr::createCall( expr->location, 2173 "?!=?", 2174 { 2175 expr, 2176 new ast::ConstantExpr( expr->location, 2177 new ast::ZeroType(), "0", std::make_optional( 0ull ) 2178 ), 2179 } 2180 ), 2181 new ast::BasicType( ast::BasicType::SignedInt ) 2182 ); 2169 2183 } 2170 2184 -
src/ResolvExpr/CandidateFinder.hpp
raf746cc rdc58e5d 72 72 const ast::Expr * getValueEnumCall(const ast::Expr * expr, 73 73 const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env ); 74 /// Wrap an expression to convert the result to a conditional result. 75 const ast::Expr * createCondExpr( const ast::Expr * expr ); 74 76 75 77 } // namespace ResolvExpr -
src/ResolvExpr/Resolver.cc
raf746cc rdc58e5d 340 340 } 341 341 342 ast::ptr< ast::Expr > findCondExpression( 343 const ast::Expr * untyped, const ResolveContext & context 344 ) { 345 if ( nullptr == untyped ) return untyped; 346 ast::ptr<ast::Expr> condExpr = createCondExpr( untyped ); 347 return findIntegralExpression( condExpr, context ); 348 } 349 342 350 /// check if a type is a character type 343 351 bool isCharType( const ast::Type * t ) { … … 356 364 return it != end; 357 365 } 358 } 366 } // anonymous namespace 359 367 360 368 class Resolver final … … 729 737 const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) { 730 738 return ast::mutate_field( 731 ifStmt, &ast::IfStmt::cond, find IntegralExpression( ifStmt->cond, context ) );739 ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) ); 732 740 } 733 741 734 742 const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) { 735 743 return ast::mutate_field( 736 whileDoStmt, &ast::WhileDoStmt::cond, find IntegralExpression( whileDoStmt->cond, context ) );744 whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) ); 737 745 } 738 746 … … 740 748 if ( forStmt->cond ) { 741 749 forStmt = ast::mutate_field( 742 forStmt, &ast::ForStmt::cond, find IntegralExpression( forStmt->cond, context ) );750 forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) ); 743 751 } 744 752 … … 1075 1083 1076 1084 // Resolve the conditions as if it were an IfStmt, statements normally 1077 clause2->when_cond = find SingleExpression( clause.when_cond, context );1085 clause2->when_cond = findCondExpression( clause.when_cond, context ); 1078 1086 clause2->stmt = clause.stmt->accept( *visitor ); 1079 1087 … … 1089 1097 new ast::BasicType{ ast::BasicType::LongLongUnsignedInt }; 1090 1098 auto timeout_time = findSingleExpression( stmt->timeout_time, target, context ); 1091 auto timeout_cond = find SingleExpression( stmt->timeout_cond, context );1099 auto timeout_cond = findCondExpression( stmt->timeout_cond, context ); 1092 1100 auto timeout_stmt = stmt->timeout_stmt->accept( *visitor ); 1093 1101 … … 1102 1110 if ( stmt->else_stmt ) { 1103 1111 // resolve the condition like IfStmt, stmts normally 1104 auto else_cond = find SingleExpression( stmt->else_cond, context );1112 auto else_cond = findCondExpression( stmt->else_cond, context ); 1105 1113 auto else_stmt = stmt->else_stmt->accept( *visitor ); 1106 1114 -
src/Validate/ImplementEnumFunc.cpp
raf746cc rdc58e5d 516 516 ast::EnumInstType enumInst(enumDecl->name); 517 517 enumInst.base = enumDecl; 518 // ast::EnumAttrType attr = ast::EnumAttrType(&enumInst); 519 // EnumAttrFuncGenerator gen(enumDecl, &enumInst functionNesting); 518 520 519 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting); 521 520 gen.generateAndAppendFunctions(declsToAddAfter);
Note: See TracChangeset
for help on using the changeset viewer.