Example #1
0
        public override void add_simple_check(CodeNode node, bool always_fails = false)
        {
            current_method_inner_error = true;

            var inner_error = get_variable_cexpression("_inner_error_");

            if (always_fails)
            {
                // inner_error is always set, avoid unnecessary if statement
                // eliminates C warnings
            }
            else
            {
                var ccond    = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, inner_error, new CCodeConstant("NULL"));
                var unlikely = new CCodeFunctionCall(new CCodeIdentifier("G_UNLIKELY"));
                unlikely.add_argument(ccond);
                ccode.open_if(unlikely);
            }

            if (current_try != null)
            {
                // surrounding try found

                // free local variables
                if (is_in_catch)
                {
                    append_local_free(current_symbol, false, current_catch);
                }
                else
                {
                    append_local_free(current_symbol, false, current_try);
                }

                var error_types = new List <DataType>();
                foreach (DataType node_error_type in node.get_error_types())
                {
                    error_types.Add(node_error_type);
                }

                bool has_general_catch_clause = false;

                if (!is_in_catch)
                {
                    var handled_error_types = new List <DataType>();
                    foreach (CatchClause clause in current_try.get_catch_clauses())
                    {
                        // keep track of unhandled error types
                        foreach (DataType node_error_type in error_types)
                        {
                            if (clause.error_type == null || node_error_type.compatible(clause.error_type))
                            {
                                handled_error_types.Add(node_error_type);
                            }
                        }
                        foreach (DataType handled_error_type in handled_error_types)
                        {
                            error_types.Remove(handled_error_type);
                        }
                        handled_error_types.Clear();

                        if (clause.error_type.equals(gerror_type))
                        {
                            // general catch clause, this should be the last one
                            has_general_catch_clause = true;
                            ccode.add_goto(clause.clabel_name);
                            break;
                        }
                        else
                        {
                            var catch_type = clause.error_type as ErrorType;

                            if (catch_type.error_code != null)
                            {
                                /* catch clause specifies a specific error code */
                                var error_match = new CCodeFunctionCall(new CCodeIdentifier("g_error_matches"));
                                error_match.add_argument(inner_error);
                                error_match.add_argument(new CCodeIdentifier(get_ccode_upper_case_name(catch_type.data_type)));
                                error_match.add_argument(new CCodeIdentifier(get_ccode_name(catch_type.error_code)));

                                ccode.open_if(error_match);
                            }
                            else
                            {
                                /* catch clause specifies a full error domain */
                                var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY,
                                                                      CCodeMemberAccess.pointer(inner_error, "domain"), new CCodeIdentifier
                                                                          (get_ccode_upper_case_name(clause.error_type.data_type)));

                                ccode.open_if(ccond);
                            }

                            // go to catch clause if error domain matches
                            ccode.add_goto(clause.clabel_name);
                            ccode.close();
                        }
                    }
                }

                if (has_general_catch_clause)
                {
                    // every possible error is already caught
                    // as there is a general catch clause
                    // no need to do anything else
                }
                else if (error_types.Count > 0)
                {
                    // go to finally clause if no catch clause matches
                    // and there are still unhandled error types
                    ccode.add_goto("__finally%d".printf(current_try_id));
                }
                else if (in_finally_block(node))
                {
                    // do not check unexpected errors happening within finally blocks
                    // as jump out of finally block is not supported
                }
                else
                {
                    // should never happen with correct bindings
                    uncaught_error_statement(inner_error, true);
                }
            }
            else if (current_method != null && current_method.get_error_types().Count > 0)
            {
                // current method can fail, propagate error
                CCodeBinaryExpression ccond = null;

                foreach (DataType error_type in current_method.get_error_types())
                {
                    // If GLib.Error is allowed we propagate everything
                    if (error_type.equals(gerror_type))
                    {
                        ccond = null;
                        break;
                    }

                    // Check the allowed error domains to propagate
                    var domain_check = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, CCodeMemberAccess.pointer
                                                                     (inner_error, "domain"), new CCodeIdentifier(get_ccode_upper_case_name(error_type.data_type)));
                    if (ccond == null)
                    {
                        ccond = domain_check;
                    }
                    else
                    {
                        ccond = new CCodeBinaryExpression(CCodeBinaryOperator.OR, ccond, domain_check);
                    }
                }

                if (ccond != null)
                {
                    ccode.open_if(ccond);
                    return_with_exception(inner_error);

                    ccode.add_else();
                    uncaught_error_statement(inner_error);
                    ccode.close();
                }
                else
                {
                    return_with_exception(inner_error);
                }
            }
            else
            {
                uncaught_error_statement(inner_error);
            }

            if (!always_fails)
            {
                ccode.close();
            }
        }
Example #2
0
        private void handle_errors(CodeNode node, bool always_fail = false)
        {
            if (node.tree_can_fail)
            {
                var last_block = current_block;

                // exceptional control flow
                foreach (DataType error_data_type in node.get_error_types())
                {
                    var error_type = error_data_type as ErrorType;
                    current_block        = last_block;
                    unreachable_reported = true;

                    for (int i = jump_stack.Count - 1; i >= 0; i--)
                    {
                        var jump_target = jump_stack[i];
                        if (jump_target.is_exit_target)
                        {
                            current_block.connect(jump_target.basic_block);
                            mark_unreachable();
                            break;
                        }
                        else if (jump_target.is_error_target)
                        {
                            if (jump_target.error_domain == null ||
                                (jump_target.error_domain == error_type.error_domain &&
                                 (jump_target.error_code == null ||
                                  jump_target.error_code == error_type.error_code)))
                            {
                                // error can always be caught by this catch clause
                                // following catch clauses cannot be reached by this error
                                current_block.connect(jump_target.basic_block);
                                mark_unreachable();
                                break;
                            }
                            else if (error_type.error_domain == null ||
                                     (error_type.error_domain == jump_target.error_domain &&
                                      (error_type.error_code == null ||
                                       error_type.error_code == jump_target.error_code)))
                            {
                                // error might be caught by this catch clause
                                // unknown at compile time
                                // following catch clauses might still be reached by this error
                                current_block.connect(jump_target.basic_block);
                            }
                        }
                        else if (jump_target.is_finally_clause)
                        {
                            current_block.connect(jump_target.basic_block);
                            current_block = jump_target.last_block;
                        }
                    }
                }

                // normal control flow
                if (!always_fail)
                {
                    current_block = new BasicBlock();
                    last_block.connect(current_block);
                }
            }
        }