From 434c4f0c3dc041c598d9d4405d16a2e99110065f Mon Sep 17 00:00:00 2001 From: Ryan Goldberg Date: Wed, 28 Jun 2023 09:17:49 -0400 Subject: [PATCH] PR30570: Improved type inference within the try block to handle elided cases --- elaborate.cxx | 77 ++++++++++++++++++++++++++++++++++++- elaborate.h | 2 + session.cxx | 4 +- session.h | 4 ++ testsuite/semok/pr30570.stp | 41 ++++++++++++++++++++ 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100755 testsuite/semok/pr30570.stp diff --git a/elaborate.cxx b/elaborate.cxx index c36f681a2..b6fbbc016 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -2595,6 +2595,12 @@ semantic_pass (systemtap_session& s) { int rc = 0; + /* PR30570: We track typeresolution_info within the session + * so that not only semantic_pass_types but also other passes have access to + * type resolution capabilities + */ + s.type_res_info = new typeresolution_info(s); + try { // FIXME: interactive mode, register_library_aliases handles @@ -2646,6 +2652,10 @@ semantic_pass (systemtap_session& s) if (s.dump_mode == systemtap_session::dump_functions) rc = s.functions.empty(); + // Type inference is complete + delete s.type_res_info; + s.type_res_info = NULL; + return rc; } @@ -3740,6 +3750,15 @@ dead_assignment_remover::visit_try_block (try_block *s) clog << _F("Eliding unused error string catcher %s at %s", errvar->unmangled_name.to_string().c_str(), lex_cast(*s->tok).c_str()) << endl; + /* PR30570: Since the unused error string is elided we assign the type of errvar (symbol) + * and it's referent (symboldecl) here. + * If this is not done then later type inference cannot determine the type as string since + * s->catch_error_var is removed but the referent remains (in locals) + */ + if (!session.type_res_info) + throw SEMANTIC_ERROR(_("internal error: type_res_info is NULL")); + session.type_res_info->resolve(pe_string, s->catch_error_var); + session.type_res_info->resolve(pe_string, s->catch_error_var->referent); s->catch_error_var = 0; } } @@ -3860,6 +3879,17 @@ dead_stmtexpr_remover::visit_try_block (try_block *s) { if (session.verbose>2) clog << _("Eliding empty try {} block ") << *s->tok << endl; + /* PR30570: Since the try block is elided we assign the type of s->catch_error_var and + * the declaration (referent) here a bit early. Since this is before type inference, + * if a type is inferred then that's what will be used, but if not then we'll have + * already set this default value + */ + if (!session.type_res_info) + throw SEMANTIC_ERROR(_("internal error: type_res_info is NULL")); + if(s->catch_error_var){ + session.type_res_info->resolve(pe_string, s->catch_error_var); + session.type_res_info->resolve(pe_string, s->catch_error_var->referent); + } s = 0; } provide (s); @@ -6085,7 +6115,9 @@ semantic_pass_types (systemtap_session& s) // next pass: type inference unsigned iterations = 0; - typeresolution_info ti (s); + if (!s.type_res_info) + throw SEMANTIC_ERROR(_("internal error: type_res_info is NULL")); + typeresolution_info& ti = *s.type_res_info; ti.assert_resolvability = false; while (1) @@ -7035,6 +7067,12 @@ typeresolution_info::visit_try_block (try_block* e) if (e->catch_error_var) { t = pe_string; + /* Try and resolve the types of the symbol and referent to be a pe_string + * If either was already defined elsewhere with a different type, cause + * a mismatching type semantic error + */ + resolve(t, e->catch_error_var); + resolve(t, e->catch_error_var->referent); e->catch_error_var->visit (this); } if (e->catch_block) @@ -7731,4 +7769,41 @@ typeresolution_info::resolve_details (const token* tok, clog << "resolved type details " << *dest << " to " << *tok << endl; } +/* t type to attempt to resolve to + * e the expression to resolve + */ +void +typeresolution_info::resolve(exp_type t, expression* e){ + const token* tok = e->tok; + + // The type has not been resolved yet so we can do so + if (pe_unknown == e->type){ + e->type = t; + resolved (tok, t); + } + // The type was already resolved to a different type than + // what is being attempted now + else if (t != e->type) + mismatch (tok, t, e->type); +} + +/* t type to attempt to resolve to + * d the symboldecl to resolve + */ +void +typeresolution_info::resolve(exp_type t, symboldecl* d){ + const token* tok = d->tok; + + // The type has not been resolved yet so we can do so + if (pe_unknown == d->type){ + d->type = t; + resolved (tok, t, d); + } + + // The type was already resolved to a different type than + // what is being attempted now + else if (t != d->type) + mismatch (tok, t, d); +} + /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ diff --git a/elaborate.h b/elaborate.h index 91c12a5b8..5f963d2b6 100644 --- a/elaborate.h +++ b/elaborate.h @@ -115,6 +115,8 @@ struct typeresolution_info: public visitor void resolved (const token* tok, exp_type type, const symboldecl* decl = NULL, int index = -1); void resolve_details (const token* tok, const exp_type_ptr& src, exp_type_ptr& dest); + void resolve(exp_type t, expression* e); + void resolve(exp_type t, symboldecl* d); exp_type t; // implicit parameter for nested visit call; may clobber // Upon entry to one of the visit_* calls, the incoming diff --git a/session.cxx b/session.cxx index a22baab47..962825836 100644 --- a/session.cxx +++ b/session.cxx @@ -103,7 +103,8 @@ systemtap_session::systemtap_session (): warningerr_count(0), target_namespaces_pid(0), suppress_costly_diagnostics(0), - last_token (0) + last_token (0), + type_res_info (0) { struct utsname buf; (void) uname (& buf); @@ -307,6 +308,7 @@ systemtap_session::systemtap_session (const systemtap_session& other, target_namespaces_pid(0), suppress_costly_diagnostics(0), last_token (0), + type_res_info (0), symbol_resolver (0) { release = kernel_release = kern; diff --git a/session.h b/session.h index ad92e0aec..3c933749d 100644 --- a/session.h +++ b/session.h @@ -77,6 +77,7 @@ struct module_cache; struct update_visitor; struct compile_server_cache; class language_server; +struct typeresolution_info; // XXX: a generalized form of this descriptor could be associated with // a vardecl instead of out here at the systemtap_session level. @@ -465,6 +466,9 @@ public: const token* last_token; + // Used during the -semantic pass- for tabulating still-unresolved counts + typeresolution_info* type_res_info; + void print_token (std::ostream& o, const token* tok); void print_error (const semantic_error& e); std::string build_error_msg (const semantic_error& e); diff --git a/testsuite/semok/pr30570.stp b/testsuite/semok/pr30570.stp new file mode 100755 index 000000000..3a3804176 --- /dev/null +++ b/testsuite/semok/pr30570.stp @@ -0,0 +1,41 @@ +#!stap -p2 + +# PR30570: ei should be resolvable in all of the following + +# the try block is elided +probe oneshot { + try { } + catch (e1) + { print(e1) } +} + +# error var is elided +probe oneshot { + try { print("foo") } + catch (e2) + { } +} + +# error var and the try block are elided +probe oneshot { + try { } + catch (e3) + { } +} + +# error var and the try block are elided which means +# it's not an issue to use e4 as a long here +global e4 = 10 +probe oneshot { + try { } + catch (e4) + { } +} + +# e5 can be a global string +global e5 = "foo" +probe oneshot { + try { } + catch (e5) + { print(e5) } +} -- 2.43.5