From patchwork Tue Mar 14 16:08:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 738789 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vjKRT3qS1z9ryk for ; Wed, 15 Mar 2017 03:08:53 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="c/9zIVpO"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=NYMh0D83X3QbbAGl5157RblPsgKRY4jzewXVu92YT2miItOd6d0Dt pOyo1PBhZeZoISNUMsZ1tNidFGtBRJZ4B5PS7majS64aX1h8b3diGRgVMf5WasZR URI+7GFzP+QA8iR84gjqudE9y9XtBRgMe5LamAJM65+5dINp6+ZYYM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=rJ8pwgyOA/yhDkEygrRUdDRuB0k=; b=c/9zIVpOJHs+ROqiCUk8 g4bbcZTjmgmmHU8ro44ujwKZ6e/ti+EuOlhJCBWSs88YSVftuaS19hC9eIx3/J7e 0IDu4z0Dzb8aXPs0UQIoTXrPFREcKmkKPU7aBFxxDjIN7m7zSNs08dzL2+ZN7VPz pw9NZH9g6IEt3d1T1BTlP5k= Received: (qmail 64581 invoked by alias); 14 Mar 2017 16:08:36 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 64446 invoked by uid 89); 14 Mar 2017 16:08:34 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=cap, anticipate, Needs, fns X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 14 Mar 2017 16:08:27 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 80831C054C4C for ; Tue, 14 Mar 2017 16:08:27 +0000 (UTC) Received: from redhat.com (ovpn-204-27.brq.redhat.com [10.40.204.27]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v2EG8OJC008686 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 14 Mar 2017 12:08:26 -0400 Date: Tue, 14 Mar 2017 17:08:22 +0100 From: Marek Polacek To: GCC Patches Subject: C++ backports to 6 Message-ID: <20170314160822.GS3172@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.7.1 (2016-10-04) I've backported the attached patches gcc-6. Marek Bootstrapped/regtested on x86_64-linux, ok for trunk? 2017-03-14 Marek Polacek PR c++/79962 PR c++/79984 * c-common.c (handle_nonnull_attribute): Save the result of default conversion to the attribute list. * c-c++-common/nonnull-3.c: New test. * g++.dg/warn/Wnonnull3.C: New test. We crash on an assert in strip_typedefs, because we find ourselves in a scenario where RESULT, the main variant of a struct, was modified in finalize_record_size (its TYPE_ALIGN changed), but its variants (T in strip_typedefs) weren't fixed-up yet; that will happen slightly later in finalize_type_size. So there's a discrepancy that confuses the code. This patch implements what Jason suggested to me on IRC, i.e., skip the attribute handling if RESULT is complete and T isn't. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2017-03-09 Marek Polacek PR c++/79900 - ICE in strip_typedefs * tree.c (strip_typedefs): Skip the attribute handling if T is a variant type which hasn't been updated yet. * g++.dg/warn/Wpadded-1.C: New test. diff --git gcc/cp/tree.c gcc/cp/tree.c index d3c63b8..b3a4a10 100644 --- gcc/cp/tree.c +++ gcc/cp/tree.c @@ -1548,29 +1548,40 @@ strip_typedefs (tree t, bool *remove_attributes) result = TYPE_MAIN_VARIANT (t); } gcc_assert (!typedef_variant_p (result)); - if (TYPE_USER_ALIGN (t) != TYPE_USER_ALIGN (result) - || TYPE_ALIGN (t) != TYPE_ALIGN (result)) + + if (COMPLETE_TYPE_P (result) && !COMPLETE_TYPE_P (t)) + /* If RESULT is complete and T isn't, it's likely the case that T + is a variant of RESULT which hasn't been updated yet. Skip the + attribute handling. */; + else { - gcc_assert (TYPE_USER_ALIGN (t)); - if (remove_attributes) - *remove_attributes = true; - else + if (TYPE_USER_ALIGN (t) != TYPE_USER_ALIGN (result) + || TYPE_ALIGN (t) != TYPE_ALIGN (result)) { - if (TYPE_ALIGN (t) == TYPE_ALIGN (result)) - result = build_variant_type_copy (result); + gcc_assert (TYPE_USER_ALIGN (t)); + if (remove_attributes) + *remove_attributes = true; else - result = build_aligned_type (result, TYPE_ALIGN (t)); - TYPE_USER_ALIGN (result) = true; + { + if (TYPE_ALIGN (t) == TYPE_ALIGN (result)) + result = build_variant_type_copy (result); + else + result = build_aligned_type (result, TYPE_ALIGN (t)); + TYPE_USER_ALIGN (result) = true; + } + } + + if (TYPE_ATTRIBUTES (t)) + { + if (remove_attributes) + result = apply_identity_attributes (result, TYPE_ATTRIBUTES (t), + remove_attributes); + else + result = cp_build_type_attribute_variant (result, + TYPE_ATTRIBUTES (t)); } } - if (TYPE_ATTRIBUTES (t)) - { - if (remove_attributes) - result = apply_identity_attributes (result, TYPE_ATTRIBUTES (t), - remove_attributes); - else - result = cp_build_type_attribute_variant (result, TYPE_ATTRIBUTES (t)); - } + return cp_build_qualified_type (result, cp_type_quals (t)); } diff --git gcc/testsuite/g++.dg/warn/Wpadded-1.C gcc/testsuite/g++.dg/warn/Wpadded-1.C index e69de29..b3f0581 100644 --- gcc/testsuite/g++.dg/warn/Wpadded-1.C +++ gcc/testsuite/g++.dg/warn/Wpadded-1.C @@ -0,0 +1,22 @@ +// PR c++/79900 - ICE in strip_typedefs +// { dg-do compile } +// { dg-options "-Wpadded" } + +template struct A; +template struct B { // { dg-warning "padding struct size to alignment boundary" } + long _M_off; + int _M_state; +}; +template <> struct A { typedef B pos_type; }; +enum _Ios_Openmode {}; +struct C { + typedef _Ios_Openmode openmode; +}; +template struct D { + typedef typename _Traits::pos_type pos_type; + pos_type m_fn1(pos_type, C::openmode); +}; +template class D >; +template +typename D<_CharT, _Traits>::pos_type D<_CharT, _Traits>::m_fn1(pos_type x, + C::openmode) { return x; } Bootstrapped/regtested on x86_64-linux, ok for trunk? 2017-03-09 Marek Polacek PR c++/79687 * init.c (constant_value_1): Break if the variable has a dynamic initializer. * g++.dg/expr/ptrmem8.C: New test. * g++.dg/expr/ptrmem9.C: New test. diff --git gcc/cp/init.c gcc/cp/init.c index 7ded37e..12e6bf4 100644 --- gcc/cp/init.c +++ gcc/cp/init.c @@ -2193,6 +2193,13 @@ constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p) if (TREE_CODE (init) == CONSTRUCTOR && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)) break; + /* If the variable has a dynamic initializer, don't use its + DECL_INITIAL which doesn't reflect the real value. */ + if (VAR_P (decl) + && TREE_STATIC (decl) + && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) + && DECL_NONTRIVIALLY_INITIALIZED_P (decl)) + break; decl = unshare_expr (init); } return decl; diff --git gcc/testsuite/g++.dg/expr/ptrmem8.C gcc/testsuite/g++.dg/expr/ptrmem8.C index e69de29..c5a766a 100644 --- gcc/testsuite/g++.dg/expr/ptrmem8.C +++ gcc/testsuite/g++.dg/expr/ptrmem8.C @@ -0,0 +1,15 @@ +// PR c++/79687 +// { dg-do run } + +struct A +{ + char c; +}; + +int main() +{ + char A::* p = &A::c; + static char A::* const q = p; + A a; + return &(a.*q) - &a.c; +} diff --git gcc/testsuite/g++.dg/expr/ptrmem9.C gcc/testsuite/g++.dg/expr/ptrmem9.C index e69de29..32ce777 100644 --- gcc/testsuite/g++.dg/expr/ptrmem9.C +++ gcc/testsuite/g++.dg/expr/ptrmem9.C @@ -0,0 +1,19 @@ +// PR c++/79687 +// { dg-do run } + +struct A +{ + char c; +}; + +int main() +{ + static char A::* p1 = &A::c; + char A::* const q1 = p1; + + char A::* p2 = &A::c; + static char A::* const q2 = p2; + + A a; + return (&(a.*q1) - &a.c) || (&(a.*q2) - &a.c); +} 2017-01-17 Nathan Sidwell PR c++/61636 * cp-tree.h (maybe_generic_this_capture): Declare. * lambda.c (resolvable_dummy_lambda): New, broken out of ... (maybe_resolve_dummy): ... here. Call it. (maybe_generic_this_capture): New. * parser.c (cp_parser_postfix_expression): Speculatively capture this in generic lambda in unresolved member function call. * pt.c (tsubst_copy_and_build): Force hard error from failed member function lookup in generic lambda. * g++.dg/cpp1y/pr61636-1.C: New. * g++.dg/cpp1y/pr61636-2.C: New. * g++.dg/cpp1y/pr61636-3.C: New. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 24de346..0c8f147 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6551,6 +6551,7 @@ extern bool is_capture_proxy (tree); extern bool is_normal_capture_proxy (tree); extern void register_capture_members (tree); extern tree lambda_expr_this_capture (tree, bool); +extern void maybe_generic_this_capture (tree, tree); extern tree maybe_resolve_dummy (tree, bool); extern tree current_nonlambda_function (void); extern tree nonlambda_method_basetype (void); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 98fdb74..4d22c3d 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -793,16 +793,14 @@ lambda_expr_this_capture (tree lambda, bool add_capture_p) return result; } -/* We don't want to capture 'this' until we know we need it, i.e. after - overload resolution has chosen a non-static member function. At that - point we call this function to turn a dummy object into a use of the - 'this' capture. */ +/* Return the current LAMBDA_EXPR, if this is a resolvable dummy + object. NULL otherwise.. */ -tree -maybe_resolve_dummy (tree object, bool add_capture_p) +static tree +resolvable_dummy_lambda (tree object) { if (!is_dummy_object (object)) - return object; + return NULL_TREE; tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object)); gcc_assert (!TYPE_PTR_P (type)); @@ -812,18 +810,55 @@ maybe_resolve_dummy (tree object, bool add_capture_p) && LAMBDA_TYPE_P (current_class_type) && lambda_function (current_class_type) && DERIVED_FROM_P (type, current_nonlambda_class_type ())) - { - /* In a lambda, need to go through 'this' capture. */ - tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type); - tree cap = lambda_expr_this_capture (lam, add_capture_p); - if (cap && cap != error_mark_node) + return CLASSTYPE_LAMBDA_EXPR (current_class_type); + + return NULL_TREE; +} + +/* We don't want to capture 'this' until we know we need it, i.e. after + overload resolution has chosen a non-static member function. At that + point we call this function to turn a dummy object into a use of the + 'this' capture. */ + +tree +maybe_resolve_dummy (tree object, bool add_capture_p) +{ + if (tree lam = resolvable_dummy_lambda (object)) + if (tree cap = lambda_expr_this_capture (lam, add_capture_p)) + if (cap != error_mark_node) object = build_x_indirect_ref (EXPR_LOCATION (object), cap, RO_NULL, tf_warning_or_error); - } return object; } +/* When parsing a generic lambda containing an argument-dependent + member function call we defer overload resolution to instantiation + time. But we have to know now whether to capture this or not. + Do that if FNS contains any non-static fns. + The std doesn't anticipate this case, but I expect this to be the + outcome of discussion. */ + +void +maybe_generic_this_capture (tree object, tree fns) +{ + if (tree lam = resolvable_dummy_lambda (object)) + if (!LAMBDA_EXPR_THIS_CAPTURE (lam)) + { + /* We've not yet captured, so look at the function set of + interest. */ + if (BASELINK_P (fns)) + fns = BASELINK_FUNCTIONS (fns); + for (; fns; fns = OVL_NEXT (fns)) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (OVL_CURRENT (fns))) + { + /* Found a non-static member. Capture this. */ + lambda_expr_this_capture (lam, true); + break; + } + } +} + /* Returns the innermost non-lambda function. */ tree diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 295c450..6d3b877 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6971,6 +6971,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, || type_dependent_expression_p (fn) || any_type_dependent_arguments_p (args))) { + maybe_generic_this_capture (instance, fn); postfix_expression = build_nt_call_vec (postfix_expression, args); release_tree_vector (args); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dec7d39..022ffda 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17142,19 +17142,34 @@ tsubst_copy_and_build (tree t, if (unq != function) { - tree fn = unq; - if (INDIRECT_REF_P (fn)) - fn = TREE_OPERAND (fn, 0); - if (TREE_CODE (fn) == COMPONENT_REF) - fn = TREE_OPERAND (fn, 1); - if (is_overloaded_fn (fn)) - fn = get_first_fn (fn); - if (permerror (EXPR_LOC_OR_LOC (t, input_location), - "%qD was not declared in this scope, " - "and no declarations were found by " - "argument-dependent lookup at the point " - "of instantiation", function)) + /* In a lambda fn, we have to be careful to not + introduce new this captures. Legacy code can't + be using lambdas anyway, so it's ok to be + stricter. */ + bool in_lambda = (current_class_type + && LAMBDA_TYPE_P (current_class_type)); + char const *msg = "%qD was not declared in this scope, " + "and no declarations were found by " + "argument-dependent lookup at the point " + "of instantiation"; + + bool diag = true; + if (in_lambda) + error_at (EXPR_LOC_OR_LOC (t, input_location), + msg, function); + else + diag = permerror (EXPR_LOC_OR_LOC (t, input_location), + msg, function); + if (diag) { + tree fn = unq; + if (INDIRECT_REF_P (fn)) + fn = TREE_OPERAND (fn, 0); + if (TREE_CODE (fn) == COMPONENT_REF) + fn = TREE_OPERAND (fn, 1); + if (is_overloaded_fn (fn)) + fn = get_first_fn (fn); + if (!DECL_P (fn)) /* Can't say anything more. */; else if (DECL_CLASS_SCOPE_P (fn)) @@ -17177,7 +17192,13 @@ tsubst_copy_and_build (tree t, inform (DECL_SOURCE_LOCATION (fn), "%qD declared here, later in the " "translation unit", fn); + if (in_lambda) + { + release_tree_vector (call_args); + RETURN (error_mark_node); + } } + function = unq; } } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C new file mode 100644 index 0000000..9426d5f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C @@ -0,0 +1,31 @@ +// PR c++/61636 +// { dg-do compile { target c++14 } } + +// ICE because we figure this capture too late. + +struct Base +{ + void Bar (int); +}; + +struct A : Base { + void b (); + void Foo (int); + using Base::Bar; + template void Baz (T); +}; + +void A::b() { + + auto lam = [&](auto asdf) { Foo (asdf); }; + + lam (0); + + auto lam1 = [&](auto asdf) { Bar (asdf); }; + + lam1 (0); + + auto lam2 = [&](auto asdf) { Baz (asdf); }; + + lam2 (0); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-2.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-2.C new file mode 100644 index 0000000..a1bd597 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-2.C @@ -0,0 +1,72 @@ +// PR c++/61636 +// { dg-do run { target c++14 } } + +// Check we don't capture this (too) unnecessarily + +struct A { + int b (); + void f (int) {} + static void f (double) {} + + static void g (int) {} + static void g (double) {} +}; + +struct O { + void x (int) {} + static void x (double) {} +}; + +namespace N { + void y (double) {} +} + +int Check (bool expect, unsigned size) +{ + return (expect ? sizeof (void *) : 1) != size; +} + +int A::b() { + int r = 0; + + // one of the functions is non-static + auto l0 = [&](auto z) { f (z); }; + r += Check (true, sizeof l0); + l0(0.0); // doesn't need this capture for A::f(double), but too late + l0 (0); // Needs this capture for A::f(int) + + // no fn is non-static. + auto l00 = [&](auto z) { g (z); }; + r += Check (false, sizeof l00); + l00(0.0); + l00 (0); + + // sizeof isn't an evaluation context, so no this capture + auto l1 = [&](auto z) { sizeof (f (z), 1); }; + r += Check (false, sizeof l1); + l1(0.0); l1 (0); + + auto l2 = [&](auto) { f (2.4); }; + auto l3 = [&](auto) { f (0); }; + l2(0); l3(0); l2(0.0); l3 (0.0); + r += Check (false, sizeof l2); + r += Check (true, sizeof l3); + + auto l4 = [&](auto) { O::x (2.4); }; + auto l5 = [&](auto) { N::y (2.4); }; + auto l6 = [&](auto) { }; + l4(0); l5(0); l6(0); + l4(0.0); l5(0.0); l6(0.0); + r += Check (false, sizeof l4); + r += Check (false, sizeof l5); + r += Check (false, sizeof l6); + + return r; +} + +int main () +{ + A a; + + return a.b () ? 1 : 0; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-3.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-3.C new file mode 100644 index 0000000..18f83fe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-3.C @@ -0,0 +1,25 @@ +// PR c++/61636 +// { dg-do compile { target c++14 } } +// permissiveness doesn't make this permitted +// { dg-additional-options "-fpermissive" } + +// ICE because we attempt to use dependent Foo during error recovery +// and die with an unexpected this capture need. + +template struct Base +{ + void Foo (int); +}; + +template struct A : Base { + void b (); +}; + +template void A::b() { + + auto lam = [&](auto asdf) { Foo (asdf); }; // { dg-error "not declared" } + + lam (T(0)); +} + +template void A::b (); 2017-01-31 Nathan Sidwell PR c++/79264 * lambda.c (maybe_generic_this_capture): Deal with template-id-exprs. * semantics.c (finish_member_declaration): Assert class is being defined. * g++.dg/cpp1y/pr61636-1.C: Augment. diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 538c806..46ab30f 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -849,13 +849,21 @@ maybe_generic_this_capture (tree object, tree fns) interest. */ if (BASELINK_P (fns)) fns = BASELINK_FUNCTIONS (fns); + bool id_expr = TREE_CODE (fns) == TEMPLATE_ID_EXPR; + if (id_expr) + fns = TREE_OPERAND (fns, 0); for (; fns; fns = OVL_NEXT (fns)) - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (OVL_CURRENT (fns))) - { - /* Found a non-static member. Capture this. */ - lambda_expr_this_capture (lam, true); - break; - } + { + tree fn = OVL_CURRENT (fns); + + if ((!id_expr || TREE_CODE (fn) == TEMPLATE_DECL) + && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + { + /* Found a non-static member. Capture this. */ + lambda_expr_this_capture (lam, true); + break; + } + } } } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index bd91e18..e4f2a6a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2962,6 +2962,12 @@ finish_member_declaration (tree decl) /* We should see only one DECL at a time. */ gcc_assert (DECL_CHAIN (decl) == NULL_TREE); + /* Don't add decls after definition. */ + gcc_assert (TYPE_BEING_DEFINED (current_class_type) + /* We can add lambda types when late parsing default + arguments. */ + || LAMBDA_TYPE_P (TREE_TYPE (decl))); + /* Set up access control for DECL. */ TREE_PRIVATE (decl) = (current_access_specifier == access_private_node); diff --git a/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C b/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C index 9426d5f..5cc8ca1 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr61636-1.C @@ -1,4 +1,5 @@ // PR c++/61636 +// PR c++/79264 // { dg-do compile { target c++14 } } // ICE because we figure this capture too late. @@ -28,4 +29,8 @@ void A::b() { auto lam2 = [&](auto asdf) { Baz (asdf); }; lam2 (0); + + auto lam3 = [&](auto asdf) { Baz (asdf); }; + + lam3 (0); } diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c index d2e3ad4..5f17984 100644 --- gcc/c-family/c-common.c +++ gcc/c-family/c-common.c @@ -9061,7 +9061,7 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), tree arg = TREE_VALUE (args); if (arg && TREE_CODE (arg) != IDENTIFIER_NODE && TREE_CODE (arg) != FUNCTION_DECL) - arg = default_conversion (arg); + TREE_VALUE (args) = arg = default_conversion (arg); if (!get_nonnull_operand (arg, &arg_num)) { diff --git gcc/testsuite/c-c++-common/nonnull-3.c gcc/testsuite/c-c++-common/nonnull-3.c index e69de29..d2ccb24 100644 --- gcc/testsuite/c-c++-common/nonnull-3.c +++ gcc/testsuite/c-c++-common/nonnull-3.c @@ -0,0 +1,11 @@ +/* PR c++/79984 */ +/* { dg-do compile } */ +/* { dg-options "-Wnonnull-compare" } */ + +enum { r = 1 }; + +__attribute__ ((nonnull (r))) int +f (int *p) +{ + return p == 0; /* { dg-warning "nonnull argument 'p' compared to NULL" } */ +} diff --git gcc/testsuite/g++.dg/warn/Wnonnull3.C gcc/testsuite/g++.dg/warn/Wnonnull3.C index e69de29..d1918ef 100644 --- gcc/testsuite/g++.dg/warn/Wnonnull3.C +++ gcc/testsuite/g++.dg/warn/Wnonnull3.C @@ -0,0 +1,15 @@ +// PR c++/79962 +// { dg-options "-Wnonnull" } + +template +__attribute__ ((__nonnull__ (T::i))) void f (typename T::U) { } + +struct S1 { enum { i = 1 }; typedef void* U; }; +struct S2 { static const int i = 1; typedef void* U; }; + +void +g () +{ + f(0); // { dg-warning "null argument where non-null required" } + f(0); // { dg-warning "null argument where non-null required" } +}