[Bug c++/107360] ICE on sizeof(*f(x)) when f's (deduced) return type is a pointer to VLA

2023-01-29 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107360

--- Comment #4 from Alexey Izbyshev  ---
(In reply to Martin Uecker from comment #3)
> I think there there are cases were variably modified
> return types are allowed in ISO C:
> 
> void f(int n, double (*(bar(void)))[n])
> {
> double (*p)[n] = bar();
> }

Yes, I should have been more precise. Per C11 6.7.6.2:

> If an identifier is declared as having a variably modified type, it shall be 
> an ordinary identifier (as defined in 6.2.3), have no linkage, and have 
> either block scope or function prototype scope.

So, since my original example is in C++ and involves return type deduction,
what I really wanted to say is that it's not allowed to *define* a function
with a variably modified return type in ISO C (hence it seems fine to not
support it in GCC's VLA extension for C++ too and consider such code invalid).

GCC does allow to define a nested function with a variably modified return type
though, and, perhaps surprisingly, a test case similar to my original C++ one
is compiled successfully:

extern int n;

int f() {
  int a[n];
  int (*g())[n] {
return &a;
  };
  return sizeof *g();
}

But what would seem to be a C++ equivalent crashes GCC:

extern int n;

int f() {
  int a[n];
  auto g = [&]() {
return &a;
  };
  return sizeof *g();
}

during RTL pass: expand
: In function 'int f()':
:6:13: internal compiler error: in expand_expr_real_1, at expr.cc:10586
6 | return &a;
  | ^
...

And for this one it's less clear to me whether GCC wants to consider it
invalid.

But without return type deduction GCC refuses to compile:

extern int n;

int f() {
  typedef int t[n];
  t a;
  auto g = [&]() -> t* {
return &a;
  };
  return sizeof *g();
}

: In function 'int f()':
:6:12: error: data member may not have variably modified type 'int
(*())[n]'
6 |   auto g = [&]() -> t* {
  |^
:6:12: error: declaration of 'operator()' as non-function
Compiler returned: 1

[Bug c++/107360] ICE on sizeof(*f(x)) when f's (deduced) return type is a pointer to VLA

2022-10-23 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107360

--- Comment #2 from Alexey Izbyshev  ---
(In reply to Andrew Pinski from comment #1)
> Maybe this should be invalid code ...

Yes, I think it should be invalid. VLAs are not allowed in function return
types in C. VLAs in C++ are a GCC extension, but it's unclear to me why (and
how) GCC should allow them in return types, even when they don't depend on
function parameters.

Currently, GCC crashes even in the latter case, e.g.:

extern int n;

auto f() {
int (*a)[n] = 0;
return a;
}

int g() {
return sizeof *f();
}

[Bug c++/107360] New: ICE on sizeof(*f(x)) when f's (deduced) return type is a pointer to VLA

2022-10-23 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107360

Bug ID: 107360
   Summary: ICE on sizeof(*f(x)) when f's (deduced) return type is
a pointer to VLA
   Product: gcc
   Version: 12.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: izbyshev at ispras dot ru
  Target Milestone: ---

auto f(int n) {
int (*a)[n] = 0;
return a;
}

int g() {
return sizeof *f(1);
}

Output of GCC 12.2:

during RTL pass: expand
: In function 'int g()':
:7:23: internal compiler error: in expand_expr_real_1, at expr.cc:10586
7 | return sizeof *f(1);
  |   ^
0x1bb069e internal_error(char const*, ...)
???:0
0x6ff396 fancy_abort(char const*, int, char const*)
???:0
0xab97bd expand_expr_real_2(separate_ops*, rtx_def*, machine_mode,
expand_modifier)
???:0
0xaab144 expand_expr_real_1(tree_node*, rtx_def*, machine_mode,
expand_modifier, rtx_def**, bool)
???:0
0xab97bd expand_expr_real_2(separate_ops*, rtx_def*, machine_mode,
expand_modifier)
???:0
0xaab144 expand_expr_real_1(tree_node*, rtx_def*, machine_mode,
expand_modifier, rtx_def**, bool)
???:0
0xab38c4 expand_operands(tree_node*, tree_node*, rtx_def*, rtx_def**,
rtx_def**, expand_modifier)
???:0
0xaba7ac expand_expr_real_2(separate_ops*, rtx_def*, machine_mode,
expand_modifier)
???:0
0xaab144 expand_expr_real_1(tree_node*, rtx_def*, machine_mode,
expand_modifier, rtx_def**, bool)
???:0
0xabb2c9 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode,
expand_modifier)
???:0
0xaab144 expand_expr_real_1(tree_node*, rtx_def*, machine_mode,
expand_modifier, rtx_def**, bool)
???:0

All versions supporting C++14 return type deduction (i.e. since 4.8) produce
ICE, except 4.9, which generates wrong code for g() instead (it returns 1
regardless of f's argument).

[Bug preprocessor/106767] Failure to detect recursive macro calls due to _Pragma(pop_macro)

2022-08-29 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106767

--- Comment #5 from Alexey Izbyshev  ---
(In reply to Richard Biener from comment #4)
> Is there a public specification of the Microsoft extension and how it is
> supposed to behave with recursion or is the recursion behavior specified
> by the C standard?

I would be surprised if anything that could be called "a public specification"
exists. The Clang patch[1] from 2010 cites only the rudimentary MSDN
documentation[2].

I've modified the first test case to be compilable to assembler to avoid
relying on broken /E:

#define P(x) _Pragma(#x)
#define f() P(push_macro("f")) P(pop_macro("f")) f()
int f() {
return 42;
}

and have checked that:

* All x64 MSVC versions supporting C99 _Pragma and available at godbolt
(19.25-19.33/latest) successfully compile it (with and without /Zc:preprocessor
option which enables standard-conforming preprocessor, where it's supported).
The only exception is 19.26 with /Zc:preprocessor: it emits strange syntax
errors, but that's likely a bug in the new preprocessor (19.26 is the first
version supporting it).

* All x64 MSVC versions available at godbolt (19.0, 19.10, 19.14-19.33/latest)
successfully compile the same test case with _Pragma(#x) replaced with
MSVC-specific __pragma(x) equivalent (again, with and without /Zc:preprocessor
where supported).

This suggests that push/pop_macro isn't supposed to interfere with recursion
detection.

[1]
https://github.com/llvm/llvm-project/commit/c0a585d63c6cf700ea01f1fe30c9f4cd51c1e97b
[2] https://docs.microsoft.com/en-us/cpp/preprocessor/push-macro

[Bug preprocessor/106767] Failure to detect recursive macro calls due to _Pragma(pop_macro)

2022-08-28 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106767

--- Comment #3 from Alexey Izbyshev  ---
> I can make newer one recognize _Pragma only by unquoting the string literal
I've investigated this strange behavior because MSVC docs do claim that C99
_Pragma is properly supported[1].

It turned out that /E (preprocess) MSVC option is semi-broken and its output
can't be trusted. When it's specified, ill-formed _Pragma with arguments that
are tokens instead of a string literal appears to behave like simple #pragma:

> type test.c
#define X 1
_Pragma(push_macro("X"))
#undef X
#define X 2
_Pragma(pop_macro("X"))
int x = X;

> cl /E /std:c11 test.c

Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29910 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
#line 1 "test.c"

int x = 1 ;

And correct _Pragma with a string literal is only expanded to MSVC-internal
__pragma, without actually "executing" it, so X is expanded incorrectly below:

> type test.c
#define X 1
_Pragma("push_macro(\"X\")")
#undef X
#define X 2
_Pragma("pop_macro(\"X\")")
int x = X;

> cl /E /std:c11 test.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29910 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
#line 1 "test.c"

__pragma(push_macro("X"))


__pragma(pop_macro("X"))
int x = 2 ;

However, without /E it works as expected: ill-formed _Pragma is a syntax error,
and proper _Pragma is processed, e.g. with the previous example X is expanded
to 1:

>cl /c /Facon /std:c11 test.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29910 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.28.29910.0

include listing.inc

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  x
_DATA   SEGMENT
x   DD  01H
_DATA   ENDS
END

Nothing of the above changes the fact that macro recursion is detected properly
by MSVC, so Clang and MSVC behave the same way in this regard.

[1]
https://docs.microsoft.com/en-us/cpp/preprocessor/pragma-directives-and-the-pragma-keyword?view=msvc-170

[Bug preprocessor/106767] Failure to detect recursive macro calls due to _Pragma(pop_macro)

2022-08-28 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106767

--- Comment #2 from Alexey Izbyshev  ---
Old MSVC doesn't support _Pragma, and I can make newer one recognize _Pragma
only by unquoting the string literal, so the first test case becomes:

// Removed stringizing in _Pragma
#define P(x) _Pragma(x)
#define f() P(push_macro("f")) P(pop_macro("f")) f()
f()

Recursion is detected properly:

> cl /E test.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29910 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
#line 1 "test.c"

  f()

The second test case modified in the same way also works:

Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29910 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

add.c
#line 1 "add.c"

1,   ADD(0, 1, 1, 0)

[Bug preprocessor/106767] New: Failure to detect recursive macro calls due to _Pragma(pop_macro)

2022-08-28 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106767

Bug ID: 106767
   Summary: Failure to detect recursive macro calls due to
_Pragma(pop_macro)
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: preprocessor
  Assignee: unassigned at gcc dot gnu.org
  Reporter: izbyshev at ispras dot ru
CC: amonakov at gcc dot gnu.org
  Target Milestone: ---

GCC preprocessor appears to behave as if each _Pragma(pop_macro("m")) creates a
new definition of "m", so, for example, the following code results in infinite
recursion:

#define P(x) _Pragma(#x)
#define f() P(push_macro("f")) P(pop_macro("f")) f()
f()

Naturally, this makes the preprocessor Turing-complete, e.g. it can add
numbers:

#define P(x) _Pragma(#x)
#define PUSH(x) P(push_macro(#x))
#define POP(x) P(pop_macro(#x))
#define R(f) PUSH(f) POP(f)
#define C(x, y) x ## y
#define ADD0(...) __VA_ARGS__
#define ADD1(...) 1, R(ADD) ADD(__VA_ARGS__)
#define ADD(x, ...) C(ADD, x)(__VA_ARGS__)

// 1 + 2 (zero-terminated unary numbers)
ADD(1, 0, 1, 1, 0)
// Outputs 1, 1, 1, 0 with "gcc -E -P"

The earliest GCC with this behavior on https://godbolt.org is 4.4.7.

Clang detects recursion correctly.

[Bug target/105355] -msmall-data-limit= unexpectedly accepts a separate argument

2022-04-26 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105355

--- Comment #3 from Alexey Izbyshev  ---
(In reply to Martin Liška from comment #2)

Yes, "gcc test.h -o test.pch" uses the separate spelling of "--output-pch=" in
cc1 command line (but, curiously, "gcc test.h" uses the joined spelling).

[Bug driver/105355] New: -msmall-data-limit= unexpectedly accepts a separate argument

2022-04-22 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105355

Bug ID: 105355
   Summary: -msmall-data-limit= unexpectedly accepts a separate
argument
   Product: gcc
   Version: 10.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: driver
  Assignee: unassigned at gcc dot gnu.org
  Reporter: izbyshev at ispras dot ru
  Target Milestone: ---
Target: riscv64-linux-gnu

"msmall-data-limit=" is marked as both Joined and Separate at
https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/config/riscv/riscv.opt;h=492aad1232404c2711811c3d04f2e02902d1b740;hb=7964ab6c364c410c34efe7ca2eba797d36525349#l95.

This is inconsistent with other "-m" options (which permit only joined
spelling) and allows strange commands like "riscv64-linux-gnu-gcc
-msmall-data-limit= 0 test.c".

Note that even if joined spelling is used by the user, GCC driver splits it for
the frontend:

riscv64-linux-gnu-gcc -msmall-data-limit=0 test.c -###
[...]
 /usr/lib/gcc-cross/riscv64-linux-gnu/10/cc1 -quiet -imultilib . -imultiarch
riscv64-linux-gnu test.c -quiet -dumpbase test.c "-mno-small-data-limit=" 0
"-march=rv64imafdc" "-mabi=lp64d" -auxbase test -fstack-protector-strong
-Wformat -Wformat-security -o /tmp/ccIJvDDO.s
[...]

This inconsistency unnecessarily complicates life of tools that parse compiler
commands (e.g. for static analysis).

[Bug other/99903] 32-bit x86 frontends randomly crash while reporting timing on Windows

2021-04-06 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99903

--- Comment #3 from Alexey Izbyshev  ---
Crashes eventually occurred with both one- and two-processor affinity masks, so
pinning GCC to a single core doesn't help. But I've tracked the reason down.

When `get_time()` from `gcc/timevar.c` gets inlined into its callers (which
happens with -O2), it "returns" the result on a x87 FPU register. Then
`timevar_accumulate()` computes the difference between this 80-bit number and a
64-bit double stored in the timer structure. So when `clock()` returns 15 at
both start and end measurements, this code basically subtracts 15 * (1.0 /
1000) stored with 64-bit precision from itself computed with 80-bit precision,
and the difference is 8.673617379884035472e-19. When `clock()` returns 15 for
all measurements during a single cc1 run, the total time and each phase time
are equal to this same constant, and the sum of phase times is twice the total
time:

Timing error: total of phase timers exceeds total time.
user1.734723475976807094e-18 > 8.673617379884035472e-19

Maybe GCC should round such ridiculously small intervals to zero?

[Bug other/99903] 32-bit x86 frontends randomly crash while reporting timing on Windows

2021-04-04 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99903

--- Comment #2 from Alexey Izbyshev  ---
> Is there a way to bind GCC to a specific core and test again?

Yes, `repro.py` can be run via `start /affinity MASK`. I've started two
experiments, with one- and two-processor masks. They haven't crashed after
several minutes, but I'll wait longer and then report the result.

Anyway, it seems that crashing in `gcc_unreachable()` due to NULL
`context->printer` is still kind-of-a-bug, since it makes it difficult to
understand what went wrong in the first place.

[Bug other/99903] New: 32-bit x86 frontends randomly crash while reporting timing on Windows

2021-04-03 Thread izbyshev at ispras dot ru via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99903

Bug ID: 99903
   Summary: 32-bit x86 frontends randomly crash while reporting
timing on Windows
   Product: gcc
   Version: 10.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: other
  Assignee: unassigned at gcc dot gnu.org
  Reporter: izbyshev at ispras dot ru
  Target Milestone: ---
  Host: i686-w64-mingw32
Target: i686-w64-mingw32
 Build: i686-w64-mingw32

Created attachment 50503
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=50503&action=edit
A reproducer

Running cc1 from i686-w64-mingw32-gcc[1] with timing report enabled (e.g.
without `-quiet` or with `-ftime-report`) may randomly crash on Windows.

A reproducer script is attached (tested on two Windows 10 1909 x64 machines).
The time to reproduce varied from seconds to half an hour. Running multiple cc1
to increase load appears to help, but is not required; just running a single
cc1 in a loop is enough too. The crash manifests as silent exit with code
3221225477 (0xc005; EXCEPTION_ACCESS_VIOLATION). Debugging showed the
following.

The eventual crash is actually a nested one. It happens at [2] while reporting
an ICE because `context->printer` is NULL (which, by itself, looks like a
separate bug).

The initial crash is triggered by `gcc_unreachable()` in
`timer::validate_phases()`[3].

#0  0x0125be91 in pp_format(pretty_printer*, text_info*) ()
#1  0x0125146b in diagnostic_report_diagnostic(diagnostic_context*,
diagnostic_info*) ()
#2  0x01251bd7 in diagnostic_impl(rich_location*, diagnostic_metadata const*,
int, char const*, char**, diagnostic_t)
()
#3  0x012521b8 in internal_error(char const*, ...) ()
#4  0x01528a96 in fancy_abort(char const*, int, char const*) ()
#5  0x014f9e9c in timer::validate_phases(_iobuf*) const [clone .cold] ()
#6  0x009400d3 in timer::print(_iobuf*) ()
#7  0x00942422 in toplev::~toplev() ()
#8  0x01526003 in main ()

And `gcc_unreachable()` is reached because `phase_user > total->user *
tolerance` is true. GCC doesn't print anything when run from `repro.py` because
of output buffering, but I extracted one message from memory:

Timing error: total of phase timers exceeds total time.
user1.734723475976807094e-18 > 8.673617379884035472e-19

I couldn't reproduce this with 64-bit x86 GCC.

[1]
https://github.com/msys2/MINGW-packages/tree/5d82e17a56a3216a54dbb5924b92c96284ae5c97/mingw-w64-gcc
[2]
https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/diagnostic.c;h=ed52bc03d17afa2d7ac3419beb73e8f59b6f392b;hb=releases/gcc-10.2.0#l1077
[3]
https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/timevar.c;h=a3a882d32040db6503260ab51ee4bf338c4aa2b5;hb=releases/gcc-10.2.0#l628