Patchwork C++ PATCH for c++/54277 (wrong cv-quals in lambda)

login
register
mail settings
Submitter Jason Merrill
Date March 17, 2013, 2:40 a.m.
Message ID <51452D06.2080709@redhat.com>
Download mbox | patch
Permalink /patch/228269/
State New
Headers show

Comments

Jason Merrill - March 17, 2013, 2:40 a.m.
On 03/16/2013 03:28 PM, Jason Merrill wrote:
> I have no idea why the existing code tried to deduce the desired quals
> from current_class_ref rather than just look at the object it has.

Well, maybe now I do; when I tested all my changes again before checking 
in, this one caused a crash because I had left out another change that 
it depends on.  Previously we gave the 'this' capture in a lambda a 
DECLTYPE_TYPE type since the enclosing class is a dependent type, but 
that means that *this has no type at all and so we can't look at its 
quals.  But that isn't necessary; we know enough about the type of 
'this' that it's a pointer to some instantiation of this class template, 
so we can give the capture field and proxy that type rather than mess 
with DECLTYPE_TYPE.  We could limit this change to only POINTER_TYPE, 
but we might as well save a bit of memory and only use the DECLTYPE_TYPE 
when we really don't know anything about the type being captured; 
specifically, when we don't know whether or not it's a reference.

Tested x86_64-pc-linux-gnu, applying to trunk.
Ryan Mansfield - March 19, 2013, 6:28 p.m.
On 13-03-16 10:40 PM, Jason Merrill wrote:
> On 03/16/2013 03:28 PM, Jason Merrill wrote:
>> I have no idea why the existing code tried to deduce the desired quals
>> from current_class_ref rather than just look at the object it has.
>
> Well, maybe now I do; when I tested all my changes again before checking
> in, this one caused a crash because I had left out another change that
> it depends on.  Previously we gave the 'this' capture in a lambda a
> DECLTYPE_TYPE type since the enclosing class is a dependent type, but
> that means that *this has no type at all and so we can't look at its
> quals.  But that isn't necessary; we know enough about the type of
> 'this' that it's a pointer to some instantiation of this class template,
> so we can give the capture field and proxy that type rather than mess
> with DECLTYPE_TYPE.  We could limit this change to only POINTER_TYPE,
> but we might as well save a bit of memory and only use the DECLTYPE_TYPE
> when we really don't know anything about the type being captured;
> specifically, when we don't know whether or not it's a reference.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.

Hi Jason,

It seems this change introduced the following segfault building 
compatibility-thread-c++0x.cc for an arm eabi target.

ice.ii:48:20: internal compiler error: Segmentation fault
         (__args) ...);
                     ^
0xa7b67f crash_signal
	../../gcc/toplev.c:332
0x4e98e2 resolve_args
	../../gcc/cp/call.c:3739
0x5022d7 build_new_function_call(tree_node*, vec<tree_node*, va_gc, 
vl_embed>**, bool, int)
	../../gcc/cp/call.c:3849
0x66dc42 finish_call_expr(tree_node*, vec<tree_node*, va_gc, 
vl_embed>**, bool, bool, int)
	../../gcc/cp/semantics.c:2214

Attached is a reduced testcase. Sorry, for reporting it on gcc-patches 
but bugzilla is currently offline.

Regards,

Ryan Mansfield
namespace std __attribute__ ((__visibility__ ("default")))
{
  template < typename _Tp > struct remove_reference
  {
    typedef _Tp type;
  };
  template < typename _Tp > constexpr _Tp
    && forward (typename std::remove_reference < _Tp >::type & __t) noexcept
  {
    return static_cast < _Tp && >(__t);
  }
  template < typename _Res, typename _T1,
    typename _T2 >
    struct _Reference_wrapper_base <_Res (_T1::*) (_T2) const volatile
    >:binary_function < const volatile _T1 *, _T2, _Res >
  {
  };
template < typename _Tp > class reference_wrapper:public _Reference_wrapper_base < typename remove_cv <
    _Tp >::type >
  {
  };
  template < typename _Tp > inline reference_wrapper < _Tp >
    ref (_Tp & __t) noexcept
  {
  }
  template < typename _Signature > struct _Bind_simple;
  template < typename _Func, typename ... _BoundArgs > struct _Bind_simple_helper
  {
    typedef _Bind_simple < __func_type (typename decay <
					_BoundArgs >::type ...) > __type;
  };
  template < typename _Callable,
    typename ... _Args > typename _Bind_simple_helper < _Callable,
    _Args ... >::__type __bind_simple (_Callable && __callable, _Args
				       && ... __args)
  {
  }
  template < typename _Signature > class function;
  struct once_flag
  {
  };
  template < typename _Callable,
    typename ... _Args > void call_once (once_flag & __once, _Callable
					 && __f, _Args && ... __args)
  {
    auto __callable = std::__bind_simple (std::forward < _Callable > (__f),
					  std::forward < _Args >
					  (__args) ...);
    __once_functor =[&]()
    {
      __callable ();
    };
  }
  class _State_base
  {
    once_flag _M_once;
    void _M_set_result (function < _Ptr_type () > __res,
			bool __ignore_failure = false)
    {
      bool __set = __ignore_failure;
        call_once (_M_once, &_State_base::_M_do_set, this, ref (__res),
		   ref (__set));
    }
  private:void _M_do_set (function < _Ptr_type () > &__f, bool & __set)
    {

    }
  }
}

