Bug 52748 - [4.9 Regression][C++11] N3276 changes to decltype
Summary: [4.9 Regression][C++11] N3276 changes to decltype
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: 4.8.1
Assignee: Jason Merrill
URL:
Keywords: rejects-valid
: 56374 (view as bug list)
Depends on:
Blocks: 54366
  Show dependency treegraph
 
Reported: 2012-03-28 05:18 UTC by Nathan Ridge
Modified: 2013-04-16 21:24 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-08-10 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nathan Ridge 2012-03-28 05:18:57 UTC
The C++11 standard section 5.2.2 pararaph 11 states that:

"If a function call is a prvalue of object type [and] if the function call is [...] the operand of a decltype-specifier [...], a temporary object is not introduced for the prvalue. The type of the prvalue may be incomplete. [Note: as a result, storage is not allocated for the prvalue and it is not destroyed; thus, a class type is not instantiated as a result of being the type of a function call in this context." 

This addition was made late in the C++11 standardization process; its rationale is described in the paper N3276 [1]

It seems GCC does not currently support this. In fact, when run on the "trivial example" given in N3276, GCC gets into an infinite loop and, if left running, uses up all the memory in the system (!) (Should I file that as a separate issue?)

Here is the example (WARNING - may exhaust your system's virtual memory if you're not careful):

template<class T> struct S;
template<class X, class Y> struct pair {};
template<class T> S<T> wrap(T) { return 0; }
template<class T>
struct S
{
   S(int = 0) {}
   decltype(wrap(pair<T,T>())) foo() { return 0; } // ERROR
   S<pair<T,T> > bar() { return 0; } // OK
};
S<int> s;


