From c6226a7e2aabd8d28a282bcad0b0c62767fb6a17 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 11 Jun 2002 17:31:11 +0000 Subject: [PATCH] jcf-write.c (generate_classfile): Use FIELD_SYNTHETIC. * jcf-write.c (generate_classfile): Use FIELD_SYNTHETIC. * parse-scan.y (statement_without_trailing_substatement): Added assert_statement. (assert_statement): New rule. * java-tree.h (struct lang_type) [assertions]: New field. (TYPE_USES_ASSERTIONS): New macro. (CLASS_USES_ASSERTIONS): Likewise. (FIELD_SYNTHETIC): New define. * lex.c (java_lval;): Added ASSERT_TK. * parse.y (ASSERT_TK): Added. (statement_without_trailing_substatement): Added assert_statement. (assert_statement): New rule. (build_assertion): New function. (maybe_generate_pre_expand_clinit): Create and initialize $assertionsDisabled. (lookup_package_type): Removed decl. * keyword.h: Rebuilt. * keyword.gperf (assert): New token. From-SVN: r54516 --- gcc/java/ChangeLog | 21 ++++++ gcc/java/java-tree.h | 7 ++ gcc/java/jcf-write.c | 8 ++- gcc/java/keyword.gperf | 1 + gcc/java/keyword.h | 141 +++++++++++++++++++---------------------- gcc/java/lex.c | 1 + gcc/java/parse-scan.y | 10 +++ gcc/java/parse.y | 97 +++++++++++++++++++++++++++- 8 files changed, 205 insertions(+), 81 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index c650282d3a4..3037f8cbc7d 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,24 @@ +2002-06-11 Tom Tromey + + * jcf-write.c (generate_classfile): Use FIELD_SYNTHETIC. + * parse-scan.y (statement_without_trailing_substatement): Added + assert_statement. + (assert_statement): New rule. + * java-tree.h (struct lang_type) [assertions]: New field. + (TYPE_USES_ASSERTIONS): New macro. + (CLASS_USES_ASSERTIONS): Likewise. + (FIELD_SYNTHETIC): New define. + * lex.c (java_lval;): Added ASSERT_TK. + * parse.y (ASSERT_TK): Added. + (statement_without_trailing_substatement): Added assert_statement. + (assert_statement): New rule. + (build_assertion): New function. + (maybe_generate_pre_expand_clinit): Create and initialize + $assertionsDisabled. + (lookup_package_type): Removed decl. + * keyword.h: Rebuilt. + * keyword.gperf (assert): New token. + 2002-06-10 Akim Demaille * parse.y (interface_type_list, class_member_declaration) diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 9ba52a6b10b..8a7fb9e9366 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -92,6 +92,7 @@ struct JCF; CLASS_PUBLIC (in TYPE_DECL). 2: METHOD_STATIC (in FUNCTION_DECL). (But note that FIELD_STATIC uses TREE_STATIC!) + FIELD_SYNTHETIC (in FIELD_DECL) CLASS_COMPLETE_P (in TYPE_DECL) 3: METHOD_FINAL (in FUNCTION_DECL) FIELD_FINAL (in FIELD_DECL) @@ -812,6 +813,9 @@ union lang_tree_node #define DECL_INIT_CALLS_THIS(DECL) \ (DECL_LANG_SPECIFIC(DECL)->u.f.init_calls_this) +/* True when DECL (a field) is Synthetic. */ +#define FIELD_SYNTHETIC(DECL) DECL_LANG_FLAG_2 (DECL) + /* True when DECL aliases an outer context local variable. */ #define FIELD_LOCAL_ALIAS(DECL) DECL_LANG_FLAG_6 (DECL) @@ -1037,6 +1041,7 @@ struct lang_decl GTY(()) #define TYPE_PRIVATE_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->pic) #define TYPE_PROTECTED_INNER_CLASS(T) (TYPE_LANG_SPECIFIC(T)->poic) #define TYPE_STRICTFP(T) (TYPE_LANG_SPECIFIC(T)->strictfp) +#define TYPE_USES_ASSERTIONS(T) (TYPE_LANG_SPECIFIC(T)->assertions) struct lang_type GTY(()) { @@ -1057,6 +1062,7 @@ struct lang_type GTY(()) unsigned pic:1; /* Private Inner Class. */ unsigned poic:1; /* Protected Inner Class. */ unsigned strictfp:1; /* `strictfp' class. */ + unsigned assertions:1; /* Any method uses `assert'. */ }; #define JCF_u4 unsigned long @@ -1330,6 +1336,7 @@ struct rtx_def * java_expand_expr PARAMS ((tree, rtx, enum machine_mode, #define CLASS_PRIVATE(DECL) (TYPE_PRIVATE_INNER_CLASS (TREE_TYPE (DECL))) #define CLASS_PROTECTED(DECL) (TYPE_PROTECTED_INNER_CLASS (TREE_TYPE (DECL))) #define CLASS_STRICTFP(DECL) (TYPE_STRICTFP (TREE_TYPE (DECL))) +#define CLASS_USES_ASSERTIONS(DECL) (TYPE_USES_ASSERTIONS (TREE_TYPE (DECL))) /* @deprecated marker flag on methods, fields and classes */ diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index f419e9f7ad3..dcf2397a9ec 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -2962,7 +2962,7 @@ generate_classfile (clas, state) if (have_value) attr_count++; - if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part)) + if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) || FIELD_SYNTHETIC (part)) attr_count++; PUT2 (attr_count); /* attributes_count */ @@ -2980,8 +2980,10 @@ generate_classfile (clas, state) PUT4 (2); /* attribute_length */ i = find_constant_index (init, state); PUT2 (i); } - /* Emit the "Synthetic" attribute for val$ and this$ fields. */ - if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part)) + /* Emit the "Synthetic" attribute for val$ and this$ + fields and other fields which need it. */ + if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) + || FIELD_SYNTHETIC (part)) ptr = append_synthetic_attribute (state); fields_count++; } diff --git a/gcc/java/keyword.gperf b/gcc/java/keyword.gperf index 4256ca7fe3c..1087d3b00af 100644 --- a/gcc/java/keyword.gperf +++ b/gcc/java/keyword.gperf @@ -87,3 +87,4 @@ strictfp, STRICT_TK true, TRUE_TK false, FALSE_TK null, NULL_TK +assert, ASSERT_TK diff --git a/gcc/java/keyword.h b/gcc/java/keyword.h index a2bc12dc534..24fcef56cc0 100644 --- a/gcc/java/keyword.h +++ b/gcc/java/keyword.h @@ -1,5 +1,5 @@ -/* C code produced by gperf version 2.7.2 */ -/* Command-line: gperf -L C -C -F ', 0' -p -t -j1 -i 1 -g -o -N java_keyword -k'1,4,$' keyword.gperf */ +/* C code produced by gperf version 2.7 */ +/* Command-line: gperf -L C -C -F , 0 -p -t -j1 -i 1 -g -o -N java_keyword -k1,4,$ keyword.gperf */ /* Keyword definition for the GNU compiler for the Java(TM) language. Copyright (C) 1997, 1998 Free Software Foundation, Inc. Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) @@ -35,19 +35,15 @@ __inline #endif const struct java_keyword *java_keyword PARAMS ((const char *, unsigned int)); -#define TOTAL_KEYWORDS 51 +#define TOTAL_KEYWORDS 52 #define MIN_WORD_LENGTH 2 #define MAX_WORD_LENGTH 12 #define MIN_HASH_VALUE 7 -#define MAX_HASH_VALUE 95 -/* maximum key range = 89, duplicates = 0 */ +#define MAX_HASH_VALUE 85 +/* maximum key range = 79, duplicates = 0 */ #ifdef __GNUC__ __inline -#else -#ifdef __cplusplus -inline -#endif #endif static unsigned int hash (str, len) @@ -56,32 +52,32 @@ hash (str, len) { static const unsigned char asso_values[] = { - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 9, 17, 3, - 1, 1, 20, 13, 15, 29, 96, 21, 1, 96, - 35, 39, 1, 96, 15, 6, 2, 1, 41, 17, - 96, 7, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96 + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 1, 34, 3, + 1, 1, 18, 7, 21, 28, 86, 14, 1, 86, + 18, 20, 37, 86, 15, 6, 2, 5, 40, 36, + 86, 36, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86 }; register int hval = len; @@ -109,74 +105,69 @@ java_keyword (str, len) { static const struct java_keyword wordlist[] = { - {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, - {"", 0}, + {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"else", ELSE_TK}, {"true", TRUE_TK}, {"case", CASE_TK}, + {"assert", ASSERT_TK}, + {"default", DEFAULT_TK}, {"", 0}, - {"public", PUBLIC_TK}, - {"try", TRY_TK}, - {"protected", PROTECTED_TK}, + {"abstract", ABSTRACT_TK}, {"continue", CONTINUE_TK}, {"extends", EXTENDS_TK}, {"const", CONST_TK}, {"static", STATIC_TK}, {"this", THIS_TK}, - {"default", DEFAULT_TK}, + {"long", LONG_TK}, {"class", CLASS_TK}, - {"abstract", ABSTRACT_TK}, + {"", 0}, {"synchronized", SYNCHRONIZED_TK}, - {"byte", BYTE_TK}, - {"while", WHILE_TK}, - {"double", DOUBLE_TK}, - {"catch", CATCH_TK}, + {"do", DO_TK}, + {"null", NULL_TK}, + {"final", FINAL_TK}, + {"float", FLOAT_TK}, {"super", SUPER_TK}, {"short", SHORT_TK}, - {"switch", SWITCH_TK}, - {"package", PACKAGE_TK}, - {"long", LONG_TK}, - {"false", FALSE_TK}, {"", 0}, + {"false", FALSE_TK}, + {"transient", TRANSIENT_TK}, + {"catch", CATCH_TK}, {"int", INT_TK}, - {"final", FINAL_TK}, - {"float", FLOAT_TK}, - {"char", CHAR_TK}, + {"throws", THROWS_TK}, + {"switch", SWITCH_TK}, {"for", FOR_TK}, + {"char", CHAR_TK}, {"", 0}, {"interface", INTERFACE_TK}, - {"null", NULL_TK}, - {"do", DO_TK}, - {"finally", FINALLY_TK}, - {"strictfp", STRICT_TK}, - {"", 0}, + {"byte", BYTE_TK}, + {"try", TRY_TK}, + {"double", DOUBLE_TK}, + {"while", WHILE_TK}, + {"return", RETURN_TK}, {"implements", IMPLEMENTS_TK}, {"void", VOID_TK}, - {"transient", TRANSIENT_TK}, - {"", 0}, - {"private", PRIVATE_TK}, + {"public", PUBLIC_TK}, {"if", IF_TK}, + {"protected", PROTECTED_TK}, + {"volatile", VOLATILE_TK}, + {"goto", GOTO_TK}, + {"", 0}, + {"native", NATIVE_TK}, {"break", BREAK_TK}, - {"throws", THROWS_TK}, {"", 0}, + {"import", IMPORT_TK}, {"new", NEW_TK}, - {"", 0}, - {"return", RETURN_TK}, - {"", 0}, - {"volatile", VOLATILE_TK}, - {"boolean", BOOLEAN_TK}, {"instanceof", INSTANCEOF_TK}, + {"package", PACKAGE_TK}, + {"boolean", BOOLEAN_TK}, {"", 0}, + {"finally", FINALLY_TK}, {"throw", THROW_TK}, + {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, - {"", 0}, - {"native", NATIVE_TK}, - {"", 0}, {"", 0}, {"", 0}, {"", 0}, - {"import", IMPORT_TK}, - {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, - {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, - {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, - {"goto", GOTO_TK} + {"strictfp", STRICT_TK}, + {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, + {"private", PRIVATE_TK} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) diff --git a/gcc/java/lex.c b/gcc/java/lex.c index 69e16b4bf1c..21c442b58e9 100644 --- a/gcc/java/lex.c +++ b/gcc/java/lex.c @@ -1616,6 +1616,7 @@ java_lex (java_lval) case CATCH_TK: case THROW_TK: case INSTANCEOF_TK: + case ASSERT_TK: BUILD_OPERATOR (kw->token); default: diff --git a/gcc/java/parse-scan.y b/gcc/java/parse-scan.y index 665a7f7e15f..977bbce226d 100644 --- a/gcc/java/parse-scan.y +++ b/gcc/java/parse-scan.y @@ -180,6 +180,7 @@ void report PARAMS ((void)); %token SWITCH_TK CONST_TK TRY_TK %token FOR_TK NEW_TK CONTINUE_TK %token GOTO_TK PACKAGE_TK THIS_TK +%token ASSERT_TK %token BYTE_TK SHORT_TK INT_TK LONG_TK %token CHAR_TK INTEGRAL_TK @@ -717,6 +718,7 @@ statement_without_trailing_substatement: | synchronized_statement | throw_statement | try_statement +| assert_statement ; empty_statement: @@ -870,6 +872,14 @@ throw_statement: THROW_TK expression SC_TK { ++complexity; } ; +assert_statement: + ASSERT_TK expression REL_CL_TK expression SC_TK +| ASSERT_TK expression SC_TK +| ASSERT_TK error + {yyerror ("Missing term"); RECOVER;} +| ASSERT_TK expression error + {yyerror ("';' expected"); RECOVER;} +; synchronized_statement: synchronized OP_TK expression CP_TK block | synchronized OP_TK expression CP_TK error diff --git a/gcc/java/parse.y b/gcc/java/parse.y index 864984b9122..907ca285808 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -220,6 +220,7 @@ static tree build_string_concatenation PARAMS ((tree, tree)); static tree patch_string_cst PARAMS ((tree)); static tree patch_string PARAMS ((tree)); static tree encapsulate_with_try_catch PARAMS ((int, tree, tree, tree)); +static tree build_assertion PARAMS ((int, tree, tree)); static tree build_try_statement PARAMS ((int, tree, tree)); static tree build_try_finally_statement PARAMS ((int, tree, tree)); static tree patch_try_statement PARAMS ((tree)); @@ -505,6 +506,7 @@ static GTY(()) tree src_parse_roots[1]; %token SWITCH_TK CONST_TK TRY_TK %token FOR_TK NEW_TK CONTINUE_TK %token GOTO_TK PACKAGE_TK THIS_TK +%token ASSERT_TK %token BYTE_TK SHORT_TK INT_TK LONG_TK %token CHAR_TK INTEGRAL_TK @@ -571,12 +573,13 @@ static GTY(()) tree src_parse_roots[1]; left_hand_side assignment for_header for_begin constant_expression do_statement_begin empty_statement switch_statement synchronized_statement throw_statement - try_statement switch_expression switch_block + try_statement assert_statement + switch_expression switch_block catches catch_clause catch_clause_parameter finally anonymous_class_creation trap_overflow_corner_case %type return_statement break_statement continue_statement -%type ASSIGN_TK MULT_ASSIGN_TK DIV_ASSIGN_TK +%type ASSIGN_TK MULT_ASSIGN_TK DIV_ASSIGN_TK %type REM_ASSIGN_TK PLUS_ASSIGN_TK MINUS_ASSIGN_TK %type LS_ASSIGN_TK SRS_ASSIGN_TK ZRS_ASSIGN_TK %type AND_ASSIGN_TK XOR_ASSIGN_TK OR_ASSIGN_TK @@ -588,7 +591,7 @@ static GTY(()) tree src_parse_roots[1]; %token OP_TK OSB_TK DOT_TK THROW_TK INSTANCEOF_TK %type THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK %type CASE_TK DEFAULT_TK TRY_TK CATCH_TK SYNCHRONIZED_TK -%type NEW_TK +%type NEW_TK ASSERT_TK %type method_body @@ -1460,6 +1463,7 @@ statement_without_trailing_substatement: | synchronized_statement | throw_statement | try_statement +| assert_statement ; empty_statement: @@ -1845,6 +1849,21 @@ throw_statement: {yyerror ("';' expected"); RECOVER;} ; +assert_statement: + ASSERT_TK expression REL_CL_TK expression SC_TK + { + $$ = build_assertion ($1.location, $2, $4); + } +| ASSERT_TK expression SC_TK + { + $$ = build_assertion ($1.location, $2, NULL_TREE); + } +| ASSERT_TK error + {yyerror ("Missing term"); RECOVER;} +| ASSERT_TK expression error + {yyerror ("';' expected"); RECOVER;} +; + synchronized_statement: synchronized OP_TK expression CP_TK block { @@ -15292,6 +15311,78 @@ patch_switch_statement (node) return node; } +/* Assertions. */ + +/* Build an assertion expression for `assert CONDITION : VALUE'; VALUE + might be NULL_TREE. */ +static tree +build_assertion (location, condition, value) + int location; + tree condition, value; +{ + tree node; + tree klass = GET_CPC (); + + if (! CLASS_USES_ASSERTIONS (klass)) + { + tree field, classdollar, id, call; + tree class_type = TREE_TYPE (klass); + + field = add_field (class_type, + get_identifier ("$assertionsDisabled"), + boolean_type_node, + ACC_PRIVATE | ACC_STATIC | ACC_FINAL); + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (field); + FIELD_SYNTHETIC (field) = 1; + + if (!TYPE_DOT_CLASS (class_type)) + build_dot_class_method (class_type); + classdollar = build_dot_class_method_invocation (class_type); + + /* Call CLASS.desiredAssertionStatus(). */ + id = build_wfl_node (get_identifier ("desiredAssertionStatus")); + call = build (CALL_EXPR, NULL_TREE, id, NULL_TREE, NULL_TREE); + call = make_qualified_primary (classdollar, call, location); + TREE_SIDE_EFFECTS (call) = 1; + DECL_INITIAL (field) = call; + + /* Record the initializer in the initializer statement list. */ + call = build (MODIFY_EXPR, NULL_TREE, field, call); + TREE_CHAIN (call) = CPC_STATIC_INITIALIZER_STMT (ctxp); + SET_CPC_STATIC_INITIALIZER_STMT (ctxp, call); + MODIFY_EXPR_FROM_INITIALIZATION_P (call) = 1; + + CLASS_USES_ASSERTIONS (klass) = 1; + } + + if (value != NULL_TREE) + value = tree_cons (NULL_TREE, value, NULL_TREE); + + node = build_wfl_node (get_identifier ("java")); + node = make_qualified_name (node, build_wfl_node (get_identifier ("lang")), + location); + node = make_qualified_name (node, build_wfl_node (get_identifier ("AssertionError")), + location); + + node = build (NEW_CLASS_EXPR, NULL_TREE, node, value, NULL_TREE); + TREE_SIDE_EFFECTS (node) = 1; + /* It is too early to use BUILD_THROW. */ + node = build1 (THROW_EXPR, NULL_TREE, node); + TREE_SIDE_EFFECTS (node) = 1; + + /* We invert the condition; if we just put NODE as the `else' part + then we generate weird-looking bytecode. */ + condition = build1 (TRUTH_NOT_EXPR, NULL_TREE, condition); + /* Check $assertionsDisabled. */ + condition + = build (TRUTH_ANDIF_EXPR, NULL_TREE, + build1 (TRUTH_NOT_EXPR, NULL_TREE, + build_wfl_node (get_identifier ("$assertionsDisabled"))), + condition); + node = build_if_else_statement (location, condition, node, NULL_TREE); + return node; +} + /* 14.18 The try/catch statements */ /* Encapsulate TRY_STMTS' in a try catch sequence. The catch clause -- 2.30.2