https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127297
Bug ID: 127297
Summary: [c++26][contracts] the postcondition const-parameter
diagnostic is emitted twice for a non-template
function
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: berne at notadragon dot com
Target Milestone: ---
Created attachment 65543
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65543&action=edit
One line; the const-parameter diagnostic is emitted twice for it
For a non-template function, the [dcl.contract.func] const-parameter
diagnostic is emitted twice: byte-identical message, byte-identical
location, and an identical note each time.
```
int f(int v) post(r : v == r) { return v; }
```
```
$ ./gcc-16.2.0/bin/g++ -std=c++26 -fsyntax-only \
postcondition-const-nontemplate.C
postcondition-const-nontemplate.C:7:23: error: a value parameter used in a
postcondition must be const
7 | int f(int v) post(r : v == r) { return v; }
| ^
postcondition-const-nontemplate.C:7:11: note: parameter declared here
7 | int f(int v) post(r : v == r) { return v; }
| ~~~~^
postcondition-const-nontemplate.C:7:23: error: a value parameter used in a
postcondition must be const
7 | int f(int v) post(r : v == r) { return v; }
| ^
postcondition-const-nontemplate.C:7:11: note: parameter declared here
7 | int f(int v) post(r : v == r) { return v; }
| ~~~~^
```
The diagnosis itself is correct -- the program is ill-formed and should be
rejected. Only the duplication is the defect.
Worth distinguishing from a case that is not a defect: for a function
template, two different diagnostics are emitted, one naming the parameter
and one pointing at the contract. Those come from two mechanisms that
deliberately anchor at different places, and with more than one parameter or
more than one postcondition they say genuinely different things. It is only
the non-template path above, where the same mechanism fires twice with the
same words at the same column, that is wrong.
DISCOVERY
Found while fixing a neighbouring defect in the same rule, by reading the
diagnostics the fix produced rather than only whether the program was
rejected -- the duplication is invisible to a test that just checks for an
error.
ANALYSIS
Both emissions come from the same place with the same location, so this is
the odr-use walk reaching the parameter twice rather than the two distinct
mechanisms firing. A postcondition's predicate is examined once through the
declaration and once more when the definition is processed, and for a
non-template both examinations reach the same tree.
VERSIONS -- all on x86_64-linux-gnu
source version emitted twice
compiler-explorer 16.1.0 yes
compiler-explorer 16.2.0 yes
compiler-explorer 17.0.0 20260909, 919c0d16c91 yes
local build -g 17.0.0 20260909, 7dab38c9d71 yes
```
$ ./gcc-16.2.0/bin/g++ -v
Using built-in specs.
COLLECT_GCC=./gcc-16.2.0/bin/g++
COLLECT_LTO_WRAPPER=/home/jberne4/repos/compilers/gcc-16.2.0/bin/../libexec/gcc/x86_64-linux-gnu/16.2.0/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../gcc-16.2.0/configure
--prefix=/opt/compiler-explorer/gcc-build/staging --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap
--enable-multiarch --with-abi=m64 --with-multilib-list=m32,m64,mx32
--enable-multilib --enable-clocale=gnu
--enable-languages=c,c++,fortran,ada,objc,obj-c++,go,d,m2,rust,cobol,algol68
--enable-ld=yes --enable-gold=yes --enable-libstdcxx-time=yes
--enable-linker-build-id --enable-lto --enable-plugins --enable-threads=posix
--with-pkgversion=Compiler-Explorer-Build-gcc--binutils-2.44
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 16.2.0 (Compiler-Explorer-Build-gcc--binutils-2.44)
```