[1] http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3276.pdf
Comment 1 Johan Lundberg 2012-08-09 08:08:46 UTC
confirmed... I agree with this. Among other things it's important for boost/C++11 interop.
Comment 2 Nathan Ridge 2012-11-07 04:31:24 UTC
Clang deemed this issue important enough to warrant a new entry ("Incomplete retrn types", under "Declared type of an expression") in their C++11 status page.
Comment 3 Nathan Ridge 2012-11-07 04:32:06 UTC
(In reply to comment #2)
> Clang deemed this issue important enough to warrant a new entry ("Incomplete
> retrn types", under "Declared type of an expression") in their C++11 status
> page.

Link: http://clang.llvm.org/cxx_status.html
Comment 4 Jonathan Wakely 2013-02-18 12:47:32 UTC
*** Bug 56374 has been marked as a duplicate of this bug. ***
Comment 5 Jason Merrill 2013-03-17 02:37:21 UTC
Author: jason
Date: Sun Mar 17 02:37:09 2013
New Revision: 196736

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=196736
Log:
	N3276
	PR c++/52748
	* cp-tree.h (tsubst_flags): Add tf_decltype.
	* call.c (build_cxx_call): Don't build a temporary if it's set.
	(build_over_call): Make sure it's only passed to build_cxx_call.
	* parser.c (cp_parser_primary_expression): Add decltype_p parm.
	(cp_parser_unary_expression): Likewise.
	(cp_parser_cast_expression): Likewise.
	(cp_parser_binary_expression): Likewise.
	(cp_parser_assignment_expression): Likewise.
	(cp_parser_postfix_expression): Likewise.  Pass tf_decltype.
	(cp_parser_explicit_instantiation): Add decltype_p.  Force a
	temporary for a call on the LHS of a comma.
	(cp_parser_decltype): Pass true to decltype_p parms.
	* pt.c (tsubst) [DECLTYPE_TYPE]: Pass tf_decltype.
	(tsubst_copy_and_build): Pass tf_decltype down only for
	CALL_EXPR and the RHS of COMPOUND_EXPR.
	* tree.c (build_cplus_new): Call complete_type_or_maybe_complain.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/decltype-call1.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/cp/cp-tree.h
    trunk/gcc/cp/parser.c
    trunk/gcc/cp/pt.c
    trunk/gcc/cp/tree.c
Comment 6 Paolo Carlini 2013-03-23 10:52:25 UTC
Fixed 4.8.1 too.
Comment 7 Jason Merrill 2013-03-26 14:31:48 UTC
Closing.
Comment 8 Michel Morin 2013-03-28 13:11:00 UTC
The implementation of N3276 is not complete. 

`decltype` in gcc-4.9-20130324 does not require type-completeness 
but involves unnecessary template instantiations: 

* Compilation of the demonstration code in N3276 (also appeared in 
Nathan Ridge's comment in this PR) exhausted memory on my PC, 
so I had to quit the compilation.

* Boost's testing code (https://svn.boost.org/svn/boost/trunk/libs/config/test/boost_no_decltype_n3276.ipp) failed to compile. 
(One needs to remove `namespace boost_no_cxx11_decltype_n3276 {` and its closing 
brace`}`, and rename `int test()` to `int main()` before the compilation.)
Comment 9 Paolo Carlini 2013-03-28 13:29:00 UTC
Jason is the right person to answer your first and third question, but the answer to the second one is simple: we have a regression in mainline, current 4_8-branch works fine.
Comment 10 Jason Merrill 2013-03-28 13:36:07 UTC
The implementation is complete.  Unfortunately, my fixes for DRs 337 and 657 are interfering with the desired result; creating a function type returning an abstract class causes deduction to fail, so we instantiate the return type of wrap in order to determine whether it is abstract.  I guess I'll disable that instantiation and raise this issue with Core...
Comment 11 Paolo Carlini 2013-03-28 13:46:02 UTC
Thanks Jason. Looks like to be safe we should also add Nathan's testcase as-is to the testsuite.
Comment 12 Jason Merrill 2013-03-28 20:02:57 UTC
Fixed again.  I added a different testcase whose failure mode is an error, rather than consuming all resources.
Comment 13 Michel Morin 2013-03-29 00:40:59 UTC
Thanks Jason, Paolo. 
I'll enable N3276 decltype support in Boost.Config for gcc 4.8.1 and 4.9.0.
Comment 14 Nathan Ridge 2013-04-10 09:27:10 UTC
Here is a related example that still fails to compile:


template <int> struct A;

template <typename T> struct B : A<sizeof(T)> {};

template <typename T>
B<typename T::type> operator-(T);

struct S
{
    struct F
    {
        typedef S type;
    };
    
    auto foo() -> decltype(-F());
};



This is compiled successfully by clang, but GCC (4.9, r197663) gives the following error:

test.cpp: In instantiation of 'struct B<S>':
test.cpp:15:31:   required from here
test.cpp:3:42: error: invalid application of 'sizeof' to incomplete type 'S'
 template <typename T> struct B : A<sizeof(T)> {};
                                          ^


If the operator- is replaced by a non-operator function, GCC compiles the example successfully, which leads me to believe it's a bug.
Comment 15 Jason Merrill 2013-04-11 21:46:33 UTC
(In reply to comment #14)
> Here is a related example that still fails to compile:

Fixed.
Comment 16 Nathan Ridge 2013-04-12 07:22:20 UTC
(In reply to comment #15)
> (In reply to comment #14)
> > Here is a related example that still fails to compile:
> 
> Fixed.

It still fails if we make S a template:


template <int> struct A;

template <typename T> struct B : A<sizeof(T)> {};

template <typename F>
B<typename F::type> operator-(F);

template <typename T>
struct S
{
    struct F
    {
        typedef S type;
    };
    
    auto foo() -> decltype(-F());
};

int main()
{   
    S<int> s;
}


test.cpp: In instantiation of 'struct B<S<int> >':
test.cpp:16:28:   required from 'struct S<int>'
test.cpp:21:12:   required from here
test.cpp:3:42: error: invalid application of 'sizeof' to incomplete type 'S<int>'
 template <typename T> struct B : A<sizeof(T)> {};
                                          ^

Tested with r197837.
Comment 17 Nathan Ridge 2013-04-12 07:23:07 UTC
(Sorry, meant to reopen with last comment.)
Comment 18 Jason Merrill 2013-04-16 21:24:12 UTC
Fixed.