Bug 90397 - Incompatibility with clang-tidy on std::variant
Summary: Incompatibility with clang-tidy on std::variant
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 9.1.1
: P3 normal
Target Milestone: 9.2
Assignee: Jonathan Wakely
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-05-08 20:25 UTC by philip.salvaggio
Modified: 2019-06-11 21:57 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-05-08 00:00:00


Attachments
Minimal example (407 bytes, application/x-zip-compressed)
2019-05-08 20:25 UTC, philip.salvaggio
Details

Note You need to log in before you can comment on or make changes to this bug.
Description philip.salvaggio 2019-05-08 20:25:00 UTC
Created attachment 46315 [details]
Minimal example

Since upgrading to GCC 9.1.1, I am getting the following errors when running clang-tidy (8.0.0) on this minimal example. Not sure whether this is a bug in the libstdc++ headers or in clang, but it seems to be related to the noexcept specifier on __get(). The code compiles fine with g++.


#include <variant>

int main() {
  std::variant<int, double> v;
  v = 5;

  int i = std::get<int>(v);
  return 0;
}

In order to reproduce from the zipped folder:

mkdir build && cd build
cmake ..
make
clang-tidy ../example.cpp

give the following errors for me.


[build]$ clang-tidy ../example.cpp
6 errors generated.
Error while processing /home/fedora/example/build/../example.cpp.
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:266:10: error: cannot cast 'const std::variant<int, double>' to its private base class 'std::__detail::__variant::_Variant_storage<true, int, double>' [clang-diagnostic-error]
                              std::forward<_Variant>(__v)._M_u);
                              ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1610:35: note: in instantiation of function template specialization 'std::__detail::__variant::__get<0, const std::variant<int, double> &>' requested here
      return __detail::__variant::__get<_Np>(__v);
                                  ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1359:11: note: in instantiation of function template specialization 'std::get<0, int, double>' requested here
            std::get<__index>(*this) = std::forward<_Tp>(__rhs);
                 ^
/home/fedora/example/example.cpp:5:5: note: in instantiation of function template specialization 'std::variant<int, double>::operator=<int>' requested here
  v = 5;
    ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1220:7: note: constrained by private inheritance here
    : private __detail::__variant::_Variant_base<_Types...>,
      ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:266:10: error: cannot cast 'std::variant<int, double>' to its private base class 'std::__detail::__variant::_Variant_storage<true, int, double>' [clang-diagnostic-error]
                              std::forward<_Variant>(__v)._M_u);
                              ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1588:35: note: in instantiation of function template specialization 'std::__detail::__variant::__get<0, std::variant<int, double> &>' requested here
      return __detail::__variant::__get<_Np>(__v);
                                  ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1061:19: note: in instantiation of function template specialization 'std::get<0, int, double>' requested here
      return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
                  ^
/home/fedora/example/example.cpp:7:16: note: in instantiation of function template specialization 'std::get<int, int, double>' requested here
  int i = std::get<int>(v);
               ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1220:7: note: constrained by private inheritance here
    : private __detail::__variant::_Variant_base<_Types...>,
      ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:266:38: error: '_M_u' is a private member of 'std::__detail::__variant::_Variant_storage<true, int, double>' [clang-diagnostic-error]
                              std::forward<_Variant>(__v)._M_u);
                                                          ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1220:7: note: constrained by private inheritance here
    : private __detail::__variant::_Variant_base<_Types...>,
      ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:453:34: note: member is declared here
      _Variadic_union<_Types...> _M_u;
                                 ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1359:31: error: cannot assign to return value because function 'get<0, int, double>' returns a const value [clang-diagnostic-error]
            std::get<__index>(*this) = std::forward<_Tp>(__rhs);
                                     ^
/home/fedora/example/example.cpp:5:5: note: in instantiation of function template specialization 'std::variant<int, double>::operator=<int>' requested here
  v = 5;
    ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:134:15: note: function 'get<0, int, double>' which returns const-qualified type 'const variant_alternative_t<0UL, variant<int, double> > &' (aka 'const int &') declared here
    constexpr variant_alternative_t<_Np, variant<_Types...>> const&
              ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:1559:55: error: '__get' is missing exception specification 'noexcept' [clang-diagnostic-error]
        friend constexpr decltype(auto) __detail::__variant::__get(_Vp&& __v);
                                                             ^
