Bug 77563 - [5 Regression] explicit constructor breaks narrowing conversion overload resolution
Summary: [5 Regression] explicit constructor breaks narrowing conversion overload reso...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.2.0
: P2 normal
Target Milestone: 6.4
Assignee: Jason Merrill
URL:
Keywords: accepts-invalid
: 78032 (view as bug list)
Depends on:
Blocks:
 
Reported: 2016-09-12 09:39 UTC by Jacek Sieka
Modified: 2021-08-09 20:04 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.5.4, 7.0
Known to fail: 5.4.0, 6.2.0
Last reconfirmed: 2016-09-13 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jacek Sieka 2016-09-12 09:39:35 UTC
In the following snippet, an error should be emitted - instead, the compiler prints a warning and keeps compiling, and simply skips the second call to f (!) in the resulting executable:

#include <stdint.h>
#include <stdio.h>

struct A {
  A(int32_t a) {}
  A(uint32_t a) {}  // Comment to make it work

  explicit A(int64_t a) {}  // Comment to make it work
};

void f(A a) { printf("hello\n"); }

int main(int, char**) {
  f(2);
  f(3l);
}

/opt/gcc62/bin/g++ -std=gnu++11 explicit.cpp
explicit.cpp: In function ‘int main(int, char**)’:
explicit.cpp:11:6: note:   initializing argument 1 of ‘void f(A)’
 void f(A a) { printf("hello\n"); }
      ^

With either marked constructor commented, compiles correctly and gives the expected output ("hello" x 2 or ambiguity error).
Comment 1 Jacek Sieka 2016-09-12 09:44:34 UTC
gcc 5.3.0 gives a different error - looks odd though, no initializer list in sight:

/opt/gcc53/bin/g++ -std=gnu++11 explicit.cpp
explicit.cpp: In function ‘int main(int, char**)’:
explicit.cpp:15:7: error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(int64_t)’
   f(3l);
       ^
explicit.cpp:11:6: note:   initializing argument 1 of ‘void f(A)’
 void f(A a) { printf("hello\n"); }
      ^
clang++ 3.8 complains about ambiguity:

clang++ -std=gnu++11 explicit.cpp
explicit.cpp:15:5: error: conversion from 'long' to 'A' is ambiguous
  f(3l);
    ^~
explicit.cpp:5:3: note: candidate constructor
  A(int32_t a) {}
  ^
explicit.cpp:6:3: note: candidate constructor
  A(uint32_t a) {}
  ^
explicit.cpp:11:10: note: passing argument to parameter 'a' here
void f(A a) { printf("hello\n"); }
Comment 2 Jonathan Wakely 2016-09-13 08:42:36 UTC
4.5.4 got this right:

ex.cc: In function ‘int main()’:
ex.cc:15:7: error: conversion from ‘long int’ to ‘A’ is ambiguous
ex.cc:6:3: note: candidates are: A::A(uint32_t)
ex.cc:5:3: note:                 A::A(int32_t)

Since GCC 4.6 the error has been misleading, and since GCC 6 it's accepts-invalid.
Comment 3 Jonathan Wakely 2016-09-13 08:45:58 UTC
Reduced:

struct A {
  A(int) {}
  A(unsigned) {}  // Comment to make it work

  explicit A(long) {}  // Comment to make it work
};

void f(A) { }

int main() {
  f(2);
  f(3l);
}
Comment 4 Jakub Jelinek 2016-09-13 09:35:17 UTC
The 4.5 -> 4.6 difference appeared in r159332:

./cc1plus.159325 -quiet -std=c++0x pr77563.C
pr77563.C: In function ‘int main()’:
pr77563.C:12:7: error: conversion from ‘long int’ to ‘A’ is ambiguous
pr77563.C:3:3: note: candidates are: A::A(unsigned int)
pr77563.C:2:3: note:                 A::A(int)
./cc1plus.159332 -quiet -std=c++0x pr77563.C
pr77563.C: In function ‘int main()’:
pr77563.C:12:7: error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(long int)’

then r229283 started to ICE on it instead, and finally r236395 fixed the ICE, but emitted a note without corresponding error/warning:

./cc1plus.236395 -quiet -std=c++0x pr77563.C
pr77563.C: In function ‘int main()’:
pr77563.C:8:6: note:   initializing argument 1 of ‘void f(A)’
 void f(A) { }
      ^
Comment 5 Jeffrey A. Law 2017-02-05 16:06:58 UTC
*** Bug 78032 has been marked as a duplicate of this bug. ***
Comment 6 Jason Merrill 2017-03-23 12:51:27 UTC
Author: jason
Date: Thu Mar 23 12:50:55 2017
New Revision: 246417

URL: https://gcc.gnu.org/viewcvs?rev=246417&root=gcc&view=rev
Log:
	PR c++/77563 - missing ambiguous conversion error.

	* call.c (convert_like_real): Use LOOKUP_IMPLICIT.

Added:
    trunk/gcc/testsuite/g++.dg/overload/ambig3.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
Comment 7 Jason Merrill 2017-03-23 12:52:28 UTC
Fixed on trunk.
Comment 8 Jason Merrill 2017-04-12 19:24:23 UTC
Author: jason
Date: Wed Apr 12 19:23:30 2017
New Revision: 246893

URL: https://gcc.gnu.org/viewcvs?rev=246893&root=gcc&view=rev
Log:
	PR c++/77563 - missing ambiguous conversion error.

	* call.c (convert_like_real): Use LOOKUP_IMPLICIT.

Added:
    branches/gcc-6-branch/gcc/testsuite/g++.dg/overload/ambig3.C
Modified:
    branches/gcc-6-branch/gcc/cp/ChangeLog
    branches/gcc-6-branch/gcc/cp/call.c
Comment 9 Jason Merrill 2017-04-12 19:26:29 UTC
Fixed for 6.4.  Since the GCC 5 bug is just a strange diagnostic, I'm not going to fix it there.