From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5981 invoked by alias); 12 Feb 2014 03:54:49 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 5910 invoked by uid 89); 12 Feb 2014 03:54:49 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_LOW,RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Wed, 12 Feb 2014 03:54:47 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 89579542B3B; Wed, 12 Feb 2014 04:54:43 +0100 (CET) Date: Wed, 12 Feb 2014 03:54:00 -0000 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, jason@redhat.com Subject: Warn about virtual table mismatches Message-ID: <20140212035443.GE18400@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.5.21 (2010-09-15) X-SW-Source: 2014-02/txt/msg00741.txt.bz2 Hi, this patch implements warning when we merge two virtual tables that do not match. It compares the size and also go into fields. I had to implement my own comparsion code, since the vtables may subtly differ - in RTTI and also I need to do so during DECL merging (since we will forget about the decl then) Here is an example of real ODR violation in bugzilla it finds. ../../dist/include/mozilla/a11y/DocAccessible.h:40:0: warning: type �struct DocAccessible� violates one definition rule [enabled by default] class DocAccessible : public HyperTextAccessibleWrap, ^ /aux/hubicka/firefox/accessible/src/generic/DocAccessible.h:40:0: note: a type with the same name but different virtual table is defined in another translation unit class DocAccessible : public HyperTextAccessibleWrap, ^ /aux/hubicka/firefox/accessible/src/generic/DocAccessible.cpp:1232:0: note: the first different method is �HandleAccEvent� DocAccessible::HandleAccEvent(AccEvent* aEvent) ^ /aux/hubicka/firefox/accessible/src/atk/AccessibleWrap.cpp:956:0: note: a conflicting method is �HandleAccEvent� AccessibleWrap::HandleAccEvent(AccEvent* aEvent) ^ The patch is not terribly pretty, but does the job. I will wait for few days for comments/suggestins and then plan to commit it. PR lto/59468 * lto/lto-symtab.c (lto_symtab_prevailing_decl): Check virtual tables for ODR violations. * ipa-devirt.c (compare_virtual_tables): New function. * ipa-utils.h (compare_virtual_tables): Declare. Index: lto/lto-symtab.c =================================================================== --- lto/lto-symtab.c (revision 207702) +++ lto/lto-symtab.c (working copy) @@ -679,5 +679,13 @@ lto_symtab_prevailing_decl (tree decl) if (!ret) return decl; + /* Check and report ODR violations on virtual tables. */ + if (decl != ret->decl && DECL_VIRTUAL_P (decl)) + { + compare_virtual_tables (ret->decl, decl); + /* We are done with checking and DECL will die after merigng. */ + DECL_VIRTUAL_P (decl) = 0; + } + return ret->decl; } Index: ipa-devirt.c =================================================================== --- ipa-devirt.c (revision 207702) +++ ipa-devirt.c (working copy) @@ -1675,6 +1673,101 @@ update_type_inheritance_graph (void) } +/* Compare two virtual tables, PREVAILING and VTABLE and output ODR + violation warings. */ + +void +compare_virtual_tables (tree prevailing, tree vtable) +{ + tree init1 = DECL_INITIAL (prevailing), init2 = DECL_INITIAL (vtable); + if (init1 == init2) + return; + if (init2 == error_mark_node) + return; + /* Be sure to keep virtual table contents even for external + vtables when they are available. */ + if (init1 == error_mark_node || !init1) + { + DECL_INITIAL (prevailing) = DECL_INITIAL (vtable); + return; + } + if (!init2 && DECL_EXTERNAL (vtable)) + return; + if (DECL_VIRTUAL_P (prevailing) && init1 && init2 + && CONSTRUCTOR_NELTS (init1) == CONSTRUCTOR_NELTS (init2)) + { + unsigned i; + tree field1, field2; + tree val1, val2; + bool matched = true; + + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init1), + i, field1, val1) + { + gcc_assert (!field1); + field2 = CONSTRUCTOR_ELT (init2, i)->index; + val2 = CONSTRUCTOR_ELT (init2, i)->value; + gcc_assert (!field2); + if (val2 == val1) + continue; + STRIP_NOPS (val1); + STRIP_NOPS (val2); + /* Unwind + val + readonly constant + arg 0 + readonly + arg 0 + arg 0 > arg 1 >> */ + + while ((TREE_CODE (val1) == MEM_REF + && TREE_CODE (val2) == MEM_REF + && (TREE_OPERAND (val1, 1) + == TREE_OPERAND (val2, 1))) + || (TREE_CODE (val1) == ADDR_EXPR + && TREE_CODE (val2) == ADDR_EXPR)) + { + val1 = TREE_OPERAND (val1, 0); + val2 = TREE_OPERAND (val2, 0); + } + if (val1 == val2) + continue; + if (TREE_CODE (val2) == ADDR_EXPR) + { + tree tmp = val1; + val1 = val2; + val2 = tmp; + } + /* Allow combining RTTI and non-RTTI is OK. */ + if (TREE_CODE (val1) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (val1, 0)) == VAR_DECL + && !DECL_VIRTUAL_P (TREE_OPERAND (val1, 0)) + && TREE_CODE (val2) == NOP_EXPR + && integer_zerop (TREE_OPERAND (val2, 0))) + continue; + if (TREE_CODE (val1) == NOP_EXPR + && TREE_CODE (val2) == NOP_EXPR + && integer_zerop (TREE_OPERAND (val1, 0)) + && integer_zerop (TREE_OPERAND (val2, 0))) + continue; + if (DECL_P (val1) && DECL_P (val2) + && DECL_ASSEMBLER_NAME (val1) == DECL_ASSEMBLER_NAME (val2)) + continue; + matched = false; + break; + } + if (matched) + return; + } + odr_violation_reported = true; + if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (vtable))), 0, + "type %qD violates one definition rule ", + DECL_CONTEXT (vtable))) + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing))), + "a type with the same name but different virtual table is " + "defined in another translation unit"); +} + /* Return true if N looks like likely target of a polymorphic call. Rule out cxa_pure_virtual, noreturns, function declared cold and other obvious cases. */ Index: ipa-utils.h =================================================================== --- ipa-utils.h (revision 207702) +++ ipa-utils.h (working copy) @@ -92,6 +92,7 @@ bool get_polymorphic_call_info_from_inva tree, tree, HOST_WIDE_INT); tree vtable_pointer_value_to_binfo (tree t); bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *); +void compare_virtual_tables (tree, tree); /* Return vector containing possible targets of polymorphic call E. If FINALP is non-NULL, store true if the list is complette.