Bug 95789 - [10/11 Regression] Const method is allowed to return non-const reference on template class
Summary: [10/11 Regression] Const method is allowed to return non-const reference on t...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.1.0
: P3 normal
Target Milestone: 10.2
Assignee: Marek Polacek
URL:
Keywords: accepts-invalid
: 96096 96104 96179 (view as bug list)
Depends on:
Blocks:
 
Reported: 2020-06-20 18:23 UTC by Ivan Chebykin
Modified: 2020-07-14 23:26 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work: 9.3.0
Known to fail: 10.1.0, 11.0
Last reconfirmed: 2020-06-21 00:00:00


Attachments
Preprocessed file without iostream (200 bytes, text/plain)
2020-06-20 18:23 UTC, Ivan Chebykin
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ivan Chebykin 2020-06-20 18:23:41 UTC
Created attachment 48762 [details]
Preprocessed file without iostream

Hello, I've recently updated from gcc 9.3.0 to 10.1.0 and found some unexpected
behaviour when trying to compile this code:

#include <iostream>

struct B {
    int n;
};

template <typename T>
struct A {
    B& get() const { return f; }

    B f;
};

int main() {
    A<int> a;
    a.f = {};

    a.get().n = 10;
    std::cout << a.f.n << std::endl;
    return 0;
}

As I understand this code shouldn't compile with error
binding reference of type ‘B&’ to ‘const B’ discards qualifiers

but this code compiles successfully. What is more interesting is that this code will stop compiling if I remove template or if I use POD type like int.

Neither gcc 9.3.0 compiles this code nor clang does.

GCC info:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/10.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --with-isl --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-install-libiberty --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-libunwind-exceptions --disable-werror gdc_include_dir=/usr/include/dlang/gdc
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.1.0 (GCC)

Compiling with -Wall -Wextra yields no output warnings or errors.

I've attached preprocessed file without iostream.
Comment 1 Jonathan Wakely 2020-06-21 09:03:40 UTC
struct B {
    int n;
};

template <typename T>
struct A {
    B& get() const { return f; }

    B f;
};

int main() {
    A<int> a;
    a.f = {};

    a.get().n = 10;
    if (a.f.n != 0)
      __builtin_abort();
}

Started with r10-7094

    c++: Readd [LR]ROTATE_EXPR support to constexpr.c [PR94067]
    
    Since r10-6527-gaaa26bf496a646778ac861aed124d960b5bf549f fold_for_warn
    will perform maybe_constant_value even on some cp_fold produced trees and
    so can include rotate exprs which were removed last fall from constexpr.c
    
    2020-03-09  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/94067
            Revert
            2019-10-11  Paolo Carlini  <paolo.carlini@oracle.com>
    
            * constexpr.c (cxx_eval_constant_expression): Do not handle
            RROTATE_EXPR and LROTATE_EXPR.
    
            * g++.dg/warn/Wconversion-pr94067.C: New test.
Comment 2 Marek Polacek 2020-06-22 19:31:54 UTC
This actually started with r10-7096-gd417b4f5414d9076300ab41974a14424f722688c so mine.
Comment 3 Marek Polacek 2020-07-07 16:10:41 UTC
*** Bug 96096 has been marked as a duplicate of this bug. ***
Comment 4 Marek Polacek 2020-07-07 23:11:11 UTC
*** Bug 96104 has been marked as a duplicate of this bug. ***
Comment 5 Marek Polacek 2020-07-07 23:11:44 UTC
Another test:

// PR c++/96104

template <typename T> void fn(T &);
class E {};
struct F {
  template <typename T> void mfn(T t) { t, fn(E()); } // { dg-error "cannot bind non-const lvalue reference" }
};
int
main()
{
  E e;
  F f;
  f.mfn(e);
}
Comment 6 Marek Polacek 2020-07-13 17:35:34 UTC
*** Bug 96179 has been marked as a duplicate of this bug. ***
Comment 7 Marek Polacek 2020-07-13 17:36:07 UTC
// PR c++/96179

