1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /><title>Chapter2.The Compiler</title><meta name="generator" content="DocBook XSL Stylesheets V1.62.4" /><link rel="home" href="index.html" title="SBCL User Manual" /><link rel="up" href="index.html" title="SBCL User Manual" /><link rel="previous" href="implementation.html" title="Overview Of SBCL, How It Works And Where It Came From" /><link rel="next" href="compiler-types.html" title="The Compiler's Handling of Types" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter2.The Compiler</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="implementation.html">Prev</a></td><th width="60%" align="center"></th><td width="20%" align="right"><a accesskey="n" href="compiler-types.html">Next</a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="compiler"></a>Chapter2.The Compiler</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="compiler.html#error-messages">Error Messages</a></span></dt><dd><dl><dt><span class="sect2"><a href="compiler.html#id2897853">The Parts of the Error Message</a></span></dt><dt><span class="sect2"><a href="compiler.html#id2906982">The Original and Actual Source</a></span></dt><dt><span class="sect2"><a href="compiler.html#id2957752">The Processing Path</a></span></dt><dt><span class="sect2"><a href="compiler.html#id2957842">Error Severity</a></span></dt><dt><span class="sect2"><a href="compiler.html#id2957898">Errors During Macroexpansion</a></span></dt><dt><span class="sect2"><a href="compiler.html#id2831850">Read Errors</a></span></dt></dl></dd><dt><span class="sect1"><a href="compiler-types.html">The Compiler's Handling of Types</a></span></dt><dd><dl><dt><span class="sect2"><a href="compiler-types.html#compiler-impl-limitations">Implementation Limitations</a></span></dt><dt><span class="sect2"><a href="compiler-types.html#id2831996">Type Errors at Compile Time</a></span></dt><dt><span class="sect2"><a href="compiler-types.html#precisetypechecking">Precise Type Checking</a></span></dt><dt><span class="sect2"><a href="compiler-types.html#weakened-type-checking">Weakened Type Checking</a></span></dt><dt><span class="sect2"><a href="compiler-types.html#id2839069">Getting Existing Programs to Run</a></span></dt></dl></dd><dt><span class="sect1"><a href="compiler-policy.html">Compiler Policy</a></span></dt><dt><span class="sect1"><a href="open-coding.html">Open Coding and Inline Expansion</a></span></dt></dl></div><p>This chapter will discuss most compiler issues other than
efficiency, including compiler error messages, the <span class="application">SBCL</span> compiler's
unusual approach to type safety in the presence of type declarations,
the effects of various compiler optimization policies, and the way
that inlining and open coding may cause optimized code to differ from
a naive translation. Efficiency issues are sufficiently varied and
separate that they have <a href="efficiency.html" title="Chapter3.Efficiency">their own
chapter</a>.</p><div class="sect1" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="error-messages"></a>Error Messages</h2></div></div><div></div></div><p>The compiler supplies a large amount of source location
information in error messages. The error messages contain a lot of
detail in a terse format, so they may be confusing at first. Error
messages will be illustrated using this example program:
</p><pre class="programlisting">(defmacro zoq (x)
`(roq (ploq (+ ,x 3))))
(defun foo (y)
(declare (symbol y))
(zoq y))</pre><p>
The main problem with this program is that it is trying to add
<tt class="literal">3</tt> to a symbol. Note also that the functions
<tt class="function">roq</tt> and <tt class="function">ploq</tt> aren't defined anywhere.
</p><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id2897853"></a>The Parts of the Error Message</h3></div></div><div></div></div><p>When processing this program, the compiler will produce this
warning:
</p><pre class="screen">file: /tmp/foo.lisp
in: DEFUN FOO
(ZOQ Y)
--> ROQ PLOQ +
==>
Y
caught WARNING:
Result is a SYMBOL, not a NUMBER.</pre><p>
In this example we see each of the six possible parts of a compiler error
message:
</p><div class="orderedlist"><ol type="1"><li><p><tt class="computeroutput">File: /tmp/foo.lisp</tt>
This is the name of the file that the compiler read the relevant
code from. The file name is displayed because it may not be
immediately obvious when there is an error during compilation of a
large system, especially when
<tt class="function">with-compilation-unit</tt> is used to delay
undefined warnings.</p></li><li><p><tt class="computeroutput">in: DEFUN FOO</tt> This is the
definition top level form responsible for the error. It is
obtained by taking the first two elements of the enclosing form
whose first element is a symbol beginning with “<span class="quote"><tt class="literal">def</tt></span>”.
If there is no such enclosing “<span class="quote"><tt class="literal">def</tt></span>” form, then the
outermost form is used. If there are multiple <tt class="literal">def</tt>
forms, then they are all printed from the outside in, separated by
<tt class="literal">=></tt>'s. In this example, the problem was in the
<tt class="function">defun</tt> for <tt class="function">foo</tt>.</p></li><li><p><tt class="computeroutput">(ZOQ Y)</tt> This is the
<span class="emphasis"><em>original source</em></span> form responsible for the error.
Original source means that the form directly appeared in the
original input to the compiler, i.e. in the lambda passed to
<tt class="function">compile</tt> or in the top level form read from the
source file. In this example, the expansion of the <tt class="function">zoq</tt>
macro was responsible for the error.</p></li><li><p><tt class="computeroutput">--> ROQ PLOQ +</tt> This is the
<span class="emphasis"><em>processing path</em></span> that the compiler used to produce
the errorful code. The processing path is a representation of
the evaluated forms enclosing the actual source that the
compiler encountered when processing the original source.
The path is the first element of each form, or the form itself
if the form is not a list. These forms result from the
expansion of macros or source-to-source transformation done
by the compiler. In this example, the enclosing evaluated forms
are the calls to <tt class="function">roq</tt>, <tt class="function">ploq</tt> and
<tt class="function">+</tt>. These calls resulted from the expansion of
the <tt class="function">zoq</tt> macro.</p></li><li><p><tt class="computeroutput">==> Y</tt> This is the
<span class="emphasis"><em>actual source</em></span> responsible for the error. If
the actual source appears in the explanation, then
we print the next enclosing evaluated form, instead of
printing the actual source twice. (This is the form
that would otherwise have been the last form of the processing
path.) In this example, the problem is with the evaluation of
the reference to the variable <tt class="varname">y</tt>.</p></li><li><p>
<tt class="computeroutput">caught WARNING: Result is a SYMBOL, not a NUMBER.</tt>
This is the <span class="emphasis"><em>explanation</em></span> of the problem. In this
example, the problem is that <tt class="varname">y</tt> evaluates to a symbol,
but is in a context where a number is required (the argument
to <tt class="function">+</tt>).</p></li></ol></div><p>
Note that each part of the error message is distinctively marked:
</p><div class="itemizedlist"><ul type="disc"><li><p> <tt class="computeroutput">file:</tt> and <tt class="computeroutput">in:</tt>
mark the file and definition, respectively.</p></li><li><p> The original source is an indented form with no
prefix.</p></li><li><p> Each line of the processing path is prefixed with
<tt class="computeroutput">--></tt></p></li><li><p> The actual source form is indented like the original
source, but is marked by a preceding <tt class="computeroutput">==></tt> line.
</p></li><li><p> The explanation is prefixed with the error
severity, which can be <tt class="computeroutput">caught ERROR:</tt>,
<tt class="computeroutput">caught WARNING:</tt>,
<tt class="computeroutput">caught STYLE-WARNING:</tt>, or
<tt class="computeroutput">note:</tt>. </p></li></ul></div><p>
</p><p>Each part of the error message is more specific than the preceding
one. If consecutive error messages are for nearby locations, then the
front part of the error messages would be the same. In this case, the
compiler omits as much of the second message as in common with the
first. For example:
</p><pre class="screen">file: /tmp/foo.lisp
in: DEFUN FOO
(ZOQ Y)
--> ROQ
==>
(PLOQ (+ Y 3))
caught STYLE-WARNING:
undefined function: PLOQ
==>
(ROQ (PLOQ (+ Y 3)))
caught STYLE-WARNING:
undefined function: ROQ</pre><p>
In this example, the file, definition and original source are
identical for the two messages, so the compiler omits them in the
second message. If consecutive messages are entirely identical, then
the compiler prints only the first message, followed by:
<tt class="computeroutput">[Last message occurs <i class="replaceable"><tt>repeats</tt></i> times]</tt>
where <i class="replaceable"><tt>repeats</tt></i> is the number of times the message
was given.</p><p>If the source was not from a file, then no file line is printed.
If the actual source is the same as the original source, then the
processing path and actual source will be omitted. If no forms
intervene between the original source and the actual source, then the
processing path will also be omitted.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id2906982"></a>The Original and Actual Source</h3></div></div><div></div></div><p>The <span class="emphasis"><em>original source</em></span> displayed will almost always be
a list. If the actual source for an error message is a symbol, the
original source will be the immediately enclosing evaluated list form.
So even if the offending symbol does appear in the original source,
the compiler will print the enclosing list and then print the symbol
as the actual source (as though the symbol were introduced by a
macro.)</p><p>When the <span class="emphasis"><em>actual source</em></span> is displayed
(and is not a symbol), it will always
be code that resulted from the expansion of a macro or a source-to-source
compiler optimization. This is code that did not appear in the original
source program; it was introduced by the compiler.</p><p>Keep in mind that when the compiler displays a source form
in an error message, it always displays the most specific (innermost)
responsible form. For example, compiling this function
</p><pre class="programlisting">(defun bar (x)
(let (a)
(declare (fixnum a))
(setq a (foo x))
a))</pre><p>
gives this error message
</p><pre class="screen">in: DEFUN BAR
(LET (A) (DECLARE (FIXNUM A)) (SETQ A (FOO X)) A)
caught WARNING: The binding of A is not a FIXNUM:
NIL</pre><p>
This error message is not saying “<span class="quote">there is a problem somewhere in
this <tt class="function">let</tt></span>” — it is saying that there is a
problem with the <tt class="function">let</tt> itself. In this example, the problem
is that <tt class="varname">a</tt>'s <tt class="literal">nil</tt> initial value is not a
<tt class="type">fixnum</tt>.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id2957752"></a>The Processing Path</h3></div></div><div></div></div><p>The processing path is mainly useful for debugging macros, so if
you don't write macros, you can probably ignore it. Consider this
example:
</p><pre class="programlisting">(defun foo (n)
(dotimes (i n *undefined*)))
</pre><p>
Compiling results in this error message:
</p><pre class="screen">in: DEFUN FOO
(DOTIMES (I N *UNDEFINED*))
--> DO BLOCK LET TAGBODY RETURN-FROM
==>
(PROGN *UNDEFINED*)
caught STYLE-WARNING:
undefined variable: *UNDEFINED*</pre><p>
Note that <tt class="function">do</tt> appears in the processing path. This is because
<tt class="function">dotimes</tt> expands into:
</p><pre class="programlisting">(do ((i 0 (1+ i)) (#:g1 n))
((>= i #:g1) *undefined*)
(declare (type unsigned-byte i)))</pre><p>
The rest of the processing path results from the expansion
of <tt class="function">do</tt>:
</p><pre class="programlisting">
(block nil
(let ((i 0) (#:g1 n))
(declare (type unsigned-byte i))
(tagbody (go #:g3)
#:g2 (psetq i (1+ i))
#:g3 (unless (>= i #:g1) (go #:g2))
(return-from nil (progn *undefined*)))))
</pre><p>
In this example, the compiler descended into the <tt class="function">block</tt>,
<tt class="function">let</tt>, <tt class="function">tagbody</tt> and <tt class="function">return-from</tt> to
reach the <tt class="function">progn</tt> printed as the actual source. This is a
place where the “<span class="quote">actual source appears in explanation</span>” rule
was applied. The innermost actual source form was the symbol
<tt class="varname">*undefined*</tt> itself, but that also appeared in the
explanation, so the compiler backed out one level.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id2957842"></a>Error Severity</h3></div></div><div></div></div><p>There are four levels of compiler error severity:
<i class="wordasword">error</i>, <i class="wordasword">warning</i>, <i class="wordasword">style
warning</i>, and <i class="wordasword">note</i>. The first three levels correspond
to condition classes which are defined in the <span class="acronym">ANSI</span> standard for
Common Lisp and which have special significance to the
<tt class="function">compile</tt> and <tt class="function">compile-file</tt> functions. These
levels of compiler error severity occur when the compiler handles
conditions of these classes. The fourth level of compiler error
severity, <i class="wordasword">note</i>, is used for problems which are too mild
for the standard condition classes, typically hints about how
efficiency might be improved.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id2957898"></a>Errors During Macroexpansion</h3></div></div><div></div></div><p>The compiler handles errors that happen during macroexpansion,
turning them into compiler errors. If you want to debug the error (to
debug a macro), you can set <tt class="varname">*break-on-signals*</tt> to
<tt class="literal">error</tt>. For example, this definition:
</p><pre class="programlisting">(defun foo (e l)
(do ((current l (cdr current))
((atom current) nil))
(when (eq (car current) e) (return current))))</pre><p>
gives this error:
</p><pre class="screen">in: DEFUN FOO
(DO ((CURRENT L #) (# NIL)) (WHEN (EQ # E) (RETURN CURRENT)) )
caught ERROR:
(in macroexpansion of (DO # #))
(hint: For more precise location, try *BREAK-ON-SIGNALS*.)
DO step variable is not a symbol: (ATOM CURRENT)</pre><p>
</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id2831850"></a>Read Errors</h3></div></div><div></div></div><p><span class="application">SBCL</span>'s compiler (unlike <span class="application">CMU CL</span>'s) does not attempt to recover
from read errors when reading a source file, but instead just reports
the offending character position and gives up on the entire source
file.</p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="implementation.html">Prev</a></td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"><a accesskey="n" href="compiler-types.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Overview Of SBCL, How It Works And Where It Came From</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">The Compiler's Handling of Types</td></tr></table></div></body></html>
|