Bug 57950 - wrong line numbers in error messages for inline assembler statements
Summary: wrong line numbers in error messages for inline assembler statements
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: inline-asm (show other bugs)
Version: 4.7.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-07-21 19:16 UTC by Frank Heckenbach
Modified: 2016-06-23 10:48 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Frank Heckenbach 2013-07-21 19:16:15 UTC
This was reported as Debian bug #588087 several years ago ...

For error messages concerning inline assembler statements, gcc
counts embedded "\n" characters towards the line number, instead of
actual newlines in the source file, so the error messages refer to
the wrong lines.

Compiling the test program below with "gcc asm-line-number.c" gives
this output:

asm-line-number.c: Assembler messages:
asm-line-number.c:3: Error: no such instruction: `foo'
asm-line-number.c:4: Error: no such instruction: `foo'
asm-line-number.c:8: Error: no such instruction: `foo'

In f1(), both asm errors are in the same source line (3), but gcc
counts them as different because of the "\n" between them.

In f2(), the line number refers to the line (8) which contains
"__asm__" instead of the line (10) with the actual asm code.

static void f1 ()
{
  __asm__ ("foo\nfoo");
}

static void f2 ()
{
  __asm__
    (
      "foo"
    );
}
Comment 1 Andrew Pinski 2013-07-21 20:19:09 UTC
It is not GCC which is reporting this error message but rather gas (binutils) though GCC is reporting to binutils the line info for the start of the inline-asm.
Comment 2 Andreas Schwab 2013-07-21 20:21:12 UTC
GCC uses the line number of the start of the asm statement, so line 8 is correct.
Comment 3 Manuel López-Ibáñez 2013-07-22 11:26:02 UTC
(In reply to Andreas Schwab from comment #2)
> GCC uses the line number of the start of the asm statement, so line 8 is
> correct.

"Correct" as "expected" but not as "desired".

This is what Clang prints by comparison:

asm-line-number.c:3:12: error: invalid instruction mnemonic 'foo'
  __asm__ ("foo\nfoo");
           ^
<inline asm>:1:2: note: instantiated into assembly here
        foo
        ^~~
asm-line-number.c:3:18: error: invalid instruction mnemonic 'foo'
  __asm__ ("foo\nfoo");
                 ^
<inline asm>:2:1: note: instantiated into assembly here
foo
^~~
asm-line-number.c:10:7: error: invalid instruction mnemonic 'foo'
      "foo"
      ^
<inline asm>:1:2: note: instantiated into assembly here
        foo
        ^~~
3 errors generated.

It seems difficult to get there without an integrated assembler, but GCC could at least provide better locations to GAS (and GAS understand and print column numbers), so we could get:

asm-line-number.c: Assembler messages:
asm-line-number.c:3:12: Error: no such instruction: `foo'
asm-line-number.c:3:18: Error: no such instruction: `foo'
asm-line-number.c:10:7: Error: no such instruction: `foo'

