Changes in / [dc58e5d:af746cc]
- Files:
-
- 1 added
- 18 edited
-
doc/theses/mike_brooks_MMath/background.tex (modified) (9 diffs)
-
doc/theses/mike_brooks_MMath/programs/bkgd-carray-arrty.c (modified) (1 diff)
-
doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/cluster.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (2 diffs)
-
libcfa/src/heap.cfa (modified) (28 diffs)
-
libcfa/src/heap.hfa (modified) (3 diffs)
-
libcfa/src/stdlib.hfa (modified) (5 diffs)
-
src/AST/Pass.hpp (modified) (1 diff)
-
src/AST/Pass.impl.hpp (modified) (10 diffs)
-
src/AST/Pass.proto.hpp (modified) (8 diffs)
-
src/Parser/StatementNode.cc (modified) (10 diffs)
-
src/Parser/module.mk (modified) (1 diff)
-
src/Parser/parserutility.cc (added)
-
src/Parser/parserutility.h (modified) (1 diff)
-
src/ResolvExpr/CandidateFinder.cpp (modified) (4 diffs)
-
src/ResolvExpr/CandidateFinder.hpp (modified) (1 diff)
-
src/ResolvExpr/Resolver.cc (modified) (7 diffs)
-
src/Validate/ImplementEnumFunc.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/mike_brooks_MMath/background.tex
rdc58e5d raf746cc 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 bythe type system.48 This misguided analogue works for a single-dimension arraybut 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.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 arrays but there is no advantage other than possibly teaching beginning programmers about basic runtime array-access. 49 50 Continuing, a shortened form for declaring local variables exists, provided that length information is given in the initializer: 51 51 \lstinput{59-62}{bkgd-carray-arrty.c} 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: 52 In these declarations, the resulting types are both arrays, but their lengths are inferred. 53 54 My contribution is enabled by recognizing 57 55 \begin{itemize} 58 \item There is value in using a type that knows its size.56 \item There is value in using a type that knows how big the whole thing is. 59 57 \item The type pointer to (first) element does not. 60 58 \item C \emph{has} a type that knows the whole picture: 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.)} 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]@. 65 60 \end{itemize} 66 61 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}} \\ 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 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: 74 79 \begin{cfa} 75 int @(*@ar@)[@5@]@; // definition 76 ... @(*@ar@)[@3@]@ += 1; // usage 80 [ * [10] T ] x; 77 81 \end{cfa} 78 & 79 \begin{cfa} 80 int @(*@f@())[@5@]@ { ... }; // definition 81 ... @(*@f@())[@3@]@ += 1; // usage 82 \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} 87 \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 83 175 \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. 128 The simplest occurrences of types distinguished in the preceding discussion are marked with $\triangleright$. 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} 133 \centering 134 \caption{Syntactic Reference for Array vs Pointer. Includes interaction with \lstinline{const}ness.} 176 \caption{Unfortunate Syntactic Reference for Array vs Pointer. Includes interaction with constness.} 135 177 \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 \end{tabular} 176 \end{table} 178 \end{figure} 179 180 181 182 177 183 178 184 TODO: Address these parked unfortunate syntaxes … … 180 186 \item static 181 187 \item star as dimension 182 \item under pointer decay: @int p1[const 3]@ being @int const *p1@188 \item under pointer decay: int p1[const 3] being int const *p1 183 189 \end{itemize} 184 190 … … 197 203 \lstinput{10-10}{bkgd-carray-decay.c} 198 204 199 So, C provides an implicit conversion from @float[10]@ to @float *@.205 So, C provides an implicit conversion from @float[10]@ to @float*@, as described in ARM-6.3.2.1.3: 200 206 \begin{quote} 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} 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 204 212 \end{quote} 213 205 214 This phenomenon is the famous ``pointer decay,'' which is a decay of an array-typed expression into a pointer-typed one. 215 206 216 It is worthy to note that the list of exception cases does not feature the occurrence of @ar@ in @ar[i]@. 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! 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. 213 224 214 225 Subscripting a pointer when the target is standard-inappropriate is still practically well-defined. … … 222 233 fs[5] = 3.14; 223 234 \end{cfa} 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. 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 229 246 No pointer is exempt from array diffraction. 247 230 248 No array shows its elements without pointer decay. 231 249 232 250 A further pointer--array confusion, closely related to decay, occurs in parameter declarations. 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 asthe 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.251 ARM-6.7.6.3.7 explains that when an array type is written for a parameter, 252 the parameter's type becomes a type that I summarize as being the array-decayed type. 253 The respective handlings of the following two parameter spellings shows that the array-spelled one is really, like the other, a pointer. 236 254 \lstinput{12-16}{bkgd-carray-decay.c} 237 255 As the @sizeof(x)@ meaning changed, compared with when run on a similarly-spelled local variable declaration, 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: 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: 243 259 \lstinput{18-21}{bkgd-carray-decay.c} 244 260 This fragment gives no warnings. … … 256 272 depending on whether the object is a local variable or a parameter. 257 273 274 258 275 In summary, when a function is written with an array-typed parameter, 259 276 \begin{itemize} … … 266 283 As a result, a function with a pointer-to-array parameter sees the parameter exactly as the caller does: 267 284 \lstinput{32-42}{bkgd-carray-decay.c} 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} 285 286 \VRef[Figure]{bkgd:ar:usr:decay-parm} gives the reference for the decay phenomenon seen in parameter decalarations. 287 288 \begin{figure} 274 289 \centering 275 290 \begin{tabular}{llllll} 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 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 304 322 \end{tabular} 305 \end{table} 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} 306 326 307 327 308 328 \subsection{Lengths may vary, checking does not} 309 329 310 When the desired number of elements is unknown at compile time, a variable-length array is a solution: 330 When the desired number of elements is unknown at compile time, 331 a variable-length array is a solution: 311 332 \begin{cfa} 312 int main( int argc, const char * argv[] ) {333 int main( int argc, const char *argv[] ) { 313 334 assert( argc == 2 ); 314 335 size_t n = atol( argv[1] ); 315 assert( 0 < n ); 336 assert( 0 < n && n < 1000 ); 337 316 338 float ar[n]; 317 339 float b[10]; 340 318 341 // ... discussion continues here 319 342 } 320 343 \end{cfa} 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. 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: 330 348 \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 ) );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 ) ); 335 353 \end{cfa} 336 354 355 356 VLA 357 337 358 Parameter dependency 338 359 … … 342 363 343 364 344 \subsection{Dynamically sized, multidimensional arrays} 365 366 \subsection{C has full-service, dynamically sized, multidimensional arrays (and \CC does not)} 345 367 346 368 In C and \CC, ``multidimensional array'' means ``array of arrays.'' Other meanings are discussed in TODO. … … 394 416 \section{Linked List} 395 417 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 400 418 401 419 \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
rdc58e5d raf746cc 57 57 f( &ar ); 58 58 59 float fs[] = {3.14, 1.7 7};59 float fs[] = {3.14, 1.707}; 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) );68 64 } 69 65 -
doc/theses/mike_brooks_MMath/programs/bkgd-carray-decay.c
rdc58e5d raf746cc 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 eteris pointer}$24 char *cp = "hello"; $\C{// pointer to read-only data [decay here]}$ 25 void edit( char c[] ) { $\C{// param 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( c p ); $\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
rdc58e5d raf746cc 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 419 418 cltr->sched.caches = alloc( target, cltr->sched.caches`realloc ); 420 419 … … 429 428 430 429 // Make sure that everything is consistent 431 ///* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );430 /* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) ); 432 431 /* paranoid */ check_readyQ( cltr ); 433 432 -
libcfa/src/concurrency/kernel/startup.cfa
rdc58e5d raf746cc 672 672 uint_fast32_t last_size = ready_mutate_lock(); 673 673 674 // Adjust the ready queue size675 ready_queue_shrink( &this );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
rdc58e5d raf746cc 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Apr 7 21:54:29202413 // Update Count : 16 4412 // Last Modified On : Wed Jan 3 21:30:54 2024 13 // Update Count : 1619 14 14 // 15 15 … … 114 114 115 115 116 // CFAgeneric Bsearchl does not inline, so substitute with hand-coded binary-search.116 // 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_ 0_calls;192 unsigned int free_calls, free_null_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 { // 4-byte word => 8-byte header, 8-byte word => 16-byte header234 struct RealHeader { 235 235 union { 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 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 }; 241 246 }; 242 size_t size; // allocation size in bytes243 247 } real; // RealHeader 244 248 … … 257 261 258 262 struct CALIGN FreeHeader { 263 size_t blockSize CALIGN; // size of allocations on this list 259 264 #ifdef OWNERSHIP 260 265 #ifdef RETURNSPIN … … 266 271 Storage * freeList; // thread free list 267 272 Heap * homeManager; // heap owner (free storage to bucket, from bucket to heap) 268 size_t blockSize; // size of allocations on this list269 273 }; // FreeHeader 270 274 … … 365 369 static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing 366 370 static __thread Heap * heapManager CALIGN TLSMODEL; 367 static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false;371 static __thread bool heapManagerBootFlag CALIGN TLSMODEL = false; 368 372 static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing 369 373 … … 591 595 592 596 #ifdef __STATISTICS__ 597 static HeapStatistics stats; // zero filled 598 593 599 #define prtFmt \ 594 600 "\nHeap statistics: (storage request / allocation)\n" \ … … 601 607 " resize >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \ 602 608 " realloc >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \ 603 " free !null calls %'u; null /0calls %'u; storage %'llu / %'llu bytes\n" \609 " free !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \ 604 610 " return pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \ 605 611 " sbrk calls %'u; storage %'llu bytes\n" \ … … 621 627 resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc, 622 628 realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc, 623 free_calls, free_null_ 0_calls, free_storage_request, free_storage_alloc,629 free_calls, free_null_calls, free_storage_request, free_storage_alloc, 624 630 return_pulls, return_pushes, return_storage_request, return_storage_alloc, 625 631 sbrk_calls, sbrk_storage, … … 644 650 "<total type=\"resize\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 645 651 "<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 646 "<total type=\"free\" !null=\"%'u;\" 0 null /0=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \652 "<total type=\"free\" !null=\"%'u;\" 0 null=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 647 653 "<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 648 654 "<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \ … … 664 670 resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc, 665 671 realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc, 666 free_calls, free_null_ 0_calls, free_storage_request, free_storage_alloc,672 free_calls, free_null_calls, free_storage_request, free_storage_alloc, 667 673 return_pulls, return_pushes, return_storage_request, return_storage_alloc, 668 674 sbrk_calls, sbrk_storage, … … 793 799 } else { 794 800 fakeHeader( header, alignment ); 795 if ( unlikely( MmappedBit( header ) ) ) { // mmapped storage?801 if ( unlikely( MmappedBit( header ) ) ) { // mmapped ? 796 802 verify( addr < heapBegin || heapEnd < addr ); 797 803 size = ClearStickyBits( header->kind.real.blockSize ); // mmap size 798 freeHead = 0p; // prevent uninitialized warning799 804 return true; 800 805 } // if … … 899 904 900 905 906 #define BOOT_HEAP_MANAGER \ 907 if ( unlikely( ! heapMasterBootFlag ) ) { \ 908 heapManagerCtor(); /* trigger for first heap */ \ 909 } /* if */ 910 901 911 #ifdef __STATISTICS__ 902 912 #define STAT_NAME __counter 903 913 #define STAT_PARM , unsigned int STAT_NAME 904 914 #define STAT_ARG( name ) , name 905 #define STAT_0_CNT( counter ) heapManager->stats.counters[counter].calls_0 += 1915 #define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1 906 916 #else 907 917 #define STAT_NAME … … 911 921 #endif // __STATISTICS__ 912 922 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 // 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 */ 927 #else 928 #define __NULL_0_ALLOC__ 929 #endif // __NONNULL_0_ALLOC__ 930 931 #define PROLOG( counter, ... ) \ 932 BOOT_HEAP_MANAGER; \ 933 if ( \ 934 __NULL_0_ALLOC__ \ 935 unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \ 923 936 STAT_0_CNT( counter ); \ 924 __VA_ARGS__; /* call routine, if specified */\937 __VA_ARGS__; \ 925 938 return 0p; \ 926 939 } /* if */ 927 #else 928 #define __NULL_0_ALLOC__( counter, ... ) 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__ 940 941 #define PROLOG( counter, ... ) \ 942 BOOT_HEAP_MANAGER; \ 943 __NULL_0_ALLOC__( counter, __VA_ARGS__ ) \ 944 __OVERFLOW_MALLOC__( __VA_ARGS__ ) 940 945 941 946 942 #define SCRUB_SIZE 1024lu … … 952 948 PROLOG( STAT_NAME ); 953 949 950 verify( heapManager ); 954 951 Heap.Storage * block; // pointer to new block of storage 955 952 … … 959 956 960 957 #ifdef __STATISTICS__ 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; 958 stats.counters[STAT_NAME].calls += 1; 967 959 stats.counters[STAT_NAME].request += size; 968 960 #endif // __STATISTICS__ … … 1086 1078 1087 1079 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 1092 1080 verify( addr ); 1093 1081 … … 1103 1091 #endif // __STATISTICS__ || __CFA_DEBUG__ 1104 1092 1105 // Do not move these down because heap can be null!1106 1093 #ifdef __STATISTICS__ 1107 #ifdef __NONNULL_0_ALLOC__1108 if ( unlikely( rsize == 0 ) ) // malloc( 0 ) ?1109 stats.free_null_0_calls += 1;1110 else1111 #endif // __NONNULL_0_ALLOC__1112 heapManager->stats.free_calls += 1; // count free amd implicit frees from resize/realloc1113 1094 stats.free_storage_request += rsize; 1114 1095 stats.free_storage_alloc += size; … … 1136 1117 } // if 1137 1118 } else { 1138 assert( freeHead );1139 1119 #ifdef __CFA_DEBUG__ 1140 1120 // memset is NOT always inlined! … … 1341 1321 // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done. 1342 1322 void * resize( void * oaddr, size_t size ) libcfa_public { 1343 if ( unlikely( oaddr == 0p ) ) { // => malloc( size )1323 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1344 1324 return doMalloc( size STAT_ARG( RESIZE ) ); 1345 1325 } // if … … 1353 1333 1354 1334 size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket 1355 // same size, DO NOT PRESERVESTICKY PROPERTIES.1335 // same size, DO NOT preserve STICKY PROPERTIES. 1356 1336 if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size 1357 1337 ClearZeroFillBit( header ); // no alignment and turn off 0 fill … … 1366 1346 } // if 1367 1347 1368 // change size, DO NOT PRESERVESTICKY PROPERTIES.1348 // change size, DO NOT preserve STICKY PROPERTIES. 1369 1349 doFree( oaddr ); // free previous storage 1370 1350 … … 1376 1356 // the old and new sizes. 1377 1357 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 );1381 1358 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1382 1359 return doMalloc( size STAT_ARG( REALLOC ) ); … … 1521 1498 } // if 1522 1499 1500 #ifdef __STATISTICS__ 1501 incCalls( FREE ); 1502 #endif // __STATISTICS__ 1503 1523 1504 doFree( addr ); // handles heapManager == nullptr 1524 1505 } // free … … 1598 1579 #endif // __STATISTICS__ 1599 1580 } // malloc_stats_clear 1581 1600 1582 1601 1583 // Changes the file descriptor where malloc_stats() writes statistics. … … 1718 1700 } // if 1719 1701 1720 // change size, DO NOT PRESERVESTICKY PROPERTIES.1702 // change size, DO NOT preserve STICKY PROPERTIES. 1721 1703 doFree( oaddr ); // free previous storage 1722 1704 return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); // create new aligned area … … 1725 1707 1726 1708 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 );1730 1709 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1731 1710 return memalignNoStats( nalign, size STAT_ARG( REALLOC ) ); -
libcfa/src/heap.hfa
rdc58e5d raf746cc 10 10 // Created On : Tue May 26 11:23:55 2020 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 1 09:36:20 202413 // Update Count : 2 512 // Last Modified On : Mon Sep 11 11:18:18 2023 13 // Update Count : 24 14 14 // 15 15 … … 46 46 } // extern "C" 47 47 48 // New allocation operations.49 48 void * resize( void * oaddr, size_t alignment, size_t size ); 50 49 void * realloc( void * oaddr, size_t alignment, size_t size ); … … 52 51 53 52 // Local Variables: // 53 // mode: c // 54 54 // tab-width: 4 // 55 55 // End: // -
libcfa/src/stdlib.hfa
rdc58e5d raf746cc 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 12 07:39:15202413 // Update Count : 81212 // Last Modified On : Sun Mar 17 08:25:31 2024 13 // Update Count : 796 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 { char c; T * a; T t; };112 struct S_fill { char tag; U_fill(T) fill; };113 struct S_realloc { inline T *; };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 ) { 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; }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 { inline size_t; } T_align;151 typedef struct S_resize { inline void *; } T_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 { char tag; char c; size_t size; T * at; char t[50]; };155 struct S_realloc { inline T *; };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 161 extern "C" ssize_t write(int fd, const void *buf, size_t count); 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 162 161 static inline forall( T & | sized(T) ) { 163 162 S_fill(T) ?`fill ( T t ) { … … 170 169 return ret; 171 170 } 172 S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved173 S_fill(T) ?`fill ( T * a ){ return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved174 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}; }171 S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved 172 S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved 173 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}; } 178 177 179 178 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) { … … 183 182 184 183 if ( Resize ) { 185 ptr = (T*) (void *)resize( (void *)Resize, Align, Dim * size );184 ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size ); 186 185 } else if ( Realloc ) { 187 186 if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size ); 188 ptr = (T *) (void *)realloc( (void *)Realloc, Align, Dim * size );187 ptr = (T *) (void *) realloc( (void *)Realloc, Align, Dim * size ); 189 188 } else { 190 ptr = (T *) (void *) memalign( Align, Dim * size );189 ptr = (T *) (void *) memalign( Align, Dim * size ); 191 190 } 192 191 -
src/AST/Pass.hpp
rdc58e5d raf746cc 252 252 private: 253 253 254 /// The return type of the general call_accept function. 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. 255 259 template< typename node_t > 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 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 > 259 268 >; 260 269 261 270 template< typename node_t > 262 auto call_accept( const node_t * node ) -> call_accept_result_t<node_t>; 271 auto call_accept( const node_t * node ) 272 -> typename generic_call_accept_result<node_t>::type; 263 273 264 274 // requests WithStmtsToAdd directly add to this statement, as if it is a compound. -
src/AST/Pass.impl.hpp
rdc58e5d raf746cc 109 109 return val; 110 110 } 111 112 //------------------------------ 113 /// Check if value was mutated, different for pointers and containers 114 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 } 111 123 } 112 124 … … 114 126 template< typename node_t > 115 127 auto ast::Pass< core_t >::call_accept( const node_t * node ) -> 116 ast::Pass< core_t >::call_accept_result_t<node_t> { 128 typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type 129 { 117 130 __pedantic_pass_assert( __visit_children() ); 118 131 __pedantic_pass_assert( node ); 119 132 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 120 136 auto nval = node->accept( *this ); 121 return { nval != node, nval }; 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 }; 122 161 } 123 162 … … 191 230 ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 192 231 __pedantic_pass_assert( __visit_children() ); 193 __pedantic_pass_assert( !statements.empty() );232 if ( statements.empty() ) return {}; 194 233 195 234 // We are going to aggregate errors for all these statements … … 224 263 const ast::Stmt * new_stmt = stmt->accept( *this ); 225 264 assert( new_stmt ); 265 if ( new_stmt != stmt ) { new_kids.differs = true; } 226 266 227 267 // Make sure that it is either adding statements or declartions but not both … … 236 276 // Now add the statement if there is one 237 277 if ( new_stmt != stmt ) { 238 new_kids.differs = true; 239 new_kids.values.emplace_back( new_stmt ); 278 new_kids.values.emplace_back( new_stmt, i, false ); 240 279 } else { 241 new_kids.values.emplace_back( i);280 new_kids.values.emplace_back( nullptr, i, true ); 242 281 } 243 282 … … 259 298 ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 260 299 __pedantic_pass_assert( __visit_children() ); 261 __pedantic_pass_assert( !container.empty() ); 262 263 // Collect errors from processing all these nodes. 300 if ( container.empty() ) return {}; 264 301 SemanticErrorException errors; 265 302 … … 305 342 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 306 343 307 auto result = call_accept( old_val ); 308 if ( result.differs ) { 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 ) { 309 349 auto new_parent = __pass::mutate<core_t>(parent); 310 result.apply( new_parent, field);350 new_val.apply(new_parent, field); 311 351 parent = new_parent; 312 352 } … … 326 366 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 327 367 328 auto result = call_accept_top( old_val ); 329 if ( result.differs ) { 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 ) { 330 373 auto new_parent = __pass::mutate<core_t>(parent); 331 result.apply( new_parent, field);374 new_val.apply(new_parent, field); 332 375 parent = new_parent; 333 376 } … … 347 390 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 348 391 349 auto result = call_accept_as_compound( old_val ); 350 if ( result.differs ) { 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 ) { 351 397 auto new_parent = __pass::mutate<core_t>(parent); 352 result.apply( new_parent, child );398 new_val.apply( new_parent, child ); 353 399 parent = new_parent; 354 400 } … … 406 452 template< typename core_t > 407 453 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) { 408 if ( auto ptr = __pass::translation Unit( visitor.core, 0 ) ) {454 if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) { 409 455 ValueGuard<const TranslationUnit *> guard( *ptr ); 410 456 *ptr = &unit; -
src/AST/Pass.proto.hpp
rdc58e5d raf746cc 154 154 bool is_old; 155 155 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) {}156 delta(const Stmt * s, ssize_t i, bool old) : 157 new_val(s), old_idx(i), is_old(old) {} 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() );190 return delta( stmt.release(), -1, false ); 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 ) );203 return delta( new DeclStmt( d->location, d ), -1, false ); 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 implementation 232 /// We need to reassign the result to 'node', unless the function 233 /// returns void, then we just leave 'node' unchanged 234 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 implementation 255 /// We need to return the result unless the function 256 /// returns void, then we just return the original node 257 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 ); 228 274 } 229 275 }; … … 251 297 ); 252 298 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 } 299 __assign< 300 std::is_void< 301 decltype( core.previsit( node ) ) 302 >::value 303 >::result( core, node ); 261 304 } 262 305 … … 269 312 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 270 313 { 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 } 314 return __return< 315 std::is_void< 316 decltype( core.postvisit( node ) ) 317 >::value 318 >::result( core, node ); 279 319 } 280 320 … … 310 350 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 311 351 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 312 FIELD_PTR( translationUnit, const TranslationUnit * )313 352 314 353 // Remove the macro to make sure we don't clash … … 507 546 } // namespace forall 508 547 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 509 562 // For passes, usually utility passes, that have a result. 510 563 namespace result { -
src/Parser/StatementNode.cc
rdc58e5d raf746cc 122 122 ast::Expr * cond = nullptr; 123 123 if ( ctl->condition ) { 124 cond = maybeMoveBuild( ctl->condition ); 124 // compare the provided condition against 0 125 cond = notZeroExpr( maybeMoveBuild( ctl->condition ) ); 125 126 } else { 126 127 for ( ast::ptr<ast::Stmt> & stmt : inits ) { … … 128 129 auto declStmt = stmt.strict_as<ast::DeclStmt>(); 129 130 auto dwt = declStmt->decl.strict_as<ast::DeclWithType>(); 130 ast::Expr * nze = n ew ast::VariableExpr( dwt->location, dwt);131 ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) ); 131 132 cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze; 132 133 } … … 199 200 // do-while cannot have declarations in the contitional, so init is always empty 200 201 return new ast::WhileDoStmt( location, 201 maybeMoveBuild( ctl),202 notZeroExpr( maybeMoveBuild( ctl ) ), 202 203 buildMoveSingle( stmt ), 203 204 buildMoveOptional( else_ ), … … 212 213 213 214 ast::Expr * astcond = nullptr; // maybe empty 214 astcond = maybeMoveBuild( forctl->condition);215 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) ); 215 216 216 217 ast::Expr * astincr = nullptr; // maybe empty … … 329 330 clause->target = maybeBuild( targetExpr ); 330 331 clause->stmt = maybeMoveBuild( stmt ); 331 clause->when_cond = maybeMoveBuild( when);332 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 332 333 333 334 ExpressionNode * next = targetExpr->next; … … 344 345 ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) { 345 346 existing->else_stmt = maybeMoveBuild( stmt ); 346 existing->else_cond = maybeMoveBuild( when);347 existing->else_cond = notZeroExpr( maybeMoveBuild( when ) ); 347 348 348 349 (void)location; … … 353 354 existing->timeout_time = maybeMoveBuild( timeout ); 354 355 existing->timeout_stmt = maybeMoveBuild( stmt ); 355 existing->timeout_cond = maybeMoveBuild( when);356 existing->timeout_cond = notZeroExpr( maybeMoveBuild( when ) ); 356 357 357 358 (void)location; … … 361 362 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { 362 363 ast::WhenClause * clause = new ast::WhenClause( loc ); 363 clause->when_cond = maybeMoveBuild( when);364 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 364 365 clause->stmt = maybeMoveBuild( stmt ); 365 366 clause->target = maybeMoveBuild( targetExpr ); … … 368 369 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) { 369 370 ast::WhenClause * clause = new ast::WhenClause( loc ); 370 clause->when_cond = maybeMoveBuild( when);371 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) ); 371 372 clause->stmt = maybeMoveBuild( stmt ); 372 373 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause ); … … 507 508 508 509 ast::Expr * astcond = nullptr; // maybe empty 509 astcond = maybeMoveBuild( forctl->condition);510 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) ); 510 511 511 512 ast::Expr * astincr = nullptr; // maybe empty -
src/Parser/module.mk
rdc58e5d raf746cc 31 31 Parser/parser.yy \ 32 32 Parser/ParserTypes.h \ 33 Parser/parserutility.cc \ 33 34 Parser/parserutility.h \ 34 35 Parser/RunParser.cpp \ -
src/Parser/parserutility.h
rdc58e5d raf746cc 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 ); 19 24 20 25 template< typename T > -
src/ResolvExpr/CandidateFinder.cpp
rdc58e5d raf746cc 46 46 #include "AST/Type.hpp" 47 47 #include "Common/utility.h" // for move, copy 48 #include "Parser/parserutility.h" // for notZeroExpr 48 49 #include "SymTab/Mangler.h" 49 50 #include "Tuples/Tuples.h" // for handleTupleAssignment … … 1513 1514 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1514 1515 CandidateFinder finder1( context, tenv ); 1515 ast::ptr<ast::Expr> arg1 = createCondExpr( logicalExpr->arg1 );1516 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 ); 1516 1517 finder1.find( arg1, ResolveMode::withAdjustment() ); 1517 1518 if ( finder1.candidates.empty() ) return; 1518 1519 1519 1520 CandidateFinder finder2( context, tenv ); 1520 ast::ptr<ast::Expr> arg2 = createCondExpr( logicalExpr->arg2 );1521 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 ); 1521 1522 finder2.find( arg2, ResolveMode::withAdjustment() ); 1522 1523 if ( finder2.candidates.empty() ) return; … … 1544 1545 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1545 1546 // candidates for condition 1546 ast::ptr<ast::Expr> arg1 = createCondExpr( conditionalExpr->arg1 );1547 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 ); 1547 1548 CandidateFinder finder1( context, tenv ); 1548 1549 finder1.find( arg1, ResolveMode::withAdjustment() ); … … 2165 2166 CandidateRef & choice = winners.front(); 2166 2167 return choice->expr; 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 ); 2168 // return std::move( choice->expr.get() ); 2183 2169 } 2184 2170 -
src/ResolvExpr/CandidateFinder.hpp
rdc58e5d raf746cc 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 );76 74 77 75 } // namespace ResolvExpr -
src/ResolvExpr/Resolver.cc
rdc58e5d raf746cc 340 340 } 341 341 342 ast::ptr< ast::Expr > findCondExpression(343 const ast::Expr * untyped, const ResolveContext & context344 ) {345 if ( nullptr == untyped ) return untyped;346 ast::ptr<ast::Expr> condExpr = createCondExpr( untyped );347 return findIntegralExpression( condExpr, context );348 }349 350 342 /// check if a type is a character type 351 343 bool isCharType( const ast::Type * t ) { … … 364 356 return it != end; 365 357 } 366 } // anonymous namespace358 } 367 359 368 360 class Resolver final … … 737 729 const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) { 738 730 return ast::mutate_field( 739 ifStmt, &ast::IfStmt::cond, find CondExpression( ifStmt->cond, context ) );731 ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) ); 740 732 } 741 733 742 734 const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) { 743 735 return ast::mutate_field( 744 whileDoStmt, &ast::WhileDoStmt::cond, find CondExpression( whileDoStmt->cond, context ) );736 whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) ); 745 737 } 746 738 … … 748 740 if ( forStmt->cond ) { 749 741 forStmt = ast::mutate_field( 750 forStmt, &ast::ForStmt::cond, find CondExpression( forStmt->cond, context ) );742 forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) ); 751 743 } 752 744 … … 1083 1075 1084 1076 // Resolve the conditions as if it were an IfStmt, statements normally 1085 clause2->when_cond = find CondExpression( clause.when_cond, context );1077 clause2->when_cond = findSingleExpression( clause.when_cond, context ); 1086 1078 clause2->stmt = clause.stmt->accept( *visitor ); 1087 1079 … … 1097 1089 new ast::BasicType{ ast::BasicType::LongLongUnsignedInt }; 1098 1090 auto timeout_time = findSingleExpression( stmt->timeout_time, target, context ); 1099 auto timeout_cond = find CondExpression( stmt->timeout_cond, context );1091 auto timeout_cond = findSingleExpression( stmt->timeout_cond, context ); 1100 1092 auto timeout_stmt = stmt->timeout_stmt->accept( *visitor ); 1101 1093 … … 1110 1102 if ( stmt->else_stmt ) { 1111 1103 // resolve the condition like IfStmt, stmts normally 1112 auto else_cond = find CondExpression( stmt->else_cond, context );1104 auto else_cond = findSingleExpression( stmt->else_cond, context ); 1113 1105 auto else_stmt = stmt->else_stmt->accept( *visitor ); 1114 1106 -
src/Validate/ImplementEnumFunc.cpp
rdc58e5d raf746cc 516 516 ast::EnumInstType enumInst(enumDecl->name); 517 517 enumInst.base = enumDecl; 518 518 // ast::EnumAttrType attr = ast::EnumAttrType(&enumInst); 519 // EnumAttrFuncGenerator gen(enumDecl, &enumInst functionNesting); 519 520 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting); 520 521 gen.generateAndAppendFunctions(declsToAddAfter);
Note:
See TracChangeset
for help on using the changeset viewer.