The GCC middle-end has started emitting "control reaches end of non-void function" warnings. This are not too useful for Go, which implements its own error for this in the frontend. Avoid the middle-end warnings 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. This fixes https://golang.org/issue/22767. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian 2017-12-01 Ian Lance Taylor <i...@golang.org> * go-gcc.cc (Gcc_backend::Gcc_backend): Define __builtin_unreachable. (Gcc_backend::function): Add does_not_return parameter.
Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 255340) +++ gcc/go/go-gcc.cc (working copy) @@ -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, con 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); Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 255340) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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. Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 255340) +++ gcc/go/gofrontend/backend.h (working copy) @@ -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++: Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 255340) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -711,7 +711,7 @@ Gogo::init_imports(std::vector<Bstatemen 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, N 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(G { 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(G 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(G 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_; Index: gcc/go/gofrontend/runtime.def =================================================================== --- gcc/go/gofrontend/runtime.def (revision 255340) +++ gcc/go/gofrontend/runtime.def (working copy) @@ -363,6 +363,9 @@ DEF_GO_RUNTIME(PRINTNL, "runtime.printnl 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 Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 255340) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -4866,8 +4866,8 @@ Select_clauses::get_backend(Translate_co Location location) { size_t count = this->clauses_.size(); - std::vector<std::vector<Bexpression*> > cases(count); - std::vector<Bstatement*> clauses(count); + std::vector<std::vector<Bexpression*> > cases(count + 1); + std::vector<Bstatement*> clauses(count + 1); Type* int_type = Type::lookup_integer_type("int"); @@ -4905,10 +4905,15 @@ Select_clauses::get_backend(Translate_co 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<Bstatement*> statements; statements.reserve(2); - Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* switch_stmt = context->backend()->switch_statement(bfunction, bcall, cases,