/home/fedora/example/example.cpp:4:29: note: in instantiation of template class 'std::variant<int, double>' requested here
  std::variant<int, double> v;
                            ^
/usr/lib/gcc/x86_64-redhat-linux/9/../../../../include/c++/9/variant:263:5: note: previous declaration is here
    __get(_Variant&& __v) noexcept
    ^
Found compiler error(s).
Comment 1 philip.salvaggio 2019-05-08 20:40:46 UTC
I was able to rectify the issue by removing the noexcept in <variant> on line 263. I assume, that would imply that the noexcept's on the other overloads would also need to be removed.
Comment 2 Jonathan Wakely 2019-05-08 20:49:05 UTC
No, it should be added to the friend declaration. I missed the friend declaration when I added 'noexcept' elsewhere in r270501.
Comment 3 philip.salvaggio 2019-05-08 21:03:45 UTC
Yep! I added the noexcept on there on my local version and that also resolved the issue.
Comment 4 Jonathan Wakely 2019-05-10 21:41:51 UTC
Author: redi
Date: Fri May 10 21:41:19 2019
New Revision: 271079

URL: https://gcc.gnu.org/viewcvs?rev=271079&root=gcc&view=rev
Log:
PR libstdc++/90397 fix std::variant friend declarations

Clang diagnoses the inconsistent noexcept-specifier on the friend
declaration of __get. Add it, and also on __get_storage.

	PR libstdc++/90397
	* include/std/variant (_Variant_storage<false, Types...>::_M_storage())
	(_Variant_storage<true, Types...>::_M_reset()))
	(_Variant_storage<true, Types...>::_M_storage())): Add noexcept.
	(__get_storage): Likewise.
	(variant): Add noexcept to friend declarations for __get and
	__get_storage.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/std/variant
Comment 5 Jonathan Wakely 2019-05-10 22:23:42 UTC
Author: redi
Date: Fri May 10 22:23:10 2019
New Revision: 271083

URL: https://gcc.gnu.org/viewcvs?rev=271083&root=gcc&view=rev
Log:
PR libstdc++/90397 fix std::variant friend declaration

Clang diagnoses insert inconsistent noexcept-specifier on the friend
declaration of __get. Add .

	PR libstdc++/90397
	* include/std/variant (variant): Add noexcept to friend declaration.

Modified:
    branches/gcc-9-branch/libstdc++-v3/ChangeLog
    branches/gcc-9-branch/libstdc++-v3/include/std/variant
Comment 6 Jonathan Wakely 2019-05-10 22:24:57 UTC
fixed on trunk and gcc-9-branch
Comment 7 Evgeniy Dushistov 2019-06-11 17:51:13 UTC
But, what about bug in gcc by itself, because of it doesn't report compile error, is it reported as one more bug?
Comment 8 Jonathan Wakely 2019-06-11 21:57:02 UTC
G++ allowed it because the mismatch was in a system header. If you use -Wsystem-headers then GCC 9.1 gives a warning about it:

/xhome/jwakely/gcc/9.1.0/include/c++/9.1.0/variant: In instantiation of 'class std::variant<A, B>':
var.cc:14:44:   required from here
/xhome/jwakely/gcc/9.1.0/include/c++/9.1.0/variant:1559:34: warning: declaration of 'template<long unsigned int _Np, class _Vp> constexpr decltype(auto) std::__detail::__variant::__get(_Vp&&)' has a different exception specifier [-Wsystem-headers]
 1559 |  friend constexpr decltype(auto) __detail::__variant::__get(_Vp&& __v);
      |                                  ^~~~~~~~
/xhome/jwakely/gcc/9.1.0/include/c++/9.1.0/variant:263:5: note: from previous declaration 'template<long unsigned int _Np, class _Variant> constexpr decltype(auto) std::__detail::__variant::__get(_Variant&&) noexcept'
  263 |     __get(_Variant&& __v) noexcept
      |     ^~~~~


If you use -pedantic-errors then you get an error.