diff options
Diffstat (limited to 'gcc/ada/gcc-interface')
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 58 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils.c | 12 |
2 files changed, 57 insertions, 13 deletions
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index a343261..258b79c 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -1481,6 +1481,49 @@ Pragma_to_gnu (Node_Id gnat_node) return gnu_result; } + +/* Check the inlining status of nested function FNDECL in the current context. + + If a non-inline nested function is referenced from an inline external + function, we cannot honor both requests at the same time without cloning + the nested function in the current unit since it is private to its unit. + We could inline it as well but it's probably better to err on the side + of too little inlining. + + This must be invoked only on nested functions present in the source code + and not on nested functions generated by the compiler, e.g. finalizers, + because they are not marked inline and we don't want them to block the + inlining of the parent function. */ + +static void +check_inlining_for_nested_subprog (tree fndecl) +{ + if (!DECL_DECLARED_INLINE_P (fndecl) + && current_function_decl + && DECL_EXTERNAL (current_function_decl) + && DECL_DECLARED_INLINE_P (current_function_decl)) + { + const location_t loc1 = DECL_SOURCE_LOCATION (fndecl); + const location_t loc2 = DECL_SOURCE_LOCATION (current_function_decl); + + if (lookup_attribute ("always_inline", + DECL_ATTRIBUTES (current_function_decl))) + { + error_at (loc1, "subprogram %q+F not marked Inline_Always", fndecl); + error_at (loc2, "parent subprogram cannot be inlined"); + } + else + { + warning_at (loc1, OPT_Winline, "subprogram %q+F not marked Inline", + fndecl); + warning_at (loc2, OPT_Winline, "parent subprogram cannot be inlined"); + } + + DECL_DECLARED_INLINE_P (current_function_decl) = 0; + DECL_UNINLINABLE (current_function_decl) = 1; + } +} + /* Return an expression for the length of TYPE, an integral type, computed in RESULT_TYPE, another integral type. @@ -1696,6 +1739,9 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) { set_expr_location_from_node (gnu_expr, gnat_node); + /* Also check the inlining status. */ + check_inlining_for_nested_subprog (TREE_OPERAND (gnu_expr, 0)); + /* Check that we're not violating the No_Implicit_Dynamic_Code restriction. Be conservative if we don't know anything about the trampoline strategy for the target. */ @@ -3729,7 +3775,12 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) gnu_subprog_language->other_ret_val = NULL; } - rest_of_subprog_body_compilation (gnu_subprog_decl); + /* If this is an inlined external function that has been marked uninlinable, + drop the body and stop there. Otherwise compile the body. */ + if (DECL_EXTERNAL (gnu_subprog_decl) && DECL_UNINLINABLE (gnu_subprog_decl)) + DECL_SAVED_TREE (gnu_subprog_decl) = NULL_TREE; + else + rest_of_subprog_body_compilation (gnu_subprog_decl); } /* Return true if GNAT_NODE requires atomic synchronization. */ @@ -3874,6 +3925,11 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, return call_expr; } + /* For a call to a nested function, check the inlining status. */ + if (TREE_CODE (gnu_subprog) == FUNCTION_DECL + && decl_function_context (gnu_subprog)) + check_inlining_for_nested_subprog (gnu_subprog); + /* The only way we can be making a call via an access type is if Name is an explicit dereference. In that case, get the list of formal args from the type the access type is pointing to. Otherwise, get the formals from the diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 39350f7..4d35060 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -3027,18 +3027,6 @@ create_subprog_decl (tree subprog_name, tree asm_name, tree subprog_type, TREE_TYPE (subprog_type)); DECL_ARGUMENTS (subprog_decl) = param_decl_list; - /* If this is a non-inline function nested inside an inlined external - function, we cannot honor both requests without cloning the nested - function in the current unit since it is private to the other unit. - We could inline the nested function as well but it's probably better - to err on the side of too little inlining. */ - if ((inline_status == is_suppressed || inline_status == is_disabled) - && !public_flag - && current_function_decl - && DECL_DECLARED_INLINE_P (current_function_decl) - && DECL_EXTERNAL (current_function_decl)) - DECL_DECLARED_INLINE_P (current_function_decl) = 0; - DECL_ARTIFICIAL (subprog_decl) = artificial_flag; DECL_EXTERNAL (subprog_decl) = extern_flag; |