Bug 102804 - [11 Regression] template matching fails w/ false ambiguity on ternary expressions with enums class defined with unsigned typedef
Summary: [11 Regression] template matching fails w/ false ambiguity on ternary express...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.2.0
: P2 normal
Target Milestone: 11.5
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: 108099
  Show dependency treegraph
 
Reported: 2021-10-17 22:09 UTC by Todd Rudick
Modified: 2023-07-07 10:41 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 7.4.0
Known to fail: 8.1.0
Last reconfirmed: 2021-10-18 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Todd Rudick 2021-10-17 22:09:29 UTC
E.g. w/ -std=c++11

#include <iostream>
int main() {
  enum: unsigned int32_t { FOO, BAR } foobar = FOO;
  std::cout << ((time(nullptr) % 2) ? foobar : 13) << std::endl;
}

The initial error is:

error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘unsigned int’)

in gcc9.2 & gcc 11.2.0

gcc7 happily compiles the code.

with -Wextra, all 3 versions warn:

error: enumerated and non-enumerated type in conditional expression

Version: 11.2.0

system: CentOS Linux 7.7.1908 on Intel Xeon

command: g++ -Wall -Wextra -std=c++11 20211017-bug.cpp
Comment 1 Andrew Pinski 2021-10-17 22:18:11 UTC
Hmm:
<source>:4:9: error: 'unsigned' specified with 'int32_t' {aka 'int'} [-Wpedantic]
    4 |   enum: unsigned int32_t { FOO, BAR } foobar = FOO;
      |         ^~~~~~~~


Looks like this is the cause of the problem, Changing it to unsigned or uint32_t and the error goes away ...
Comment 2 Jonathan Wakely 2021-10-18 00:04:04 UTC
unsigned int32_t is invalid. You cannot use unsigned (or short or long) with a typedef, only with 'int'.

GCC was changed to diagnose that fairly recently, which is probably why the behaviour changed since GCC 7.
Comment 3 Jonathan Wakely 2021-10-18 00:16:18 UTC
I think it was pr 84701
Comment 4 Richard Biener 2021-10-18 06:51:08 UTC
Thus invalid.
Comment 5 Todd Rudick 2021-10-18 16:23:42 UTC
Richard, is there a way to represent the part of this that is a bug?  Presumably accepting the construct but having it break template specialization with an error that can be arbitrarily disconnected from the definition is not a desired behavior. In the production code that I eventually isolated this from, there is in fact no reference at all to the header that contained the enum.

Also, it seems likely that the compiler state is bad at that point (?), as the error message indicates an 'unsigned int' ambiguity that doesn't actually exist.
Comment 6 Jonathan Wakely 2021-10-18 16:37:28 UTC
This is a bug, we should either reject 'unsigned int32_t' immediately (which we only do with -pedantic-errors) or we should accept it and treat it consistently as unsigned int.

Reduced:

enum: unsigned int32_t { FOO, BAR } foobar = FOO;
int f(int);
int f(unsigned);
auto x = f(1 ? foobar : 13);


With r254043 we just have a pedwarn:

102804.C:2:16: warning: long, short, signed or unsigned used invalidly for 'type name' [-Wpedantic]
 enum: unsigned int32_t { FOO, BAR } foobar = FOO;
                ^~~~~~~

With r254046 we get the error:

102804.C:2:16: warning: long, short, signed or unsigned used invalidly for 'type name' [-Wpedantic]
 enum: unsigned int32_t { FOO, BAR } foobar = FOO;
                ^~~~~~~
102804.C:5:27: error: call of overloaded 'f(unsigned int)' is ambiguous
 auto x = f(1 ? foobar : 13);
                           ^
102804.C:3:5: note: candidate: 'int f(int)'
 int f(int);
     ^
102804.C:4:5: note: candidate: 'int f(unsigned int)'
 int f(unsigned);
     ^


    re PR c++/82307 (unscoped enum-base incorrect cast)
    
    /cp
    2017-10-24  Mukesh Kapoor  <mukesh.kapoor@oracle.com>
                Paolo Carlini  <paolo.carlini@oracle.com>
    
            PR c++/82307
            * cvt.c (type_promotes_to): Implement C++17, 7.6/4, about unscoped
            enumeration type whose underlying type is fixed.


So it was actually caused by fixing the promotion rules for enums (PR 82307), not by the handling of 'unsigned' applied to a typedef.
Comment 7 Jonathan Wakely 2021-10-18 16:43:42 UTC
Oops, sorry the reduced example was missing the first line.

Fixed, and further reduced:

using int32_t = int;
enum: unsigned int32_t { foo };
int f(int);
int f(unsigned);
auto x = f(1 ? foo : 1);
Comment 8 GCC Commits 2022-04-15 01:55:37 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:e580f81d22d61153564959f08d9a6d3bcc7fd386

commit r12-8173-ge580f81d22d61153564959f08d9a6d3bcc7fd386
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Apr 14 17:49:47 2022 -0400

    c++: unsigned int32_t enum promotion [PR102804]
    
    There's been an extension for a long time to allow applying 'unsigned' to an
    int typedef, but that was confusing the integer promotion code.  Fixed by
    forgetting about the typedef in that case.
    
    I'm going to make this an unconditional pedwarn in stage 1.
    
            PR c++/102804
    
    gcc/cp/ChangeLog:
    
            * decl.cc (grokdeclarator): Drop typedef used with 'unsigned'.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/unsigned-typedef1.C: New test.
Comment 9 Richard Biener 2022-05-27 09:46:26 UTC
GCC 9 branch is being closed
Comment 10 Jakub Jelinek 2022-06-28 10:46:41 UTC
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
Comment 11 Richard Biener 2023-07-07 10:41:15 UTC
GCC 10 branch is being closed.