xref: /openbsd-src/gnu/gcc/libcpp/line-map.c (revision 404b540a9034ac75a6199ad1a32d1bbc7a0d4210)
1*404b540aSrobert /* Map logical line numbers to (source file, line number) pairs.
2*404b540aSrobert    Copyright (C) 2001, 2003, 2004
3*404b540aSrobert    Free Software Foundation, Inc.
4*404b540aSrobert 
5*404b540aSrobert This program is free software; you can redistribute it and/or modify it
6*404b540aSrobert under the terms of the GNU General Public License as published by the
7*404b540aSrobert Free Software Foundation; either version 2, or (at your option) any
8*404b540aSrobert later version.
9*404b540aSrobert 
10*404b540aSrobert This program is distributed in the hope that it will be useful,
11*404b540aSrobert but WITHOUT ANY WARRANTY; without even the implied warranty of
12*404b540aSrobert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*404b540aSrobert GNU General Public License for more details.
14*404b540aSrobert 
15*404b540aSrobert You should have received a copy of the GNU General Public License
16*404b540aSrobert along with this program; if not, write to the Free Software
17*404b540aSrobert Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*404b540aSrobert 
19*404b540aSrobert  In other words, you are welcome to use, share and improve this program.
20*404b540aSrobert  You are forbidden to forbid anyone else to use, share and improve
21*404b540aSrobert  what you give them.   Help stamp out software-hoarding!  */
22*404b540aSrobert 
23*404b540aSrobert #include "config.h"
24*404b540aSrobert #include "system.h"
25*404b540aSrobert #include "line-map.h"
26*404b540aSrobert 
27*404b540aSrobert static void trace_include (const struct line_maps *, const struct line_map *);
28*404b540aSrobert 
29*404b540aSrobert /* Initialize a line map set.  */
30*404b540aSrobert 
31*404b540aSrobert void
linemap_init(struct line_maps * set)32*404b540aSrobert linemap_init (struct line_maps *set)
33*404b540aSrobert {
34*404b540aSrobert   set->maps = NULL;
35*404b540aSrobert   set->allocated = 0;
36*404b540aSrobert   set->used = 0;
37*404b540aSrobert   set->last_listed = -1;
38*404b540aSrobert   set->trace_includes = false;
39*404b540aSrobert   set->depth = 0;
40*404b540aSrobert   set->cache = 0;
41*404b540aSrobert   set->highest_location = 0;
42*404b540aSrobert   set->highest_line = 0;
43*404b540aSrobert   set->max_column_hint = 0;
44*404b540aSrobert }
45*404b540aSrobert 
46*404b540aSrobert /* Check for and warn about line_maps entered but not exited.  */
47*404b540aSrobert 
48*404b540aSrobert void
linemap_check_files_exited(struct line_maps * set)49*404b540aSrobert linemap_check_files_exited (struct line_maps *set)
50*404b540aSrobert {
51*404b540aSrobert   struct line_map *map;
52*404b540aSrobert   /* Depending upon whether we are handling preprocessed input or
53*404b540aSrobert      not, this can be a user error or an ICE.  */
54*404b540aSrobert   for (map = &set->maps[set->used - 1]; ! MAIN_FILE_P (map);
55*404b540aSrobert        map = INCLUDED_FROM (set, map))
56*404b540aSrobert     fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n",
57*404b540aSrobert 	     map->to_file);
58*404b540aSrobert }
59*404b540aSrobert 
60*404b540aSrobert /* Free a line map set.  */
61*404b540aSrobert 
62*404b540aSrobert void
linemap_free(struct line_maps * set)63*404b540aSrobert linemap_free (struct line_maps *set)
64*404b540aSrobert {
65*404b540aSrobert   if (set->maps)
66*404b540aSrobert     {
67*404b540aSrobert       linemap_check_files_exited (set);
68*404b540aSrobert 
69*404b540aSrobert       free (set->maps);
70*404b540aSrobert     }
71*404b540aSrobert }
72*404b540aSrobert 
73*404b540aSrobert /* Add a mapping of logical source line to physical source file and
74*404b540aSrobert    line number.
75*404b540aSrobert 
76*404b540aSrobert    The text pointed to by TO_FILE must have a lifetime
77*404b540aSrobert    at least as long as the final call to lookup_line ().  An empty
78*404b540aSrobert    TO_FILE means standard input.  If reason is LC_LEAVE, and
79*404b540aSrobert    TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their
80*404b540aSrobert    natural values considering the file we are returning to.
81*404b540aSrobert 
82*404b540aSrobert    FROM_LINE should be monotonic increasing across calls to this
83*404b540aSrobert    function.  A call to this function can relocate the previous set of
84*404b540aSrobert    A call to this function can relocate the previous set of
85*404b540aSrobert    maps, so any stored line_map pointers should not be used.  */
86*404b540aSrobert 
87*404b540aSrobert const struct line_map *
linemap_add(struct line_maps * set,enum lc_reason reason,unsigned int sysp,const char * to_file,unsigned int to_line)88*404b540aSrobert linemap_add (struct line_maps *set, enum lc_reason reason,
89*404b540aSrobert 	     unsigned int sysp, const char *to_file, unsigned int to_line)
90*404b540aSrobert {
91*404b540aSrobert   struct line_map *map;
92*404b540aSrobert   source_location start_location = set->highest_location + 1;
93*404b540aSrobert 
94*404b540aSrobert   if (set->used && start_location < set->maps[set->used - 1].start_location)
95*404b540aSrobert     abort ();
96*404b540aSrobert 
97*404b540aSrobert   if (set->used == set->allocated)
98*404b540aSrobert     {
99*404b540aSrobert       set->allocated = 2 * set->allocated + 256;
100*404b540aSrobert       set->maps = XRESIZEVEC (struct line_map, set->maps, set->allocated);
101*404b540aSrobert     }
102*404b540aSrobert 
103*404b540aSrobert   map = &set->maps[set->used];
104*404b540aSrobert 
105*404b540aSrobert   if (to_file && *to_file == '\0')
106*404b540aSrobert     to_file = "<stdin>";
107*404b540aSrobert 
108*404b540aSrobert   /* If we don't keep our line maps consistent, we can easily
109*404b540aSrobert      segfault.  Don't rely on the client to do it for us.  */
110*404b540aSrobert   if (set->depth == 0)
111*404b540aSrobert     reason = LC_ENTER;
112*404b540aSrobert   else if (reason == LC_LEAVE)
113*404b540aSrobert     {
114*404b540aSrobert       struct line_map *from;
115*404b540aSrobert       bool error;
116*404b540aSrobert 
117*404b540aSrobert       if (MAIN_FILE_P (map - 1))
118*404b540aSrobert 	{
119*404b540aSrobert 	  if (to_file == NULL)
120*404b540aSrobert 	    {
121*404b540aSrobert 	      set->depth--;
122*404b540aSrobert 	      return NULL;
123*404b540aSrobert 	    }
124*404b540aSrobert 	  error = true;
125*404b540aSrobert           reason = LC_RENAME;
126*404b540aSrobert           from = map - 1;
127*404b540aSrobert 	}
128*404b540aSrobert       else
129*404b540aSrobert 	{
130*404b540aSrobert 	  from = INCLUDED_FROM (set, map - 1);
131*404b540aSrobert 	  error = to_file && strcmp (from->to_file, to_file);
132*404b540aSrobert 	}
133*404b540aSrobert 
134*404b540aSrobert       /* Depending upon whether we are handling preprocessed input or
135*404b540aSrobert 	 not, this can be a user error or an ICE.  */
136*404b540aSrobert       if (error)
137*404b540aSrobert 	fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n",
138*404b540aSrobert 		 to_file);
139*404b540aSrobert 
140*404b540aSrobert       /* A TO_FILE of NULL is special - we use the natural values.  */
141*404b540aSrobert       if (error || to_file == NULL)
142*404b540aSrobert 	{
143*404b540aSrobert 	  to_file = from->to_file;
144*404b540aSrobert 	  to_line = SOURCE_LINE (from, from[1].start_location);
145*404b540aSrobert 	  sysp = from->sysp;
146*404b540aSrobert 	}
147*404b540aSrobert     }
148*404b540aSrobert 
149*404b540aSrobert   map->reason = reason;
150*404b540aSrobert   map->sysp = sysp;
151*404b540aSrobert   map->start_location = start_location;
152*404b540aSrobert   map->to_file = to_file;
153*404b540aSrobert   map->to_line = to_line;
154*404b540aSrobert   set->cache = set->used++;
155*404b540aSrobert   map->column_bits = 0;
156*404b540aSrobert   set->highest_location = start_location;
157*404b540aSrobert   set->highest_line = start_location;
158*404b540aSrobert   set->max_column_hint = 0;
159*404b540aSrobert 
160*404b540aSrobert   if (reason == LC_ENTER)
161*404b540aSrobert     {
162*404b540aSrobert       map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2);
163*404b540aSrobert       set->depth++;
164*404b540aSrobert       if (set->trace_includes)
165*404b540aSrobert 	trace_include (set, map);
166*404b540aSrobert     }
167*404b540aSrobert   else if (reason == LC_RENAME)
168*404b540aSrobert     map->included_from = map[-1].included_from;
169*404b540aSrobert   else if (reason == LC_LEAVE)
170*404b540aSrobert     {
171*404b540aSrobert       set->depth--;
172*404b540aSrobert       map->included_from = INCLUDED_FROM (set, map - 1)->included_from;
173*404b540aSrobert     }
174*404b540aSrobert 
175*404b540aSrobert   return map;
176*404b540aSrobert }
177*404b540aSrobert 
178*404b540aSrobert source_location
linemap_line_start(struct line_maps * set,unsigned int to_line,unsigned int max_column_hint)179*404b540aSrobert linemap_line_start (struct line_maps *set, unsigned int to_line,
180*404b540aSrobert 		    unsigned int max_column_hint)
181*404b540aSrobert {
182*404b540aSrobert   struct line_map *map = &set->maps[set->used - 1];
183*404b540aSrobert   source_location highest = set->highest_location;
184*404b540aSrobert   source_location r;
185*404b540aSrobert   unsigned int last_line = SOURCE_LINE (map, set->highest_line);
186*404b540aSrobert   int line_delta = to_line - last_line;
187*404b540aSrobert   bool add_map = false;
188*404b540aSrobert   if (line_delta < 0
189*404b540aSrobert       || (line_delta > 10 && line_delta * map->column_bits > 1000)
190*404b540aSrobert       || (max_column_hint >= (1U << map->column_bits))
191*404b540aSrobert       || (max_column_hint <= 80 && map->column_bits >= 10))
192*404b540aSrobert     {
193*404b540aSrobert       add_map = true;
194*404b540aSrobert     }
195*404b540aSrobert   else
196*404b540aSrobert     max_column_hint = set->max_column_hint;
197*404b540aSrobert   if (add_map)
198*404b540aSrobert     {
199*404b540aSrobert       int column_bits;
200*404b540aSrobert       if (max_column_hint > 100000 || highest > 0xC0000000)
201*404b540aSrobert 	{
202*404b540aSrobert 	  /* If the column number is ridiculous or we've allocated a huge
203*404b540aSrobert 	     number of source_locations, give up on column numbers. */
204*404b540aSrobert 	  max_column_hint = 0;
205*404b540aSrobert 	  if (highest >0xF0000000)
206*404b540aSrobert 	    return 0;
207*404b540aSrobert 	  column_bits = 0;
208*404b540aSrobert 	}
209*404b540aSrobert       else
210*404b540aSrobert 	{
211*404b540aSrobert 	  column_bits = 7;
212*404b540aSrobert 	  while (max_column_hint >= (1U << column_bits))
213*404b540aSrobert 	    column_bits++;
214*404b540aSrobert 	  max_column_hint = 1U << column_bits;
215*404b540aSrobert 	}
216*404b540aSrobert       /* Allocate the new line_map.  However, if the current map only has a
217*404b540aSrobert 	 single line we can sometimes just increase its column_bits instead. */
218*404b540aSrobert       if (line_delta < 0
219*404b540aSrobert 	  || last_line != map->to_line
220*404b540aSrobert 	  || SOURCE_COLUMN (map, highest) >= (1U << column_bits))
221*404b540aSrobert 	map = (struct line_map*) linemap_add (set, LC_RENAME, map->sysp,
222*404b540aSrobert 				      map->to_file, to_line);
223*404b540aSrobert       map->column_bits = column_bits;
224*404b540aSrobert       r = map->start_location + ((to_line - map->to_line) << column_bits);
225*404b540aSrobert     }
226*404b540aSrobert   else
227*404b540aSrobert     r = highest - SOURCE_COLUMN (map, highest)
228*404b540aSrobert       + (line_delta << map->column_bits);
229*404b540aSrobert   set->highest_line = r;
230*404b540aSrobert   if (r > set->highest_location)
231*404b540aSrobert     set->highest_location = r;
232*404b540aSrobert   set->max_column_hint = max_column_hint;
233*404b540aSrobert   return r;
234*404b540aSrobert }
235*404b540aSrobert 
236*404b540aSrobert source_location
linemap_position_for_column(struct line_maps * set,unsigned int to_column)237*404b540aSrobert linemap_position_for_column (struct line_maps *set, unsigned int to_column)
238*404b540aSrobert {
239*404b540aSrobert   source_location r = set->highest_line;
240*404b540aSrobert   if (to_column >= set->max_column_hint)
241*404b540aSrobert     {
242*404b540aSrobert       if (r >= 0xC000000 || to_column > 100000)
243*404b540aSrobert 	{
244*404b540aSrobert 	  /* Running low on source_locations - disable column numbers.  */
245*404b540aSrobert 	  return r;
246*404b540aSrobert 	}
247*404b540aSrobert       else
248*404b540aSrobert 	{
249*404b540aSrobert 	  struct line_map *map = &set->maps[set->used - 1];
250*404b540aSrobert 	  r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50);
251*404b540aSrobert 	}
252*404b540aSrobert     }
253*404b540aSrobert   r = r + to_column;
254*404b540aSrobert   if (r >= set->highest_location)
255*404b540aSrobert     set->highest_location = r;
256*404b540aSrobert   return r;
257*404b540aSrobert }
258*404b540aSrobert 
259*404b540aSrobert /* Given a logical line, returns the map from which the corresponding
260*404b540aSrobert    (source file, line) pair can be deduced.  Since the set is built
261*404b540aSrobert    chronologically, the logical lines are monotonic increasing, and so
262*404b540aSrobert    the list is sorted and we can use a binary search.  */
263*404b540aSrobert 
264*404b540aSrobert const struct line_map *
linemap_lookup(struct line_maps * set,source_location line)265*404b540aSrobert linemap_lookup (struct line_maps *set, source_location line)
266*404b540aSrobert {
267*404b540aSrobert   unsigned int md, mn, mx;
268*404b540aSrobert   const struct line_map *cached;
269*404b540aSrobert 
270*404b540aSrobert   mn = set->cache;
271*404b540aSrobert   mx = set->used;
272*404b540aSrobert 
273*404b540aSrobert   cached = &set->maps[mn];
274*404b540aSrobert   /* We should get a segfault if no line_maps have been added yet.  */
275*404b540aSrobert   if (line >= cached->start_location)
276*404b540aSrobert     {
277*404b540aSrobert       if (mn + 1 == mx || line < cached[1].start_location)
278*404b540aSrobert 	return cached;
279*404b540aSrobert     }
280*404b540aSrobert   else
281*404b540aSrobert     {
282*404b540aSrobert       mx = mn;
283*404b540aSrobert       mn = 0;
284*404b540aSrobert     }
285*404b540aSrobert 
286*404b540aSrobert   while (mx - mn > 1)
287*404b540aSrobert     {
288*404b540aSrobert       md = (mn + mx) / 2;
289*404b540aSrobert       if (set->maps[md].start_location > line)
290*404b540aSrobert 	mx = md;
291*404b540aSrobert       else
292*404b540aSrobert 	mn = md;
293*404b540aSrobert     }
294*404b540aSrobert 
295*404b540aSrobert   set->cache = mn;
296*404b540aSrobert   return &set->maps[mn];
297*404b540aSrobert }
298*404b540aSrobert 
299*404b540aSrobert /* Print the file names and line numbers of the #include commands
300*404b540aSrobert    which led to the map MAP, if any, to stderr.  Nothing is output if
301*404b540aSrobert    the most recently listed stack is the same as the current one.  */
302*404b540aSrobert 
303*404b540aSrobert void
linemap_print_containing_files(struct line_maps * set,const struct line_map * map)304*404b540aSrobert linemap_print_containing_files (struct line_maps *set,
305*404b540aSrobert 				const struct line_map *map)
306*404b540aSrobert {
307*404b540aSrobert   if (MAIN_FILE_P (map) || set->last_listed == map->included_from)
308*404b540aSrobert     return;
309*404b540aSrobert 
310*404b540aSrobert   set->last_listed = map->included_from;
311*404b540aSrobert   map = INCLUDED_FROM (set, map);
312*404b540aSrobert 
313*404b540aSrobert   fprintf (stderr,  _("In file included from %s:%u"),
314*404b540aSrobert 	   map->to_file, LAST_SOURCE_LINE (map));
315*404b540aSrobert 
316*404b540aSrobert   while (! MAIN_FILE_P (map))
317*404b540aSrobert     {
318*404b540aSrobert       map = INCLUDED_FROM (set, map);
319*404b540aSrobert       /* Translators note: this message is used in conjunction
320*404b540aSrobert 	 with "In file included from %s:%ld" and some other
321*404b540aSrobert 	 tricks.  We want something like this:
322*404b540aSrobert 
323*404b540aSrobert 	 | In file included from sys/select.h:123,
324*404b540aSrobert 	 |                  from sys/types.h:234,
325*404b540aSrobert 	 |                  from userfile.c:31:
326*404b540aSrobert 	 | bits/select.h:45: <error message here>
327*404b540aSrobert 
328*404b540aSrobert 	 with all the "from"s lined up.
329*404b540aSrobert 	 The trailing comma is at the beginning of this message,
330*404b540aSrobert 	 and the trailing colon is not translated.  */
331*404b540aSrobert       fprintf (stderr, _(",\n                 from %s:%u"),
332*404b540aSrobert 	       map->to_file, LAST_SOURCE_LINE (map));
333*404b540aSrobert     }
334*404b540aSrobert 
335*404b540aSrobert   fputs (":\n", stderr);
336*404b540aSrobert }
337*404b540aSrobert 
338*404b540aSrobert /* Print an include trace, for e.g. the -H option of the preprocessor.  */
339*404b540aSrobert 
340*404b540aSrobert static void
trace_include(const struct line_maps * set,const struct line_map * map)341*404b540aSrobert trace_include (const struct line_maps *set, const struct line_map *map)
342*404b540aSrobert {
343*404b540aSrobert   unsigned int i = set->depth;
344*404b540aSrobert 
345*404b540aSrobert   while (--i)
346*404b540aSrobert     putc ('.', stderr);
347*404b540aSrobert   fprintf (stderr, " %s\n", map->to_file);
348*404b540aSrobert }
349