From 9638589faff5b5ec33afba0b5a4560a3f0b5aaa6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 2 Dec 2017 00:38:54 +0000 Subject: [PATCH] compiler: avoid GCC middle-end control warnings GCC has started emitting "control reaches end of non-void function" warnings. Avoid them for Go by 1) marking the builtin function panic and the compiler-generated function __go_runtime_error as not returning and 2) adding a default case to the switch used for select statements that simply calls __builtin_unreachable. Fixes golang/go#22767 Reviewed-on: https://go-review.googlesource.com/80416 * go-gcc.cc (Gcc_backend::Gcc_backend): Define __builtin_unreachable. (Gcc_backend::function): Add does_not_return parameter. From-SVN: r255346 --- gcc/go/ChangeLog | 6 ++++++ gcc/go/go-gcc.cc | 15 ++++++++++++--- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/backend.h | 5 ++++- gcc/go/gofrontend/gogo.cc | 16 +++++++++++----- gcc/go/gofrontend/runtime.def | 3 +++ gcc/go/gofrontend/statements.cc | 11 ++++++++--- 7 files changed, 45 insertions(+), 13 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 26f823e0442..03100610d71 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,9 @@ +2017-12-01 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::Gcc_backend): Define + __builtin_unreachable. + (Gcc_backend::function): Add does_not_return parameter. + 2017-12-01 Than McIntosh * go-c.h (go_create_gogo_args): Add nil_check_size_threshold diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 1b0190d954b..730e2da24ed 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -486,7 +486,8 @@ class Gcc_backend : public Backend Bfunction* function(Btype* fntype, const std::string& name, const std::string& asm_name, bool is_visible, bool is_declaration, bool is_inlinable, - bool disable_split_stack, bool in_unique_section, Location); + bool disable_split_stack, bool does_not_return, + bool in_unique_section, Location); Bstatement* function_defer_statement(Bfunction* function, Bexpression* undefer, @@ -760,6 +761,12 @@ Gcc_backend::Gcc_backend() const_ptr_type_node, NULL_TREE), false, false); + + // The compiler uses __builtin_unreachable for cases that can not + // occur. + this->define_builtin(BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL, + build_function_type(void_type_node, void_list_node), + true, true); } // Get an unnamed integer type. @@ -3012,8 +3019,8 @@ Bfunction* Gcc_backend::function(Btype* fntype, const std::string& name, const std::string& asm_name, bool is_visible, bool is_declaration, bool is_inlinable, - bool disable_split_stack, bool in_unique_section, - Location location) + bool disable_split_stack, bool does_not_return, + bool in_unique_section, Location location) { tree functype = fntype->get_tree(); if (functype != error_mark_node) @@ -3049,6 +3056,8 @@ Gcc_backend::function(Btype* fntype, const std::string& name, tree attr = get_identifier ("no_split_stack"); DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE); } + if (does_not_return) + TREE_THIS_VOLATILE(decl) = 1; if (in_unique_section) resolve_unique_section(decl, 0, 1); diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index ca329c2de32..61f94159974 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -8cd42a3e9e0e618bb09e67be73f7d2f2477a0faa +1949a203fca0c8bde6f2690ebc36427c5e3953c7 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 48dbe7eb0da..601e7c95b3a 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -711,12 +711,15 @@ class Backend // IS_INLINABLE is true if the function can be inlined. // DISABLE_SPLIT_STACK is true if this function may not split the stack; this // is used for the implementation of recover. + // DOES_NOT_RETURN is true for a function that does not return; this is used + // for the implementation of panic. // IN_UNIQUE_SECTION is true if this function should be put into a unique // location if possible; this is used for field tracking. virtual Bfunction* function(Btype* fntype, const std::string& name, const std::string& asm_name, bool is_visible, bool is_declaration, bool is_inlinable, - bool disable_split_stack, bool in_unique_section, Location) = 0; + bool disable_split_stack, bool does_not_return, + bool in_unique_section, Location) = 0; // Create a statement that runs all deferred calls for FUNCTION. This should // be a statement that looks like this in C++: diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 74b45958f61..b1c780794c9 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -711,7 +711,7 @@ Gogo::init_imports(std::vector& init_stmts, Bfunction *bfunction) Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name, true, true, true, false, - false, unknown_loc); + false, false, unknown_loc); Bexpression* pfunc_code = this->backend()->function_code_expression(pfunc, unknown_loc); Bexpression* pfunc_call = @@ -5435,8 +5435,8 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) this->fndecl_ = gogo->backend()->function(functype, no->get_id(gogo), asm_name, is_visible, false, is_inlinable, - disable_split_stack, in_unique_section, - this->location()); + disable_split_stack, false, + in_unique_section, this->location()); } return this->fndecl_; } @@ -5448,6 +5448,8 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) { if (this->fndecl_ == NULL) { + bool does_not_return = false; + // Let Go code use an asm declaration to pick up a builtin // function. if (!this->asm_name_.empty()) @@ -5459,6 +5461,10 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) this->fndecl_ = builtin_decl; return this->fndecl_; } + + if (this->asm_name_ == "runtime.gopanic" + || this->asm_name_ == "__go_runtime_error") + does_not_return = true; } std::string asm_name; @@ -5475,8 +5481,8 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) Btype* functype = this->fntype_->get_backend_fntype(gogo); this->fndecl_ = gogo->backend()->function(functype, no->get_id(gogo), asm_name, - true, true, true, false, false, - this->location()); + true, true, true, false, does_not_return, + false, this->location()); } return this->fndecl_; diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 6df53498d72..ef148eec9b0 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -363,6 +363,9 @@ DEF_GO_RUNTIME(PRINTNL, "runtime.printnl", P0(), R0()) DEF_GO_RUNTIME(FIELDTRACK, "__go_fieldtrack", P1(POINTER), R0()) +// Unreachable code. +DEF_GO_RUNTIME(UNREACHABLE, "__builtin_unreachable", P0(), R0()) + // Remove helper macros. #undef ABFT6 #undef ABFT2 diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index d3878a6ba05..93718ff8c2a 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -4866,8 +4866,8 @@ Select_clauses::get_backend(Translate_context* context, Location location) { size_t count = this->clauses_.size(); - std::vector > cases(count); - std::vector clauses(count); + std::vector > cases(count + 1); + std::vector clauses(count + 1); Type* int_type = Type::lookup_integer_type("int"); @@ -4905,10 +4905,15 @@ Select_clauses::get_backend(Translate_context* context, return context->backend()->expression_statement(bfunction, bcall); } + Bfunction* bfunction = context->function()->func_value()->get_decl(); + + Expression* crash = Runtime::make_call(Runtime::UNREACHABLE, location, 0); + Bexpression* bcrash = crash->get_backend(context); + clauses[count] = context->backend()->expression_statement(bfunction, bcrash); + std::vector statements; statements.reserve(2); - Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* switch_stmt = context->backend()->switch_statement(bfunction, bcall, cases, -- 2.30.2