Any editor worth its salt would jump to the correct line and column in the sources.
Comment 4 Frank Heckenbach 2013-07-22 11:42:10 UTC
(In reply to Manuel López-Ibáñez from comment #3)
> (In reply to Andreas Schwab from comment #2)
> > GCC uses the line number of the start of the asm statement, so line 8 is
> > correct.
> 
> "Correct" as "expected" but not as "desired".

And it would only explain the latter messages, not the former ones
reported as lines 3 and 4.

> This is what Clang prints by comparison:
> 
> asm-line-number.c:3:12: error: invalid instruction mnemonic 'foo'
>   __asm__ ("foo\nfoo");
>            ^
> <inline asm>:1:2: note: instantiated into assembly here
>         foo
>         ^~~
> asm-line-number.c:3:18: error: invalid instruction mnemonic 'foo'
>   __asm__ ("foo\nfoo");
>                  ^
> <inline asm>:2:1: note: instantiated into assembly here
> foo
> ^~~
> asm-line-number.c:10:7: error: invalid instruction mnemonic 'foo'
>       "foo"
>       ^
> <inline asm>:1:2: note: instantiated into assembly here
>         foo
>         ^~~
> 3 errors generated.
> 
> It seems difficult to get there without an integrated assembler, but GCC
> could at least provide better locations to GAS (and GAS understand and print
> column numbers), so we could get:
> 
> asm-line-number.c: Assembler messages:
> asm-line-number.c:3:12: Error: no such instruction: `foo'
> asm-line-number.c:3:18: Error: no such instruction: `foo'
> asm-line-number.c:10:7: Error: no such instruction: `foo'
> 
> Any editor worth its salt would jump to the correct line and column in the
> sources.

The clang output is indeed very nice, though to me, the wrong line
numbers (at least in the presence of "\n") are the more serious
problem than the lack of column numbers.
Comment 5 Andreas Schwab 2013-07-22 12:41:25 UTC
The error messages are all generated by the assembler which knows nothing about the source file.
Comment 6 Manuel López-Ibáñez 2013-07-22 13:03:43 UTC
(In reply to Andreas Schwab from comment #5)
> The error messages are all generated by the assembler which knows nothing
> about the source file.

It knows the locations passed by GCC. (And it could know the column also, if gas supported that). GCC seem to be passing wrong line numbers.
Comment 7 Andreas Schwab 2013-07-22 13:26:56 UTC
There is no way to know how the newline was written.
Comment 8 Manuel López-Ibáñez 2013-07-22 18:25:21 UTC
(In reply to Andreas Schwab from comment #7)
> There is no way to know how the newline was written.

Sorry I don't get this. Could you elaborate?

There are some technical limitations of GCC:

* string constants don't have their own location:
* asm expressions only have one location (starting at the "asm" keyword)
* GCC currently doesn't look at all into the string constant given to an asm expression.

First, it is not clear that the location given to asm expressions needs to be the location of the asm keyword. It could be the location of the string and it would be already an improvement.

Second, when printing the assembler, GCC can check for newlines and simply print the line directive after each newline. I see one potential problem:

 static void f1 ()
{
  __asm__ ("foo\n"
           "foo");
}

This works OK now by pure chance but it will be broken by the above trick. To reliably fix this, GCC must learn to track locations of multi-line strings. Interestingly, the same problem we face when improving the diagnostics for -Wformat: PR52952
Comment 9 Andreas Schwab 2013-07-22 19:34:26 UTC
The assembler only sees literal newlines, it does not know how they were written in the source.

The compiler cannot put line directives in the middle of an assembler string by itself because it cannot know how the assembler will interpret the text around the newline.  This will surely break things.
Comment 10 Manuel López-Ibáñez 2013-07-22 20:22:43 UTC
(In reply to Andreas Schwab from comment #9)
> The assembler only sees literal newlines, it does not know how they were
> written in the source.

Is there other way to generate literal newlines apart from printing a literal newline? And why it matters how they were written in the source code? The point is that GCC should see that it is a literal newline and hint GAS that it was actually in the same line (or not) in the original source code. GAS does not need to know anything.
 
> The compiler cannot put line directives in the middle of an assembler string
> by itself because it cannot know how the assembler will interpret the text
> around the newline.  This will surely break things.

If there are restrictions on the lines where the location directives can appear in an assembler file, then it is a problem, yes. I wasn't aware of such restrictions, I was assuming that they were basically like preprocessor directives.

Oh, well, another reason why an integrated assembler is such a good idea...
Comment 11 Andreas Schwab 2013-07-22 21:37:41 UTC
See the example in the original description.
Comment 12 Manuel López-Ibáñez 2014-04-16 20:44:59 UTC
(In reply to Andreas Schwab from comment #11)
> See the example in the original description.

For the original example, GCC just has to generate this:

# 3 "pr57950.c" 1
        foo
# 3 "pr57950.c" 1
foo

to get the correct line numbers.

But the idea of the clang people of integrating the assembler is of course much superior: you get column numbers + caret + consistent diagnostic format + colors.

I am quite happy I don't have to use inline-asm with GCC, it doesn't sound fun at all.