http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51199

             Bug #: 51199
           Summary: [C++11][DR 547] gcc forms impossible types derived
                    from function types with cv-qualifier-seq
    Classification: Unclassified
           Product: gcc
           Version: 4.7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: daniel.krueg...@googlemail.com
                CC: ja...@gcc.gnu.org


gcc 4.7 20111112 (experimental) in C++11 mode accepts the following code:

//------
typedef void FC() const;

template<class T>
struct add_ref {
  typedef T& type;
};

typedef add_ref<FC>::type ref_type; // #1

template<class T>
struct add_ptr {
  typedef T* type;
};

typedef add_ptr<FC>::type ptr_type; // #2
//------

According to DR 547 the function type FC is valid as argument for the templates
add_ref and add_ptr and shall keep its cv-qualifier-seq, but the type
declarations ref_type (#1) and ptr_type (#2) are accepted, even though they
describe types that are impossible to form in C++ because they contradict what
the bulleted list in N3290 8.3.5 p6 allows. 

Further-on 8.3.5 p10 say:

"A typedef of a function type whose declarator includes a cv-qualifier-seq
shall be used only to declare the function type for a non-static member
function, to declare the function type to which a pointer to member refers, or
to declare the top-level function type of another function typedef
declaration."

Nonetheless static deduction can be used to demonstrate that ref_type behaves
essentially like the type void (&FC)() const and that ptr_type behaves like the
type void (*FC)() const. E.g. the following tests succeed given the type
definitions FC, ref_type, and ptr_type from above:

//--
#include <type_traits>

static_assert(std::is_reference<ref_type>::value, "Ouch");
static_assert(std::is_same<std::remove_reference<ref_type>::type, FC>::value,
"Ouch");
static_assert(std::is_pointer<ptr_type>::value, "Ouch");
static_assert(std::is_same<std::remove_pointer<ptr_type>::type, FC>::value,
"Ouch");
//--

The formation of the types ref_type and ptr_type should be rejected.

Additionally, under sfinae conditions, these invalid types are also not
properly recognized. The following code is rejected by gcc, but shouldn't:

//----
typedef void FC() const;

template<class T, class = T&>
auto fr(int) -> char;

template<class>
auto fr(...) -> char (&)[2];

static_assert(sizeof(fr<FC>(0)) == 2, "Error");

template<class T, class = T*>
auto fp(int) -> char;

template<class>
auto fp(...) -> char (&)[2];

static_assert(sizeof(fp<FC>(0)) == 2, "Error");
//----

Both static assertions fail, but shouldn't.

If there are doubts about the interpretation of the standard, I would suggest
to keep this open, because I have posted a corresponding clarification notice
to the CWG reflector and this may end in an issue.

Reply via email to