template<typename T> struct vector
{
  void push_back(T) { }
};

struct dummy{
        int a;
};

void Modify_Dummy(dummy &d){
        d.a=1;
}

template <bool bla=true> void Templated_Function(){
        vector<dummy> A;
        A.push_back(Modify_Dummy(dummy{0}));
}

int main(){
        Templated_Function();
}
Comment 8 GCC Commits 2020-07-14 20:03:42 UTC
The master branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:8e64d182850560dbedfabb88aac90d4fc6155067

commit r11-2097-g8e64d182850560dbedfabb88aac90d4fc6155067
Author: Marek Polacek <polacek@redhat.com>
Date:   Mon Jun 22 21:26:49 2020 -0400

    c++: Make convert_like complain about bad ck_ref_bind again [PR95789]
    
    convert_like issues errors about bad_p conversions at the beginning
    of the function, but in the ck_ref_bind case, it only issues them
    after we've called convert_like on the next conversion.
    
    This doesn't work as expected since r10-7096 because when we see
    a conversion from/to class type in a template, we return early, thereby
    missing the error, and a bad_p conversion goes by undetected.  That
    made the attached test to compile even though it should not.
    
    I had thought that I could just move the ck_ref_bind/bad_p errors
    above to the rest of them, but that regressed diagnostics because
    expr then wasn't converted yet by the nested convert_like_real call.
    
    So, for bad_p conversions, do the normal processing, but still return
    the IMPLICIT_CONV_EXPR to avoid introducing trees that the template
    processing can't handle well.  This I achieved by adding a wrapper
    function.
    
    gcc/cp/ChangeLog:
    
            PR c++/95789
            PR c++/96104
            PR c++/96179
            * call.c (convert_like_real_1): Renamed from convert_like_real.
            (convert_like_real): New wrapper for convert_like_real_1.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/95789
            PR c++/96104
            PR c++/96179
            * g++.dg/conversion/ref4.C: New test.
            * g++.dg/conversion/ref5.C: New test.
            * g++.dg/conversion/ref6.C: New test.
Comment 9 GCC Commits 2020-07-14 23:24:53 UTC
The releases/gcc-10 branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:315b87f63bcde4c881e9963c39d57258da08ccb5

commit r10-8497-g315b87f63bcde4c881e9963c39d57258da08ccb5
Author: Marek Polacek <polacek@redhat.com>
Date:   Mon Jun 22 21:26:49 2020 -0400

    c++: Make convert_like complain about bad ck_ref_bind again [PR95789]
    
    convert_like issues errors about bad_p conversions at the beginning
    of the function, but in the ck_ref_bind case, it only issues them
    after we've called convert_like on the next conversion.
    
    This doesn't work as expected since r10-7096 because when we see
    a conversion from/to class type in a template, we return early, thereby
    missing the error, and a bad_p conversion goes by undetected.  That
    made the attached test to compile even though it should not.
    
    I had thought that I could just move the ck_ref_bind/bad_p errors
    above to the rest of them, but that regressed diagnostics because
    expr then wasn't converted yet by the nested convert_like_real call.
    
    So, for bad_p conversions, do the normal processing, but still return
    the IMPLICIT_CONV_EXPR to avoid introducing trees that the template
    processing can't handle well.  This I achieved by adding a wrapper
    function.
    
    gcc/cp/ChangeLog:
    
            PR c++/95789
            PR c++/96104
            PR c++/96179
            * call.c (convert_like_real_1): Renamed from convert_like_real.
            (convert_like_real): New wrapper for convert_like_real_1.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/95789
            PR c++/96104
            PR c++/96179
            * g++.dg/conversion/ref4.C: New test.
            * g++.dg/conversion/ref5.C: New test.
            * g++.dg/conversion/ref6.C: New test.
    
    (cherry picked from commit 8e64d182850560dbedfabb88aac90d4fc6155067)
Comment 10 Marek Polacek 2020-07-14 23:26:03 UTC
Fixed for 11/10.2.