Hi David,
On 15 January 2018 at 11:09, Richard Biener <richard.guent...@gmail.com> wrote: > On Mon, Jan 8, 2018 at 8:36 PM, David Malcolm <dmalc...@redhat.com> wrote: >> On Sat, 2018-01-06 at 08:44 +0100, Richard Biener wrote: >>> On January 5, 2018 11:55:11 PM GMT+01:00, David Malcolm <dmalcolm@red >>> hat.com> wrote: >>> > On Fri, 2018-01-05 at 10:36 +0100, Richard Biener wrote: >>> > > On Thu, Jan 4, 2018 at 10:52 PM, David Malcolm <dmalcolm@redhat.c >>> > > om> >>> > > wrote: >>> > > > PR lto/83121 reports an ICE deep inside the linemap code when >>> > > > -Wodr >>> > > > reports on a type mismatch. >>> > > > >>> > > > The root cause is that the warning can access the >>> > > > DECL_SOURCE_LOCATION >>> > > > of a streamed-in decl before the lto_location_cache has been >>> > > > applied. >>> > > > >>> > > > lto_location_cache::input_location stores >>> > > > RESERVED_LOCATION_COUNT >>> > > > (==2) >>> > > > as a poison value until the cache is applied: >>> > > > 250 /* Keep value RESERVED_LOCATION_COUNT in *loc as >>> > > > linemap >>> > > > lookups will >>> > > > 251 ICE on it. */ >>> > > > >>> > > > The fix is relatively simple: apply the cache before reading >>> > > > the >>> > > > DECL_SOURCE_LOCATION. >>> > > > >>> > > > (I wonder if we should instead have a INVALID_LOCATION value to >>> > > > handle >>> > > > this case more explicitly? e.g. 0xffffffff? or reserve 2 in >>> > > > libcpp for >>> > > > that purpose, and have the non-reserved locations start at >>> > > > 3? Either >>> > > > would be more invasive, though) >>> > > > >>> > > > Triggering the ICE was fiddly: it seems to be affected by many >>> > > > things, >>> > > > including the order of files, and (I think) by filenames. My >>> > > > theory is >>> > > > that it's affected by the ordering of the tree nodes in the LTO >>> > > > stream: >>> > > > for the ICE to occur, the types in question need to be compared >>> > > > before >>> > > > some other operation flushes the lto_location_cache. This >>> > > > ordering >>> > > > is affected by the hash-based ordering in DFS in lto-streamer- >>> > > > out.c, which >>> > > > might explain why r255066 seemed to trigger the bug; the only >>> > > > relevant >>> > > > change to LTO there seemed to be: >>> > > > * lto-streamer-out.c (hash_tree): Hash TYPE_EMPTY_P and >>> > > > DECL_PADDING_P. >>> > > > If so, then the bug was presumably already present, but hidden. >>> > > > >>> > > > The patch also adds regression test coverage for the ICE, which >>> > > > is >>> > > > more >>> > > > involved - as far as I can tell, we don't have an existing way >>> > > > to >>> > > > verify >>> > > > diagnostics emitted during link-time optimization. >>> > > > >>> > > > Hence the patch adds some machinery to lib/lto.exp to support >>> > > > two >>> > > > new >>> > > > directives: dg-lto-warning and dg-lto-message, corresponding to >>> > > > dg-warning and dg-message respectively, where the diagnostics >>> > > > are >>> > > > expected to be emitted at link-time. >>> > > > >>> > > > The test case includes examples of LTO warnings and notes in >>> > > > both >>> > > > the >>> > > > primary and secondary source files >>> > > > >>> > > > Doing so required reusing the logic from DejaGnu for handling >>> > > > diagnostics. >>> > > > Unfortunately the pertinent code is a 50 line loop within a >>> > > > ~200 >>> > > > line Tcl >>> > > > function in dg.exp (dg-test), so I had to copy it from DejaGnu, >>> > > > making >>> > > > various changes as necessary (see >>> > > > lto_handle_diagnostics_for_file >>> > > > in the >>> > > > patch; for example the LTO version supports multiple source >>> > > > files, >>> > > > identifying which source file emitted a diagnostic). >>> > > > >>> > > > For non-LTO diagnostics we currently ignore surplus "note" >>> > > > diagnostics. >>> > > > This patch updates lto_prune_warns to follow this behavior >>> > > > (since >>> > > > otherwise we'd need numerous dg-lto-message directives for the >>> > > > motivating >>> > > > test case). >>> > > > >>> > > > The patch adds these PASS results to g++.sum: >>> > > > >>> > > > PASS: g++.dg/lto/pr83121 cp_lto_pr83121_0.o assemble, -O0 -flto >>> > > > PASS: g++.dg/lto/pr83121 cp_lto_pr83121_1.o assemble, -O0 -flto >>> > > > PASS: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_0.C >>> > > > line >>> > > > 6) >>> > > > PASS: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_0.C >>> > > > line >>> > > > 8) >>> > > > PASS: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_1.C >>> > > > line >>> > > > 2) >>> > > > PASS: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_1.C >>> > > > line >>> > > > 3) >>> > > > PASS: g++.dg/lto/pr83121 cp_lto_pr83121_0.o-cp_lto_pr83121_1.o >>> > > > link, -O0 -flto >>> > > > >>> > > > The output for dg-lto-message above refers to "warnings", >>> > > > rather >>> > > > than >>> > > > "messages" but that's the same as for the non-LTO case, where >>> > > > dg- >>> > > > message >>> > > > also refers to "warnings". >>> > > > >>> > > > Successfully bootstrapped®rtested on x86_64-pc-linux-gnu. >>> > > > >>> > > > OK for trunk? >>> > > >>> > > Hmm, but we do this in warn_odr already? How's that not enough? >>> > > >>> > > At least it seems the place you add this isn't ideal (not at the >>> > > "root cause"). >>> > > >>> > > Richard. >>> > >>> > [CCing Honza] >>> > >>> > Yes, warn_odr does apply the cache, but this warning is coming from >>> > warn_types_mismatch. >>> > >>> > Of the various calls to warn_types_mismatch, most are immediately >>> > after >>> > a warn_odr guarded by if (warn && warned) or if (warned), and if >>> > warn_odr writes back true to *warned, it has definitely applied the >>> > cache. >>> > >>> > However, the 7-argument overload of odr_types_equivalent_p can >>> > also call warn_types_mismatch, passing in the location_t values it >>> > received. >>> > >>> > The problem occurs with this call stack, when: >>> > >>> > add_type_duplicate, passes DECL_SOURCE_LOCATIONs to: >>> > odr_types_equivalent_p (7-argument overload) - which calls: >>> > warn_types_mismatch, which calls: >>> > warning_at with the given location_t >>> > >>> > where the DECL_SOURCE_LOCATION might not yet have been fixed up >>> > yet. >>> > My patch adds the fixup there. >>> > >>> > This behavior seems to have been introduced by r224248 (aka >>> > 379ca7f842e5b13109b689b3c732741cab3d178e), Honza's fix for "PR >>> > lto/65378" (though that seems to have been a typo, as that bug is >>> > unrelated to the changes in that commit); the relevant ML post was: >>> > https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00523.html >>> > >>> > >>> > Would you prefer this if I reworked the two-liner into something >>> > like >>> > an "lto_location_cache::ensure_cache_applied" function? >>> >>> No, but put it in warn_types_mismatch? >> >> Hmm... putting it in warn_types_mismatch dosn't fix it, for the same >> reason as in the earlier description (or maybe I'm misunderstanding >> you?). >> >> As I understand it, the lto_location_cache effectively contains a vec >> of location_t * and expanded locations, and writes back to the >> location_t * once those "expanded" locations can be turned back into >> valid location_t values. >> >> The issue is that add_type_duplicate takes the DECL_SOURCE_LOCATION of >> a decl before the cache is applied, and that location_t gets passed >> around as a parameter. At that point, even if the cache is applied and >> the DECL_SOURCE_LOCATION is fixed, the local location_t values being >> passed around aren't going to be touched (they're not in the lto >> location cache - they're on the stack or in registers). >> >> FWIW, the backtrace at the point of failure looks like as follows; the >> invalid loc=2 values can be seen there. Note how the invalid >> location_t value of 2 is read in frame 17, and is passed around as a >> param in frames 16 down to 10, leading to the crash: >> >> (gdb) bt >> #0 fancy_abort (file=0x2135f00 "../../src/libcpp/line-map.c", line=990, >> function=0x2136390 <linemap_ordinary_map_lookup(line_maps*, unsigned >> int)::__FUNCTION__> "linemap_ordinary_map_lookup") at >> ../../src/gcc/diagnostic.c:1500 >> #1 0x0000000001c262c7 in linemap_ordinary_map_lookup (line=2, >> set=<optimized out>) >> at ../../src/libcpp/line-map.c:990 >> #2 linemap_lookup (set=set@entry=0x7ffff7ffb000, line=<optimized out>, >> line@entry=2) >> at ../../src/libcpp/line-map.c:943 >> #3 0x0000000001c27294 in linemap_macro_loc_to_def_point >> (original_map=0x7fffffffd2e0, location=2, >> set=0x7ffff7ffb000) at ../../src/libcpp/line-map.c:1448 >> #4 linemap_resolve_location (set=0x7ffff7ffb000, loc=<optimized out>, >> lrk=<optimized out>, map=0x7fffffffd2e0) >> at ../../src/libcpp/line-map.c:1580 >> #5 0x0000000001bdc4f2 in diagnostic_report_current_module >> (context=0x288bce0 <global_diagnostic_context>, where=2) >> at ../../src/gcc/diagnostic.c:581 >> #6 0x0000000000f36ae0 in diagnostic_report_current_function >> (context=0x288bce0 <global_diagnostic_context>, >> diagnostic=0x7fffffffd3f0) at ../../src/gcc/tree-diagnostic.c:39 >> #7 0x0000000000f36b44 in default_tree_diagnostic_starter (context=0x288bce0 >> <global_diagnostic_context>, >> diagnostic=0x7fffffffd3f0) at ../../src/gcc/tree-diagnostic.c:48 >> #8 0x0000000001bdd3b4 in diagnostic_report_diagnostic (context=0x288bce0 >> <global_diagnostic_context>, >> diagnostic=0x7fffffffd3f0) at ../../src/gcc/diagnostic.c:985 >> #9 0x0000000001bdd90e in diagnostic_impl (richloc=0x7fffffffd450, opt=-1, >> gmsgid=0x1cdcd40 "array types have different bounds", ap=0x7fffffffd4d8, >> kind=DK_NOTE) >> at ../../src/gcc/diagnostic.c:1108 >> #10 0x0000000001bddbfa in inform (location=2, gmsgid=0x1cdcd40 "array types >> have different bounds") >> at ../../src/gcc/diagnostic.c:1160 >> #11 0x0000000000bb2dd0 in warn_types_mismatch (t1=<array_type >> 0x7ffff1aa6dc8>, t2=<array_type 0x7ffff1aa69d8>, >> loc1=2, loc2=4448) at ../../src/gcc/ipa-devirt.c:1176 >> #12 0x0000000000bb5245 in odr_types_equivalent_p (t1=<record_type >> 0x7ffff1aa6e70 AsyncHooks>, >> t2=<record_type 0x7ffff1aa6b28 AsyncHooks>, warn=true, >> warned=0x7fffffffd7e3, visited=0x7fffffffd7b0, loc1=2, >> loc2=4448) at ../../src/gcc/ipa-devirt.c:1569 >> #13 0x0000000000bb6ebb in add_type_duplicate (val=0x7ffff18ab570, >> type=<record_type 0x7ffff1aa6b28 AsyncHooks>) >> at ../../src/gcc/ipa-devirt.c:1848 >> #14 0x0000000000bb77f2 in get_odr_type (type=<record_type 0x7ffff1aa6b28 >> AsyncHooks>, insert=true) >> at ../../src/gcc/ipa-devirt.c:2028 >> #15 0x0000000000bb0ae0 in odr_subtypes_equivalent_p (t1=<record_type >> 0x7ffff1aa6b28 AsyncHooks>, >> t2=<record_type 0x7ffff1aa6e70 AsyncHooks>, visited=0x7fffffffda10, >> loc1=288, loc2=2) >> at ../../src/gcc/ipa-devirt.c:689 >> #16 0x0000000000bb5151 in odr_types_equivalent_p (t1=<record_type >> 0x7ffff1aa6a80 Environment>, >> t2=<record_type 0x7ffff1aa6f18 Environment>, warn=true, >> warned=0x7fffffffda43, visited=0x7fffffffda10, loc1=288, >> loc2=2) at ../../src/gcc/ipa-devirt.c:1556 >> #17 0x0000000000bb6ebb in add_type_duplicate (val=0x7ffff18ab4e0, >> type=<record_type 0x7ffff1aa6f18 Environment>) >> at ../../src/gcc/ipa-devirt.c:1848 >> #18 0x0000000000bb77f2 in get_odr_type (type=<record_type 0x7ffff1aa6f18 >> Environment>, insert=true) >> at ../../src/gcc/ipa-devirt.c:2028 >> #19 0x0000000000bb7e42 in register_odr_type (type=<record_type >> 0x7ffff1aa6f18 Environment>) >> at ../../src/gcc/ipa-devirt.c:2111 >> #20 0x00000000007eae64 in lto_read_decls (decl_data=0x7ffff1696000, >> data=0x296c040, resolutions=...) >> at ../../src/gcc/lto/lto.c:1755 >> #21 0x00000000007eb9c3 in lto_file_finalize (file_data=0x7ffff1696000, >> file=0x2968cc0) >> at ../../src/gcc/lto/lto.c:2055 >> #22 0x00000000007eba1b in lto_create_files_from_ids (file=0x2968cc0, >> file_data=0x7ffff1696000, count=0x7fffffffdd4c) >> at ../../src/gcc/lto/lto.c:2065 >> #23 0x00000000007ebb4f in lto_file_read (file=0x2968cc0, >> resolution_file=0x290aad0, count=0x7fffffffdd4c) >> at ../../src/gcc/lto/lto.c:2106 >> #24 0x00000000007ef930 in read_cgraph_and_symbols (nfiles=2, >> fnames=0x28e5c00) at ../../src/gcc/lto/lto.c:2818 >> #25 0x00000000007f0c16 in lto_main () at ../../src/gcc/lto/lto.c:3323 >> #26 0x0000000000eb3ae6 in compile_file () at ../../src/gcc/toplev.c:455 >> #27 0x0000000000eb6de6 in do_compile () at ../../src/gcc/toplev.c:2076 >> #28 0x0000000000eb715c in toplev::main (this=0x7fffffffdeae, argc=16, >> argv=0x28a0aa0) at ../../src/gcc/toplev.c:2211 >> #29 0x0000000001bbd183 in main (argc=15, argv=0x7fffffffdfa8) at >> ../../src/gcc/main.c:39 >> >> My patch put the apply_location_cache immediately before the read in >> add_type_duplicate, but maybe there's a better place? > > Ugh, quite a maze ;) So your original patch is ok unless Honza comes > up with something better. > > Thanks, > Richard. > >> Thanks >> Dave >> >>> >>> Richard. >>> >>> > Thanks >>> > Dave >>> > >>> > > >>> > > > gcc/ChangeLog: >>> > > > PR lto/83121 >>> > > > * ipa-devirt.c (add_type_duplicate): When comparing >>> > > > memory >>> > > > layout, >>> > > > call the lto_location_cache before reading the >>> > > > DECL_SOURCE_LOCATION of the types. >>> > > > >>> > > > gcc/testsuite/ChangeLog: >>> > > > PR lto/83121 >>> > > > * g++.dg/lto/pr83121_0.C: New test case. >>> > > > * g++.dg/lto/pr83121_1.C: New test case. I've noticed that the new tests fail on aarch64/arm: FAIL: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_0.C line 8) FAIL: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_1.C line 2) FAIL: g++.dg/lto/pr83121 (test for LTO warnings, pr83121_1.C line 3) on aarch64, the logs contain: /gcc/testsuite/g++.dg/lto/pr83121_0.C:6:8: warning: type 'struct Environment' violates the C++ One Definition Rule [-Wodr] /gcc/testsuite/g++.dg/lto/pr83121_1.C:1:8: note: a type with different size is defined in another translation unit on arm, the logs contain: /gcc/testsuite/g++.dg/lto/pr83121_0.C:7:10: warning: type 'struct AsyncHooks' violates the C++ One Definition Rule [-Wodr] /gcc/testsuite/g++.dg/lto/pr83121_1.C:2:10: note: a different type is defined in another translation unit /gcc/testsuite/g++.dg/lto/pr83121_0.C:8:21: note: the first difference of corresponding definitions is field 'providers_' /gcc/testsuite/g++.dg/lto/pr83121_1.C:3:21: note: a field of same name but different type is defined in another translation unit /gcc/testsuite/g++.dg/lto/pr83121_0.C:7:10: note: array types have different bounds /gcc/testsuite/g++.dg/lto/pr83121_0.C:6:8: warning: type 'struct Environment' violates the C++ One Definition Rule [-Wodr] /gcc/testsuite/g++.dg/lto/pr83121_1.C:1:8: note: a different type is defined in another translation unit /gcc/testsuite/g++.dg/lto/pr83121_0.C:10:14: note: the first difference of corresponding definitions is field 'async_hooks_' /gcc/testsuite/g++.dg/lto/pr83121_1.C:5:14: note: a field of same name but different type is defined in another translation unit /gcc/testsuite/g++.dg/lto/pr83121_0.C:7:10: note: type 'struct AsyncHooks' itself violates the C++ One Definition Rule /gcc/testsuite/g++.dg/lto/pr83121_1.C:2:10: note: the incompatible type is defined here and on arm only: FAIL: g++.dg/lto/pr83121 cp_lto_pr83121_0.o-cp_lto_pr83121_1.o link, -O0 -flto Christophe >>> > > > * lib/lto.exp (lto_handle_diagnostics_for_file): New >>> > > > procedure, >>> > > > adapted from DejaGnu's dg-test. >>> > > > (lto_handle_diagnostics): New procedure. >>> > > > (lto_prune_warns): Ignore informational notes. >>> > > > (lto-link-and-maybe-run): Add "messages_by_file" param. >>> > > > Call lto_handle_diagnostics. Avoid issuing >>> > > > "unresolved" >>> > > > for >>> > > > "execute" when "link" fails if "execute" was not >>> > > > specified. >>> > > > (lto-can-handle-directive): New procedure. >>> > > > (lto-get-options-main): Call lto-can-handle- >>> > > > directive. Add >>> > > > a >>> > > > dg-messages local, using it to set the caller's >>> > > > dg-messages-by-file for the given source file. >>> > > > (lto-get-options): Likewise. >>> > > > (lto-execute): Add dg-messages-by-file local, and pass >>> > > > it >>> > > > to >>> > > > lto-link-and-maybe-run. >>> > > > --- >>> > > > gcc/ipa-devirt.c | 7 +- >>> > > > gcc/testsuite/g++.dg/lto/pr83121_0.C | 12 +++ >>> > > > gcc/testsuite/g++.dg/lto/pr83121_1.C | 10 ++ >>> > > > gcc/testsuite/lib/lto.exp | 199 >>> > > > ++++++++++++++++++++++++++++++++++- >>> > > > 4 files changed, 222 insertions(+), 6 deletions(-) >>> > > > create mode 100644 gcc/testsuite/g++.dg/lto/pr83121_0.C >>> > > > create mode 100644 gcc/testsuite/g++.dg/lto/pr83121_1.C >>> > > > >>> > > > diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c >>> > > > index 540f038..f3d2e4a 100644 >>> > > > --- a/gcc/ipa-devirt.c >>> > > > +++ b/gcc/ipa-devirt.c >>> > > > @@ -1844,7 +1844,12 @@ add_type_duplicate (odr_type val, tree >>> > > > type) >>> > > > } >>> > > > } >>> > > > >>> > > > - /* Next compare memory layout. */ >>> > > > + /* Next compare memory layout. >>> > > > + The DECL_SOURCE_LOCATIONs in this invocation came from >>> > > > LTO >>> > > > streaming. >>> > > > + We must apply the location cache to ensure that they are >>> > > > valid >>> > > > + before we can pass them to odr_types_equivalent_p (PR >>> > > > lto/83121). */ >>> > > > + if (lto_location_cache::current_cache) >>> > > > + lto_location_cache::current_cache->apply_location_cache >>> > > > (); >>> > > > if (!odr_types_equivalent_p (val->type, type, >>> > > > !flag_ltrans && !val- >>> > > > >odr_violated >>> > > > && !warned, >>> > > > &warned, &visited, >>> > > > diff --git a/gcc/testsuite/g++.dg/lto/pr83121_0.C >>> > > > b/gcc/testsuite/g++.dg/lto/pr83121_0.C >>> > > > new file mode 100644 >>> > > > index 0000000..ef894c7 >>> > > > --- /dev/null >>> > > > +++ b/gcc/testsuite/g++.dg/lto/pr83121_0.C >>> > > > @@ -0,0 +1,12 @@ >>> > > > +// { dg-lto-do link } >>> > > > +// { dg-lto-options {{-O0 -flto}} } >>> > > > +/* We need -O0 to avoid the "Environment" locals in the test >>> > > > functions >>> > > > + from being optimized away. */ >>> > > > + >>> > > > +struct Environment { // { dg-lto-warning "8: type 'struct >>> > > > Environment' violates the C\\+\\+ One Definition Rule" } >>> > > > + struct AsyncHooks { >>> > > > + int providers_[2]; // { dg-lto-message "a field of same >>> > > > name >>> > > > but different type is defined in another translation unit" } >>> > > > + }; >>> > > > + AsyncHooks async_hooks_; >>> > > > +}; >>> > > > +void fn2() { Environment a; } >>> > > > diff --git a/gcc/testsuite/g++.dg/lto/pr83121_1.C >>> > > > b/gcc/testsuite/g++.dg/lto/pr83121_1.C >>> > > > new file mode 100644 >>> > > > index 0000000..2aef1b5 >>> > > > --- /dev/null >>> > > > +++ b/gcc/testsuite/g++.dg/lto/pr83121_1.C >>> > > > @@ -0,0 +1,10 @@ >>> > > > +struct Environment { >>> > > > + struct AsyncHooks { // { dg-lto-warning "10: type 'struct >>> > > > AsyncHooks' violates the C\\+\\+ One Definition Rule" } >>> > > > + int providers_[1]; // { dg-lto-message "the first >>> > > > difference >>> > > > of corresponding definitions is field 'providers_'" } >>> > > > + }; >>> > > > + AsyncHooks async_hooks_; >>> > > > +}; >>> > > > +void fn1() { Environment a; } >>> > > > +int main () >>> > > > +{ >>> > > > +} >>> > > > diff --git a/gcc/testsuite/lib/lto.exp >>> > > > b/gcc/testsuite/lib/lto.exp >>> > > > index 477f683..e69d8d4 100644 >>> > > > --- a/gcc/testsuite/lib/lto.exp >>> > > > +++ b/gcc/testsuite/lib/lto.exp >>> > > > @@ -16,6 +16,122 @@ >>> > > > >>> > > > # Contributed by Diego Novillo <dnovi...@google.com> >>> > > > >>> > > > +# A subroutine of lto_handle_diagnostics: check TEXT for the >>> > > > expected >>> > > > +# diagnostics for one specific source file, issuing PASS/FAIL >>> > > > results. >>> > > > +# Return TEXT, stripped of any diagnostics that were handled. >>> > > > +# >>> > > > +# NAME is the testcase name to use when reporting PASS/FAIL >>> > > > results. >>> > > > +# FILENAME is the name (with full path) of the file we're >>> > > > interested in. >>> > > > +# MESSAGES_FOR_FILE is a list of expected messages, akin to >>> > > > DejaGnu's >>> > > > +# "dg-messages" variable. >>> > > > +# TEXT is the textual output from the LTO link. >>> > > > + >>> > > > +proc lto_handle_diagnostics_for_file { name filename >>> > > > messages_for_file text } { >>> > > > + global dg-linenum-format >>> > > > + >>> > > > + set filename_without_path [file tail $filename] >>> > > > + >>> > > > + # This loop is adapted from the related part of DejaGnu's >>> > > > dg- >>> > > > test, >>> > > > + # with changes as detailed below to cope with the LTO >>> > > > case. >>> > > > + >>> > > > + foreach i ${messages_for_file} { >>> > > > + verbose "Scanning for message: $i" 4 >>> > > > + >>> > > > + # Remove all error messages for the line [lindex $i 0] >>> > > > + # in the source file. If we find any, success! >>> > > > + set line [lindex $i 0] >>> > > > + set pattern [lindex $i 2] >>> > > > + set comment [lindex $i 3] >>> > > > + verbose "line: $line" 4 >>> > > > + verbose "pattern: $pattern" 4 >>> > > > + verbose "comment: $comment" 4 >>> > > > + #send_user "Before:\n$text\n" >>> > > > + >>> > > > + # Unlike dg-test, we use $filename_without_path in this >>> > > > pattern. >>> > > > + # This is to ensure that we have the correct file/line >>> > > > combination. >>> > > > + # This imposes the restriction that the filename can't >>> > > > contain >>> > > > + # any regexp control characters. We have to strip the >>> > > > path, since >>> > > > + # e.g. the '+' in "g++.dg" wouldn't be valid. >>> > > > + set pat >>> > > > "(^|\n)(\[^\n\]+$filename_without_path$line\[^\n\]*($pattern)\[ >>> > > > ^\n\ >>> > > > ]*\n?)+" >>> > > > + if {[regsub -all $pat $text "\n" text]} { >>> > > > + set text [string trimleft $text] >>> > > > + set ok pass >>> > > > + set uhoh fail >>> > > > + } else { >>> > > > + set ok fail >>> > > > + set uhoh pass >>> > > > + } >>> > > > + #send_user "After:\n$text\n" >>> > > > + >>> > > > + # $line will either be a formatted line number or a >>> > > > number >>> > > > all by >>> > > > + # itself. Delete the formatting. >>> > > > + scan $line ${dg-linenum-format} line >>> > > > + >>> > > > + # Unlike dg-test, add the filename to the PASS/FAIL >>> > > > message >>> > > > (rather >>> > > > + # than just the line number) so that the user can >>> > > > identify >>> > > > the >>> > > > + # pertinent directive. >>> > > > + set describe_where "$filename_without_path line $line" >>> > > > + >>> > > > + # Issue the PASS/FAIL, adding "LTO" to the messages >>> > > > (e.g. >>> > > > "LTO errors") >>> > > > + # to distinguish them from the non-LTO case (in case we >>> > > > ever need to >>> > > > + # support both). >>> > > > + switch [lindex $i 1] { >>> > > > + "ERROR" { >>> > > > + $ok "$name $comment (test for LTO errors, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "XERROR" { >>> > > > + x$ok "$name $comment (test for LTO errors, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "WARNING" { >>> > > > + $ok "$name $comment (test for LTO warnings, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "XWARNING" { >>> > > > + x$ok "$name $comment (test for LTO warnings, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "BOGUS" { >>> > > > + $uhoh "$name $comment (test for LTO bogus >>> > > > messages, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "XBOGUS" { >>> > > > + x$uhoh "$name $comment (test for LTO bogus >>> > > > messages, $describe_where)" >>> > > > + } >>> > > > + "BUILD" { >>> > > > + $uhoh "$name $comment (test for LTO build >>> > > > failure, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "XBUILD" { >>> > > > + x$uhoh "$name $comment (test for LTO build >>> > > > failure, >>> > > > $describe_where)" >>> > > > + } >>> > > > + "EXEC" { } >>> > > > + "XEXEC" { } >>> > > > + } >>> > > > + } >>> > > > + return $text >>> > > > +} >>> > > > + >>> > > > +# Support for checking for link-time diagnostics: check for >>> > > > +# the expected diagnostics within TEXT, issuing PASS/FAIL >>> > > > results. >>> > > > +# Return TEXT, stripped of any diagnostics that were handled. >>> > > > +# >>> > > > +# MESSAGES_BY_FILE is a dict; the keys are source files (with >>> > > > paths) >>> > > > +# the values are lists of expected messages, akin to DejaGnu's >>> > > > "dg-messages" >>> > > > +# variable. >>> > > > +# TEXT is the textual output from the LTO link. >>> > > > + >>> > > > +proc lto_handle_diagnostics { messages_by_file text } { >>> > > > + global testcase >>> > > > + >>> > > > + verbose "lto_handle_diagnostics: entry: $text" 2 >>> > > > + verbose " messages_by_file $messages_by_file" 3 >>> > > > + >>> > > > + dict for {src dg-messages} $messages_by_file { >>> > > > + set text [lto_handle_diagnostics_for_file $testcase >>> > > > $src \ >>> > > > + ${dg-messages} $text] >>> > > > + } >>> > > > + >>> > > > + verbose "lto_handle_diagnostics: exit: $text" 2 >>> > > > + >>> > > > + return $text >>> > > > +} >>> > > > + >>> > > > # Prune messages that aren't useful. >>> > > > >>> > > > proc lto_prune_warns { text } { >>> > > > @@ -39,6 +155,9 @@ proc lto_prune_warns { text } { >>> > > > regsub -all "(^|\n)\[ \t\]*\[\(\]file \[^\n\]* >>> > > > value=\[^\n\]*; >>> > > > file \[^\n\]* value=\[^\n\]*\[)\];" $text "" text >>> > > > regsub -all "(^|\n)\[ \t\]*\[^\n\]* definition taken" >>> > > > $text "" >>> > > > text >>> > > > >>> > > > + # Ignore informational notes. >>> > > > + regsub -all "(^|\n)\[^\n\]*: note: \[^\n\]*" $text "" text >>> > > > + >>> > > > verbose "lto_prune_warns: exit: $text" 2 >>> > > > >>> > > > return $text >>> > > > @@ -175,12 +294,17 @@ proc lto-obj { source dest optall optfile >>> > > > optstr xfaildata } { >>> > > > # OPTALL is a list of compiler and linker options to use for >>> > > > all >>> > > > tests >>> > > > # OPTFILE is a list of compiler and linker options to use for >>> > > > this >>> > > > test >>> > > > # OPTSTR is the list of options to list in messages >>> > > > -proc lto-link-and-maybe-run { testname objlist dest optall >>> > > > optfile >>> > > > optstr } { >>> > > > +# MESSAGES_BY_FILE is a dict of (src, dg-messages) >>> > > > +proc lto-link-and-maybe-run { testname objlist dest optall >>> > > > optfile >>> > > > optstr \ >>> > > > + messages_by_file } { >>> > > > global testcase >>> > > > global tool >>> > > > global compile_type >>> > > > global board_info >>> > > > >>> > > > + verbose "lto-link-and-maybe-run" 2 >>> > > > + verbose " messages_by_file $messages_by_file" 3 >>> > > > + >>> > > > # Check that all of the objects were built successfully. >>> > > > foreach obj [split $objlist] { >>> > > > if ![file_on_host exists $obj] then { >>> > > > @@ -217,12 +341,17 @@ proc lto-link-and-maybe-run { testname >>> > > > objlist dest optall optfile optstr } { >>> > > > set board_info($target_board,ldscript) $saved_ldscript >>> > > > } >>> > > > >>> > > > + # Check for diagnostics specified by directives >>> > > > + set comp_output [lto_handle_diagnostics $messages_by_file >>> > > > $comp_output] >>> > > > + >>> > > > # Prune unimportant visibility warnings before checking >>> > > > output. >>> > > > set comp_output [lto_prune_warns $comp_output] >>> > > > >>> > > > if ![${tool}_check_compile "$testcase $testname link" >>> > > > $optstr >>> > > > \ >>> > > > $dest $comp_output] then { >>> > > > - unresolved "$testcase $testname execute $optstr" >>> > > > + if { ![string compare "execute" $compile_type] } { >>> > > > + unresolved "$testcase $testname execute $optstr" >>> > > > + } >>> > > > return >>> > > > } >>> > > > >>> > > > @@ -243,6 +372,51 @@ proc lto-link-and-maybe-run { testname >>> > > > objlist >>> > > > dest optall optfile optstr } { >>> > > > $status "$testcase $testname execute $optstr" >>> > > > } >>> > > > >>> > > > +# Potentially handle the given dg- directive (a list) >>> > > > +# Return true is the directive was handled, false otherwise. >>> > > > + >>> > > > +proc lto-can-handle-directive { op } { >>> > > > + set cmd [lindex $op 0] >>> > > > + >>> > > > + # dg-warning and dg-message append to dg-messages. >>> > > > + upvar dg-messages dg-messages >>> > > > + >>> > > > + # A list of directives to recognize, and a list of >>> > > > directives >>> > > > + # to remap them to. >>> > > > + # For example, "dg-lto-warning" is implemented by calling >>> > > > "dg- >>> > > > warning". >>> > > > + set directives { dg-lto-warning dg-lto-message } >>> > > > + set remapped_directives { dg-warning dg-message } >>> > > > + >>> > > > + set idx [lsearch -exact $directives $cmd] >>> > > > + if { $idx != -1 } { >>> > > > + verbose "remapping from: $op" 4 >>> > > > + >>> > > > + set remapped_cmd [lindex $remapped_directives $idx] >>> > > > + set op [lreplace $op 0 0 $remapped_cmd] >>> > > > + >>> > > > + verbose "remapped to: $op" 4 >>> > > > + >>> > > > + set status [catch "$op" errmsg] >>> > > > + if { $status != 0 } { >>> > > > + if { 0 && [info exists errorInfo] } { >>> > > > + # This also prints a backtrace which will just >>> > > > confuse >>> > > > + # testcase writers, so it's disabled. >>> > > > + perror "$name: $errorInfo\n" >>> > > > + } else { >>> > > > + perror "$name: $errmsg for \"$op\"\n" >>> > > > + } >>> > > > + # ??? The call to unresolved here is necessary to >>> > > > clear >>> > > > `errcnt'. >>> > > > + # What we really need is a proc like perror that >>> > > > doesn't set errcnt. >>> > > > + # It should also set exit_status to 1. >>> > > > + unresolved "$name: $errmsg for \"$op\"" >>> > > > + } >>> > > > + >>> > > > + return true >>> > > > + } >>> > > > + >>> > > > + return false >>> > > > +} >>> > > > + >>> > > > # lto-get-options-main -- get target requirements for a test >>> > > > and >>> > > > # options for the primary source file and the test as a whole >>> > > > # >>> > > > @@ -266,6 +440,10 @@ proc lto-get-options-main { src } { >>> > > > upvar dg-final-code dg-final-code >>> > > > set dg-final-code "" >>> > > > >>> > > > + # dg-warning and dg-message append to dg-messages. >>> > > > + upvar dg-messages-by-file dg-messages-by-file >>> > > > + set dg-messages "" >>> > > > + >>> > > > set tmp [dg-get-options $src] >>> > > > verbose "getting options for $src: $tmp" >>> > > > foreach op $tmp { >>> > > > @@ -342,12 +520,15 @@ proc lto-get-options-main { src } { >>> > > > } else { >>> > > > append dg-final-code "[lindex $op 2]\n" >>> > > > } >>> > > > - } else { >>> > > > + } elseif { ![lto-can-handle-directive $op] } { >>> > > > # Ignore unrecognized dg- commands, but warn about >>> > > > them. >>> > > > warning "lto.exp does not support $cmd" >>> > > > } >>> > > > } >>> > > > >>> > > > + verbose "dg-messages: ${dg-messages}" 3 >>> > > > + dict append dg-messages-by-file $src ${dg-messages} >>> > > > + >>> > > > # Return flags to use for compiling the primary source >>> > > > file >>> > > > and for >>> > > > # linking. >>> > > > verbose "dg-extra-tool-flags for main is ${dg-extra-tool- >>> > > > flags}" >>> > > > @@ -373,6 +554,10 @@ proc lto-get-options { src } { >>> > > > # dg-xfail-if needs access to dg-do-what. >>> > > > upvar dg-do-what dg-do-what >>> > > > >>> > > > + # dg-warning appends to dg-messages. >>> > > > + upvar dg-messages-by-file dg-messages-by-file >>> > > > + set dg-messages "" >>> > > > + >>> > > > set tmp [dg-get-options $src] >>> > > > foreach op $tmp { >>> > > > set cmd [lindex $op 0] >>> > > > @@ -386,12 +571,15 @@ proc lto-get-options { src } { >>> > > > } >>> > > > } elseif { [string match "dg-require-*" $cmd] } { >>> > > > warning "lto.exp does not support $cmd in secondary >>> > > > source files" >>> > > > - } else { >>> > > > + } elseif { ![lto-can-handle-directive $op] } { >>> > > > # Ignore unrecognized dg- commands, but warn about >>> > > > them. >>> > > > warning "lto.exp does not support $cmd in secondary >>> > > > source files" >>> > > > } >>> > > > } >>> > > > >>> > > > + verbose "dg-messages: ${dg-messages}" 3 >>> > > > + dict append dg-messages-by-file $src ${dg-messages} >>> > > > + >>> > > > return ${dg-extra-tool-flags} >>> > > > } >>> > > > >>> > > > @@ -421,6 +609,7 @@ proc lto-execute { src1 sid } { >>> > > > verbose "lto-execute: $src1" 1 >>> > > > set compile_type "run" >>> > > > set dg-do-what [list ${dg-do-what-default} "" P] >>> > > > + set dg-messages-by-file [dict create] >>> > > > set extra_flags(0) [lto-get-options-main $src1] >>> > > > set compile_xfail(0) "" >>> > > > >>> > > > @@ -544,7 +733,7 @@ proc lto-execute { src1 sid } { >>> > > > lto-link-and-maybe-run \ >>> > > > "[lindex $obj_list 0]-[lindex $obj_list >>> > > > end]" \ >>> > > > $obj_list $execname $filtered ${dg-extra- >>> > > > ld- >>> > > > options} \ >>> > > > - $filtered >>> > > > + $filtered ${dg-messages-by-file} >>> > > > } >>> > > > >>> > > > >>> > > > -- >>> > > > 1.8.5.3 >>> > > > >>> >>>