Patch

commit 4be028d462b52838a0afd6cf3f25fff33ac925ad
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 15 14:14:12 2013 -0500

    	PR c++/54277
    	* cp-tree.h (WILDCARD_TYPE_P): Split out from...
    	(MAYBE_CLASS_TYPE_P): ...here.
    	* semantics.c (lambda_capture_field_type): Only build a
    	magic decltype for wildcard types.
    	(lambda_proxy_type): Likewise.
    	(finish_non_static_data_member): Get the quals from
    	the object.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 39fb3df..7ce1acb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1220,17 +1220,20 @@  enum languages { lang_c, lang_cplusplus, lang_java };
 /* The _DECL for this _TYPE.  */
 #define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
 
-/* Nonzero if T is a class (or struct or union) type.  Also nonzero
-   for template type parameters, typename types, and instantiated
-   template template parameters.  Keep these checks in ascending code
-   order.  */
-#define MAYBE_CLASS_TYPE_P(T)					\
+/* Nonzero if T is a type that could resolve to any kind of concrete type
+   at instantiation time.  */
+#define WILDCARD_TYPE_P(T)				\
   (TREE_CODE (T) == TEMPLATE_TYPE_PARM			\
    || TREE_CODE (T) == TYPENAME_TYPE			\
    || TREE_CODE (T) == TYPEOF_TYPE			\
    || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM	\
-   || TREE_CODE (T) == DECLTYPE_TYPE			\
-   || CLASS_TYPE_P (T))
+   || TREE_CODE (T) == DECLTYPE_TYPE)
+
+/* Nonzero if T is a class (or struct or union) type.  Also nonzero
+   for template type parameters, typename types, and instantiated
+   template template parameters.  Keep these checks in ascending code
+   order.  */
+#define MAYBE_CLASS_TYPE_P(T) (WILDCARD_TYPE_P (T) || CLASS_TYPE_P (T))
 
 /* Set CLASS_TYPE_P for T to VAL.  T must be a class, struct, or
    union type.  */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 9a2b728..5143e4b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1574,9 +1574,7 @@  finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
       else
 	{
 	  /* Set the cv qualifiers.  */
-	  int quals = (current_class_ref
-		       ? cp_type_quals (TREE_TYPE (current_class_ref))
-		       : TYPE_UNQUALIFIED);
+	  int quals = cp_type_quals (TREE_TYPE (object));
 
 	  if (DECL_MUTABLE_P (decl))
 	    quals &= ~TYPE_QUAL_CONST;
@@ -9056,7 +9054,7 @@  tree
 lambda_capture_field_type (tree expr)
 {
   tree type;
-  if (type_dependent_expression_p (expr))
+  if (!TREE_TYPE (expr) || WILDCARD_TYPE_P (TREE_TYPE (expr)))
     {
       type = cxx_make_type (DECLTYPE_TYPE);
       DECLTYPE_TYPE_EXPR (type) = expr;
@@ -9265,7 +9263,7 @@  lambda_proxy_type (tree ref)
   if (REFERENCE_REF_P (ref))
     ref = TREE_OPERAND (ref, 0);
   type = TREE_TYPE (ref);
-  if (!dependent_type_p (type))
+  if (type && !WILDCARD_TYPE_P (type))
     return type;
   type = cxx_make_type (DECLTYPE_TYPE);
   DECLTYPE_TYPE_EXPR (type) = ref;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this9.C
new file mode 100644
index 0000000..07ddd08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this9.C
@@ -0,0 +1,19 @@ 
+// PR c++/54277
+// { dg-do compile { target c++11 } }
+
+struct Used
+{
+  void foo() { }
+};
+
+template <typename>
+struct S
+{
+  Used x;
+
+  void bar()
+  {
+    auto f = [this] { x.foo(); };
+    f();
+  }
+};