Re: Fix class type lookup from OBJ_TYPE_REF
> This patch causes an ICE when building libobjc, which is part of > normal bootstrap. > > PR 58179 > > /nasfarm/edelsohn/src/src/libobjc/accessors.m: In function 'objc_getProperty': > /nasfarm/edelsohn/src/src/libobjc/accessors.m:127:11: internal > compiler error: in obj_type_ref_class, at tree.c:11876 > result = RETAIN (*(pointer_to_ivar)); Oops, sorry, I was really convinced OBJ_TYPE_REF is a C++ thing so I did not test obj-C. The obj-C use is produced by: /* Possibly rewrite a function CALL into an OBJ_TYPE_REF expression. This needs to be done if we are calling a function through a cast. */ tree objc_rewrite_function_call (tree function, tree first_param) { if (TREE_CODE (function) == NOP_EXPR && TREE_CODE (TREE_OPERAND (function, 0)) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (TREE_OPERAND (function, 0), 0)) == FUNCTION_DECL) { function = build3 (OBJ_TYPE_REF, TREE_TYPE (function), TREE_OPERAND (function, 0), first_param, size_zero_node); } return function; } so obviously it is again type of the first parameter that correspond to the type of a pointer to the class. I am testing Index: tree.c === --- tree.c (revision 201814) +++ tree.c (working copy) @@ -11873,7 +11873,11 @@ obj_type_ref_class (tree ref) ref = TREE_TYPE (ref); gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE); ref = TREE_TYPE (ref); - gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE); + /* Wee look for type THIS points to. ObjC also builds + OBJ_TYPE_REF with non-method calls, their first parameter + ID however also corresponds to class type. */ + gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE + || TREE_CODE (ref) == FUNCTION_TYPE); ref = TREE_VALUE (TYPE_ARG_TYPES (ref)); gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE); return TREE_TYPE (ref); This obviously should get me to the same value as TREE_TYPE (TREE_TYPE (FIRST_PARAM)) the old code will get from OBJ_REF_OBJECT generated above. I will go with this patch if it passes testing to unbreak bootstrap. The question however is if we should not drop OBJ_TYPE_REF generation in objc or if we want to somehow add the necesary bits to actually make it useful? At least in the testcase above however there is no TYPE_BINFO attached, so there is no way backend can actually take use of it. OBJ_TYPE_REF will just sit there and consume memory + drag alive the parameter. By grep, objc prouces some BINFOs but they never have VTABLE attached. So even if sometimes binfo was there, the devirtualization machinery will be unable to do anything useful about it. Moreover objc apparently never produce any virtual functions/methods. Can someone explain me in greater detail how the objc use works? Honza
Go patch committed: Don't generate range value for sink
This patch from Chris Manghane fixes a bug when the value in a range clause is a sink variable. It's fixedbugs/bug454.go in the master Go testsuite, and will appear in the gccgo testsuite in due course. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch. Ian diff -r 4baad377e84a go/parse.cc --- a/go/parse.cc Sat Aug 17 10:56:57 2013 -0700 +++ b/go/parse.cc Sat Aug 17 11:02:05 2013 -0700 @@ -5266,7 +5266,8 @@ no->var_value()->set_type_from_range_value(); if (is_new) any_new = true; - p_range_clause->value = Expression::make_var_reference(no, location); + if (!Gogo::is_sink_name(pti->name())) +p_range_clause->value = Expression::make_var_reference(no, location); } if (!any_new)
Re: Fix class type lookup from OBJ_TYPE_REF
Hi, this is the patch I comitted after testing. My apologizes for the breakage. Honza Index: ChangeLog === --- ChangeLog (revision 201816) +++ ChangeLog (working copy) @@ -1,3 +1,8 @@ +2013-08-16 Jan Hubicka + + PR middle-end/58179 + * tree.c (obj_type_ref_class): Do not ICE on non-method calls. + 2013-08-16 David Edelsohn * config/rs6000/rs6000.md (rs6000_get_timebase_ppc32): Add length Index: tree.c === --- tree.c (revision 201814) +++ tree.c (working copy) @@ -11873,7 +11873,11 @@ obj_type_ref_class (tree ref) ref = TREE_TYPE (ref); gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE); ref = TREE_TYPE (ref); - gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE); + /* We look for type THIS points to. ObjC also builds + OBJ_TYPE_REF with non-method calls, Their first parameter + ID however also corresponds to class type. */ + gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE + || TREE_CODE (ref) == FUNCTION_TYPE); ref = TREE_VALUE (TYPE_ARG_TYPES (ref)); gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE); return TREE_TYPE (ref);
Type inheritance graph analysis & speculative devirtualization, part 1/6
Hi, I have got the ipa-devirt implementation into shape it seems actually useful and working as expected. The main selling point of it for the moment is compile time of C++ programs (especially with LTO) and verification facilities. Currently we keep all virtual functions in the callgraph until after inlining in hope that the type based devirtualization will find use of them. This does not happen in wast majorty of cases (currently about 400 times for Firefox). Removing them early, at compile time, reduces tons of streaming and thus linktime speed and memory use. For firefox the callgraph node count goes down from over 3 million functions, to hundred of thousdands. Martin Liska did statistic for me with a recent Firefox tree (rev 201708). Without the patch the overall build time is 33m real, 180m user. LTO link time is 8m real, 26m user. Peaking over 15GB of memory use (combined GCC+linker), With the patch it goes down to 26m real, 149m user and the linking is 6m real, 24m user. Memory use is peaking at 4GB for WPA, parallel part runs to 9GB, but that can be controlled by an parallelism (plus I have independent patch to cut it to half). Memory use graphs can be seen at http://kam.mff.cuni.cz/~hubicka/build1.pdf http://kam.mff.cuni.cz/~hubicka/build2.pdf I think we thus arrived to shape LTO is practically useful for firefox. I still hope to cut WPA in approx half in 4.9 timeframe and we need to address issues with command line options merging at least. Some of the improvements are seen w/o LTO, too. We save running early opts on all those functions, but I did not made any detailed stats. Since the whole area of devirtualization in middle end seems to have very little documentation and number of latent bugs and moreover I am by no means expert on C++ type hiearchy a virtual calls, I decided to break up the change into small patches and try to write an detailed description for each, so hopefully it will be easier to eyeball the changes and hopefully identify issues + get things more sane. The plan is as follows part 1: tracking of all polymorphic calls in indirect_info (until now we track part 2: basic ipa-devirt type inheritance graph construction code, debugging dumps, function to get possible targets of given virtual function call and its use at callgraph construction time. This is the part bringing important improvements on compile time, especially with firefox LTO because we get rid of unreachable function calls comming from headers quickly without having them to bubble through early optimization, LTO streaming and merging. part 4: verifier that all devirtualization decisions are in the list of possible targets + user warning when this is not true for virtual table access folding machinery. Ignoring GCC bugs it can happen only in programs with undefined effect. Falss warnings are useful to detect changes where type inheritance graph is broken. part 3: support for One Definition Rule matching at LTO time. This needs fix to types_same_for_odr I posted to the original thread. It also adds logic to match multiple different tree types together, detect some ODR violations, eliminate external vtables when internal are around and other bit subtle details. part 4: Use of ipa-devirt in unreachable function removal (that is done at LTO time, too) part 5: Do devirtualization for types in local namespaces where there is only one candidate. part 6: Do speculative devirtualization when there is only one candidate. This will handle Firefox's addref. All these changes are conceptually very easy. I found number of weird things and little improvements in the current devirt code I will send independently. I am also trying to keep code flexible so it allows further development: such as tracking of multiple type variants with same targets thorough ipa-cp and folding and such. The dynamic type changes seems somewhat scary so I want to keep code simple at start to be sure it won't produce wrong code. (in the plan above only part 5 risks bad code). This is part 1 of the series. Nothing really fancy is going on here. It adds code to cgraph.c to notice all polymorphic calls and record the info. I also added virtual_method_call_p that disables the devirtualization code path from trying to do something on the OBJ-C OBJ_TYPE_REF use because it can not work as currently written. If we remove it, we can use test for OBJ_TYPE_REF again instead. Boostrapped/regtested x86_64-linux, testing ppc64-linux and will commit it if passes and there are no objections. Honza * cgraph.c (cgraph_create_indirect_edge): Discover polymorphic calls and record basic info into indirect_info. * gimple-fold.c (gimple_fold_call): When doing BINFO based devirtualization, ignore objc function calls. * ipa-cp.c (initialize_node_lattices): Be
Re: [PATCH] Sanitize block partitioning under -freorder-blocks-and-partition
> > I added both of these and ran into issues due to profile maintenance. > For example, there were non-zero blocks in the cold section because > pro_and_epilogue split a simple return block that was previously reach > by both hot and cold paths. The new return block that was then only > reached via the cold path did not have its count properly updated to > reflect this, and since with this patch, blocks dominated by cold > blocks are remarked cold, we ended up with a non-zero count block in > the cold section. And there were 0 count blocks reached by non-zero > edges because copyprop did not clean up edge weights after removing > some branches and blocks, leading to non-zero edge weights that had > previously targeted a branch that was removed, now targeting a 0 count > block that the removed branch always branched around. I see, can you please send fixes for the problems you identified? Thanks for owrking on this! > > In any case, the good news is in that the cases I looked at, the > splitting code is doing the right thing and these blocks that were > marked cold really were cold. It would be great to fix the profile > maintenance issues, but that in the meantime the above sanity checks > are too aggressive. We can keep them and output info into dump file - it is what most of the profile sanity checking does anyway. Did you try to use Martin's linker script to turn text.unlikely section unexecutable? I think that way we will easily find what really causes us to use it during startup of trained application (just like Martin does for gimp). > > I think it makes sense to commit the current patch if possible, as it > is making the splitting more sane. My only concern about the patch is that I am not convinced the dominator based code has chance to work reliably enough so we won't see too many accesses into the cold section. We can commit it and work on better solution incrementally but it will probably mean replacing it later. If you think it makes things easier to work on it incrementally, I think the patch is OK. > > > - I'll try building and profiling gimp myself to see if I can > > reproduce the issue with code executing out of the cold section. > > I have spent some time this week trying to get the latest gimp Martin > pointed me to configured and built, but it took awhile to track down > and configure/build all of the required versions of dependent > packages. I'm still hitting some issues trying to get it compiled, so > it may not yet be configured properly. I'll take a look again early > next week. I do not think there is anything special about gimp. You can probably take any other bigger app, like GCC itself. With profiledbootstrap and linker script to lock unlikely section you should get ICEs where we jump into cold secton and should not. > > Teresa > > patch for updating counts based on estimated frequencies to address > inlined comdats with 0 profile counts: > > 013-08-16 Teresa Johnson > > * tree-inline.c (copy_bb): Compute count based on frequency. > (copy_edges_for_bb): Ditto. > (copy_cfg_body): Ditto. > (copy_body): Pass down frequency. > (expand_call_inline): Ditto. > (tree_function_versioning): Ditto. > * predict.c (init_and_estimate_bb_frequencies): New function. > (rebuild_frequencies): Invoke init_and_estimate_bb_frequencies. > * predict.h (init_and_estimate_bb_frequencies): Declare. > * profile.c (branch_prob): Invoke init_and_estimate_bb_frequencies. > * ipa-inline-transform.c (update_noncloned_frequencies): Scale edge > counts. > (clone_inlined_nodes): Compute edge count scale if needed. I do not see why inliner needs to care about scaling more than it does right now. So you have init_and_estimate_bb_frequencies that force profile guessing on a given function body. In addition to that I thing you need something like freqs_to_counts that will compute counts based on freqs with given scale (actually you can do that as part of propagation before frequencies are scalled to the usual 0...FREQ_MAX scale and precision is lost). Because offline COMDAT functoin will be porduced for every COMDAT used, I think it is bad to porduce any COMDAT (or any reachable function via calls with non-0 count) that has empty profile (either because it got lost by COMDAT merging or because of reading mismatch). So I guess you can just check functions with 0 count and non-0 count callers and initialize their guessed profile. Some capping will probably be needed to not propagate insanely large numbers.. Since new direct calls can be discovered later, inline may want to do that again each time it inlines non-0 count call of COMDAT with 0 count... Honza > > Index: tree-inline.c > === > --- tree-inline.c (revision 201644) > +++ tree-inline.c (working copy) > @@ -1502,7 +1502,7 @@ remap_gimple_stmt (gimple stmt,
Re: Fix class type lookup from OBJ_TYPE_REF
On Sat, 17 Aug 2013, Jan Hubicka wrote: > this is the patch I comitted after testing. > My apologizes for the breakage. > > +2013-08-16 Jan Hubicka > + > + PR middle-end/58179 > + * tree.c (obj_type_ref_class): Do not ICE on non-method calls. This fixes my bootstraps on {amd64,i386}-unknown-freebsd*, too. Thanks. Gerald
[RFC] Issues with intraprocedural devirtualization
Hi, this patch tries to make gimple_extract_devirt_binfo_from_cst little bit more sane and make it match bit more cases. Currently we seem to be able to devirtualize only if the type in question has no basetypes (not even some not having virtual methods at all) and it is the initial type implementing the given virtual method (i.e. we even refuse any derivation not giving new implementation of the virtual method in question). This is bit silly. What the current implemntation does === gimple_extract_devirt_binfo_from_cst looks for address expression that object used for virtual method comes from. It sees something like &var + 10; It looks at the type of VAR and tries to look for a field at offset 10. If it suceeds it verify that the field is not artificial (i.e. it is not base of some outer type present in var) and that its BINFO has no derived types (it basically has to be the original type defining the virtual method and the type can not be derived at all). After this happen the caller proceeds by calling get_binfo_at_offset and by lookup of virtual call from vtable found. Why it does so == I was always confused on why gimple_extract_devirt_binfo_from_cst apparently duplicates logic of get_binfo_at_offset and why it has the limitations. Disussing this with Martin, it is about dynamic type changes. My understanding is that 1) we want the type to not have base because we may have inlined the constructor. During construction the vtables are filled by base's vtable and thus we can not simply devirtualize based on the final virtual table without proving that constructor was not (partially) inlined. This is ensured by the exisitng code refusing artifical types and by the check for number of bases being 0. 2) apparently the code is supposed to refuse non-0 offset because ipa-prop is tracking possibly dynamic type changes only for beggining of the objects. What is wrong with 1 I think 1) is unnecesarily restrictive. a) when tyhe bases of type found define no virtual methods (or do not define virtual method in question) then partially constructed types are not harmful. b) when the type found has a base type that defines given method, but do not overwrite it, we are safe too. Less conservative solution for 1 I think 1) can be also ignored in gimple_extract_devirt_binfo_from_cst pushing the need to check for effects of partial construction into users. I think I can track constructors inlined into given function, but I am not doing it right now. Intead I do two lookups - I find the method by the mechanizm above and I compare it with the first definition of the method. If they are same, I devirtualize. What seems worng with 2 === For 2) i actually found no code checking it. All I can notice that current implementation will always fail to find anything in ipa-prop when indirect_info->offset is non-0. This is because the conditions implementing 1) prevents gimple_extract_devirt_binfo_from_cst to return anything than the final type and it will never match on any derived type (making the whole thing bit pointless, since devirtualization is mostly about derived types I think). Solution for 2 == It does not seem to break the testcases, but if check_stmt_for_type_change really can not detect changes outside the main object, then I think all the code above is wrong anyway and it needs to test for zero the combined offset (i.e. offset given by get_ref_base_and_extent on the constant as well as offset of the basetype given by indirect_info->offset). This can be done easily and will disable any transformations on derived types, but I suppose I can extend it incrementally. I am also confused why ipa-prop needs to track dynamic changes, while gimple-fold is happy without doing so. I do not know if one can do something like having automatic variable of class A and use placement new to change it to class B. I tried to change devirt-6.C testcase to do so but did not suceed in producing anything that would seem to have sane construction and destruction order. The local variable is destructed at the end of sope block, so I would at least need to placement new it to something class B, do somethjing and then placement new it back so the destructor can be called. I would hope this is invalid. Is there any sane summary of restriction of placement new use? If such changing of dyanmic type is possible, we will need to track in gimple-fold the changes, too. My secret plan is to track these cases and devirtualize speculatively - the dynamic type changes are rare and often they can be detected by the local constant propagation on memory locations and optimized out anyway (at least for the inlined constructors). Why I can not use get_binfo_at_offset = Finally I decided to replace the lookup of b
Re: [RFC] Issues with intraprocedural devirtualization
On 08/17/2013 05:44 PM, Jan Hubicka wrote: 1) we want the type to not have base because we may have inlined the constructor. During construction the vtables are filled by base's vtable and thus we can not simply devirtualize based on the final virtual table without proving that constructor was not (partially) inlined. If the constructor is inlined into the current function, then we can see the most recent assignment to the vptr and use that for devirtualization. I do not know if one can do something like having automatic variable of class A and use placement new to change it to class B. This is something of a grey area in the standard, with a few defect reports yet to be resolved. I think it should be undefined behavior. Finally I decided to replace the lookup of base binfo by call to get_binfo_at_offset. This is not possible. For example my base variable can be: struct {class A a; class B b} var; and offset 10 may point to class B. Here I get an ICE since TYPE_BINFO of the structure is NULL (it is not class). I don't understand. In C++ a struct is a class. I wonder if we can track functions that return pointers/values of objects exactly of given type (i.e. no derivations). If the function returns by value, it's always a value of that exact type. Is the dynamic type upon return from constructor always known to be of constructor's type? Yes. We may want to introduce assert_type_expr use like: obj_ptr = assert_type_expr obj_ptr; that can be dropped by FE for us to drive those more interesting cases, like partial construction. I guess we would need to be careful to insert those after vptr assignments within the constructor body, as well. Jason
C++ PATCH for c++/58083 (ICE with lambda in default argument)
The standard says that lambdas go in the enclosing block, class or namespace scope, but also that default arguments aren't parsed until the class is complete. So we need to accept pushing a lambda into a complete class. Tested x86_64-pc-linux-gnu, applying to trunk and 4.8. commit a3eed6be088f776afde7a9d6020a477dc04c23f2 Author: Jason Merrill Date: Wed Aug 7 16:40:53 2013 -0400 PR c++/58083 * name-lookup.c (push_class_level_binding_1): It's OK to push a lambda type after the enclosing type is complete. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 0fe0246..cf6c757 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3062,8 +3062,10 @@ push_class_level_binding_1 (tree name, tree x) if (name == error_mark_node) return false; - /* Check for invalid member names. */ - gcc_assert (TYPE_BEING_DEFINED (current_class_type)); + /* Check for invalid member names. But don't worry about a default + argument-scope lambda being pushed after the class is complete. */ + gcc_assert (TYPE_BEING_DEFINED (current_class_type) + || LAMBDA_TYPE_P (TREE_TYPE (decl))); /* Check that we're pushing into the right binding level. */ gcc_assert (current_class_type == class_binding_level->this_entity); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg5.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg5.C new file mode 100644 index 000..d85918d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-defarg5.C @@ -0,0 +1,30 @@ +// PR c++/58083 +// { dg-do compile { target c++11 } } + +namespace details { +struct iterator_concept_checker +{ +typedef char yes_type; +typedef char (&no_type)[2]; + +template +static no_type test(...); + +template +static yes_type test( +int* + , void (*)(T) = [](T it) +{ +auto copy = T{it}; // copy constructible +copy = it; // copy assignable +copy.~T(); // destroyable +++it; // incrementable +} + ); +}; +} + +int main() +{ + details::iterator_concept_checker::test(0); +}
Re: [RFC] Issues with intraprocedural devirtualization
On Sat, Aug 17, 2013 at 7:56 PM, Jason Merrill wrote: >> I do not know if one can do >> something like having automatic variable of class A and use placement new >> to change it to class B. > > > This is something of a grey area in the standard, with a few defect reports > yet to be resolved. I think it should be undefined behavior. Jason, could you remind me of the CWG issue numbers for these? It is also of interest for SG12, even if it isn't going to come withe a different answer. -- Gaby
C++ PATCH for c++/58119 (possibly wrong error with conversion template)
In this testcase, the A conversion template can't possibly produce a pointer type, so its presence in the overload set shouldn't cause an error. The standard is unclear about the B case, but it seems appropriate to me to still complain there. Tested x86_64-pc-linux-gnu, applying to trunk, 4.8, 4.7. commit bd43671e5087c4fbee728305af02abd54bafa91e Author: Jason Merrill Date: Sat Aug 17 21:30:36 2013 -0400 PR c++/58119 * cvt.c (build_expr_type_conversion): Don't complain about a template that can't match the desired type category. diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 532e8fd..08c026d 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1590,17 +1590,6 @@ build_expr_type_conversion (int desires, tree expr, bool complain) if (DECL_NONCONVERTING_P (cand)) continue; - if (TREE_CODE (cand) == TEMPLATE_DECL) - { - if (complain) - { - error ("ambiguous default type conversion from %qT", - basetype); - error (" candidate conversions include %qD", cand); - } - return error_mark_node; - } - candidate = non_reference (TREE_TYPE (TREE_TYPE (cand))); switch (TREE_CODE (candidate)) @@ -1634,11 +1623,23 @@ build_expr_type_conversion (int desires, tree expr, bool complain) break; default: + /* A wildcard could be instantiated to match any desired + type, but we can't deduce the template argument. */ + if (WILDCARD_TYPE_P (candidate)) + win = true; break; } if (win) { + if (TREE_CODE (cand) == TEMPLATE_DECL) + { + if (complain) + error ("default type conversion can't deduce template" + " argument for %qD", cand); + return error_mark_node; + } + if (winner) { tree winner_type diff --git a/gcc/testsuite/g++.dg/template/delete2.C b/gcc/testsuite/g++.dg/template/delete2.C new file mode 100644 index 000..b6ab380 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/delete2.C @@ -0,0 +1,26 @@ +// PR c++/58119 + +template +struct A +{ + operator T*(); + template + operator A(); +}; + +template +struct B +{ + operator T*(); + template + operator A*(); +}; + +int main() +{ + A a; + delete a; + + B b; + delete b; // { dg-error "template|delete" } +}
Re: [RFC] Issues with intraprocedural devirtualization
Jason Merrill wrote: >On 08/17/2013 05:44 PM, Jan Hubicka wrote: >> 1) we want the type to not have base because we may have inlined >the constructor. >> During construction the vtables are filled by base's vtable and >thus we can >> not simply devirtualize based on the final virtual table without >proving that >> constructor was not (partially) inlined. > >If the constructor is inlined into the current function, then we can >see >the most recent assignment to the vptr and use that for >devirtualization. > >> I do not know if one can do >> something like having automatic variable of class A and use placement >new >> to change it to class B. > >This is something of a grey area in the standard, with a few defect >reports yet to be resolved. I think it should be undefined behavior. I'm curious if special.casing the automatic non-pod type case is worth the trouble. At least you need to support placement new on pod class members, in which case you need to be careful with which cases you can reliably detectat the gimple level. As always - look at past dynamic type bugs we had with boost. Richard. >> Finally I decided to replace the lookup of base binfo by call to >> get_binfo_at_offset. This is not possible. For example my base >> variable can be: >> >> struct {class A a; class B b} var; >> >> and offset 10 may point to class B. Here I get an ICE since >TYPE_BINFO >> of the structure is NULL (it is not class). > >I don't understand. In C++ a struct is a class. > >> I wonder if we can track functions that return pointers/values of >objects >> exactly of given type (i.e. no derivations). > >If the function returns by value, it's always a value of that exact >type. > >> Is the dynamic type upon return from constructor always known to be >of >> constructor's type? > >Yes. > >> We may want to introduce assert_type_expr use like: >> >> obj_ptr = assert_type_expr obj_ptr; >> >> that can be dropped by FE for us to drive those more interesting >cases, like >> partial construction. > >I guess we would need to be careful to insert those after vptr >assignments within the constructor body, as well. > >Jason