From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14602 invoked by alias); 19 Oct 2011 11:36:14 -0000 Received: (qmail 13786 invoked by uid 22791); 19 Oct 2011 11:36:06 -0000 X-SWARE-Spam-Status: No, hits=3.2 required=5.0 tests=AWL,BAYES_50,FAKE_REPLY_C,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,MSGID_FROM_MTA_HEADER,RCVD_IN_DNSWL_NONE,TW_BJ,TW_CX,TW_FP,TW_JC,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from blu0-omc3-s2.blu0.hotmail.com (HELO blu0-omc3-s2.blu0.hotmail.com) (65.55.116.77) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 19 Oct 2011 11:35:18 +0000 Received: from BLU0-SMTP143 ([65.55.116.74]) by blu0-omc3-s2.blu0.hotmail.com with Microsoft SMTPSVC(6.0.3790.4675); Wed, 19 Oct 2011 04:35:17 -0700 Message-ID: Received: from andyg ([84.178.59.250]) by BLU0-SMTP143.phx.gbl over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Wed, 19 Oct 2011 04:35:15 -0700 Date: Wed, 19 Oct 2011 12:26:00 -0000 From: Andy Gibbs To: gcc-patches@gcc.gnu.org CC: paolo.carlini@oracle.com, iant@google.com Subject: Re: [C++ Patch] __builtin_choose_expr MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-10/txt/msg01716.txt.bz2 Andy Gibbs wrote on 18th October 2011 at 1:36 PM: > Paolo Carlini wrote on 18th October 2011 at 12:00 PM: >> I'm under the impression that some tests are written in C, wouldn't better >> fit in c-c++-common? > > Ok, I can do this but I think only 2 out of the 8 tests can be moved > across. I will then move the duplicates out of the gcc.dg folder too. Actually, I managed to get 3 common tests moved out of gcc.dg (pre-existing) and g++.dg/ext (from my original patch) into c-c++-common. > I will post a replacement patch later this afternoon. And here it is... Is it now ready to be committed to trunk? Regards, Andy ===== Changelog: 2011-10-19 Andy Gibbs * c-family/c-common.c: Enable __builtin_choose_expr * cp/cp-tree.def: Add tree node for handling __builtin_choose_expr within a template scenario * cp/cp-tree.h: Ditto * cp/cp-objcp-common.c: Ditto * cp/decl.c: Ditto * cp/parser.c (cp_parser_skip_to_closing_parenthesis): Remove the unnecessary requirement for 'recovering' flag to be set when 'or_comma' flag is set * cp/parser.c (cp_parser_skip_to_end_of_parameter): New function * cp/parser.c (cp_parser_builtin_choose_expr): New function * cp/parser.c (cp_parser_primary_expression): Use it * cp/semantics.c (potential_constant_expression_1): Mark the use of __builtin_choose_expr as a potentially constant expression * cp/semantics.c (evaluate_builtin_choose_expr_condition): New function * cp/semantics.c (finish_builtin_choose_expr): New function * cp/pt.c (tsubst_copy_and_build): Use it * cp/cxx-pretty-print.h: New function pp_cxx_choose_expression * cp/cxx-pretty-print.c: Document, define and use it * cp/error.c: Use it * doc/extend.text: Update docs * testsuite/gcc.dg/builtin-choose-expr.c: Moved... * testsuite/c-c++-common/builtin-choose-expr.c: ...to here * testsuite/gcc.dg/builtin-choose-expr-2.c: Moved... * testsuite/c-c++-common/builtin-choose-expr-2.c: ...to here * testsuite/gcc.dg/Wunused-var-2.c: Moved... * testsuite/c-c++-common/Wunused-var-15.c: ...to here * testsuite/g++.dg/ext/builtin-choose-expr1.C: New test * testsuite/g++.dg/ext/builtin-choose-expr2.C: New test * testsuite/g++.dg/ext/builtin-choose-expr3.C: New test * testsuite/g++.dg/ext/builtin-choose-expr4.C: New test * testsuite/g++.dg/ext/builtin-choose-expr5.C: New test --- gcc-4.7.0-r180072/gcc/c-family/c-common.c +++ gcc-4.7.0-patched/gcc/c-family/c-common.c @@ -423,7 +423,7 @@ const struct c_common_resword c_common_r { "__asm__", RID_ASM, 0 }, { "__attribute", RID_ATTRIBUTE, 0 }, { "__attribute__", RID_ATTRIBUTE, 0 }, - { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, + { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 }, { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY }, { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, D_CONLY }, { "__builtin_offsetof", RID_OFFSETOF, 0 }, --- gcc-4.7.0-r180072/gcc/cp/cp-objcp-common.c +++ gcc-4.7.0-patched/gcc/cp/cp-objcp-common.c @@ -100,6 +100,8 @@ cp_tree_size (enum tree_code code) case TEMPLATE_INFO: return sizeof (struct tree_template_info); + case CHOOSE_EXPR: return sizeof (struct tree_choose_expr); + default: gcc_unreachable (); } @@ -301,6 +303,7 @@ cp_common_init_ts (void) MARK_TS_TYPED (USING_STMT); MARK_TS_TYPED (LAMBDA_EXPR); MARK_TS_TYPED (CTOR_INITIALIZER); + MARK_TS_TYPED (CHOOSE_EXPR); } #include "gt-cp-cp-objcp-common.h" --- gcc-4.7.0-r180072/gcc/cp/cp-tree.def +++ gcc-4.7.0-patched/gcc/cp/cp-tree.def @@ -332,6 +332,9 @@ DEFTREECODE (TAG_DEFN, "tag_defn", tcc_e /* Represents an 'offsetof' expression during template expansion. */ DEFTREECODE (OFFSETOF_EXPR, "offsetof_expr", tcc_expression, 1) +/* Represents an '__builtin_choose_expr' expression during template expansion. */ +DEFTREECODE (CHOOSE_EXPR, "choose_expr", tcc_exceptional, 0) + /* Represents a 'sizeof' expression during template expansion. */ DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1) --- gcc-4.7.0-r180072/gcc/cp/cp-tree.h +++ gcc-4.7.0-patched/gcc/cp/cp-tree.h @@ -532,6 +532,33 @@ struct GTY (()) tree_deferred_noexcept { }; +/* The condition associated with __builtin_choose_expr. This must be + an integral constant expression. */ +#define CHOOSE_EXPR_CONDITION(NODE) \ + (((struct tree_choose_expr *)CHOOSE_EXPR_CHECK (NODE))->condition) + +/* The expression to be used when condition in __builtin_choose_expr + is true*/ +#define CHOOSE_EXPR_TRUE(NODE) \ + (((struct tree_choose_expr *)CHOOSE_EXPR_CHECK (NODE))->expr_true) + +/* The expression to be used when condition in __builtin_choose_expr + is false*/ +#define CHOOSE_EXPR_FALSE(NODE) \ + (((struct tree_choose_expr *)CHOOSE_EXPR_CHECK (NODE))->expr_false) + +/* Source location information for __builtin_choose_expr. */ +#define CHOOSE_EXPR_SOURCE_LOCATION(NODE) \ + (((struct tree_choose_expr *)CHOOSE_EXPR_CHECK (NODE))->location) + +struct GTY (()) tree_choose_expr { + struct tree_common common; + tree condition; + tree expr_true; + tree expr_false; + location_t location; +}; + /* The condition associated with the static assertion. This must be an integral constant expression. */ #define STATIC_ASSERT_CONDITION(NODE) \ @@ -738,6 +765,7 @@ enum cp_tree_node_structure_enum { TS_CP_TRAIT_EXPR, TS_CP_LAMBDA_EXPR, TS_CP_TEMPLATE_INFO, + TS_CP_CHOOSE_EXPR, LAST_TS_CP_ENUM }; @@ -763,6 +791,7 @@ union GTY((desc ("cp_tree_node_structure lambda_expression; struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO"))) template_info; + struct tree_choose_expr GTY ((tag ("TS_CP_CHOOSE_EXPR"))) choose_expr; }; @@ -5463,6 +5492,8 @@ extern tree finish_id_expression (tree, extern tree finish_typeof (tree); extern tree finish_underlying_type (tree); extern tree finish_offsetof (tree); +extern bool evaluate_builtin_choose_expr_condition (tree, location_t, bool *); +extern tree finish_builtin_choose_expr (tree, tree, tree, location_t); extern void finish_decl_cleanup (tree, tree); extern void finish_eh_cleanup (tree); extern void emit_associated_thunks (tree); --- gcc-4.7.0-r180072/gcc/cp/cxx-pretty-print.c +++ gcc-4.7.0-patched/gcc/cp/cxx-pretty-print.c @@ -379,6 +379,7 @@ pp_cxx_id_expression (cxx_pretty_printer GNU Extensions: __builtin_va_arg ( assignment-expression , type-id ) __builtin_offsetof ( type-id, offsetof-expression ) + __builtin_choose_expr ( constant-expression , assignment-expression , assignment-expression ) __has_nothrow_assign ( type-id ) __has_nothrow_constructor ( type-id ) @@ -450,6 +451,10 @@ pp_cxx_primary_expression (cxx_pretty_pr pp_cxx_offsetof_expression (pp, t); break; + case CHOOSE_EXPR: + pp_cxx_choose_expression (pp, t); + break; + default: pp_c_primary_expression (pp_c_base (pp), t); break; @@ -2312,6 +2317,19 @@ pp_cxx_offsetof_expression (cxx_pretty_p pp_cxx_right_paren (pp); } +void +pp_cxx_choose_expression (cxx_pretty_printer *pp, tree t) +{ + pp_cxx_ws_string (pp, "__builtin_choose_expr"); + pp_cxx_left_paren (pp); + pp_cxx_expression (pp, CHOOSE_EXPR_CONDITION (t)); + pp_cxx_separate_with (pp, ','); + pp_cxx_expression (pp, CHOOSE_EXPR_TRUE (t)); + pp_cxx_separate_with (pp, ','); + pp_cxx_expression (pp, CHOOSE_EXPR_FALSE (t)); + pp_cxx_right_paren (pp); +} + void pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) { --- gcc-4.7.0-r180072/gcc/cp/cxx-pretty-print.h +++ gcc-4.7.0-patched/gcc/cp/cxx-pretty-print.h @@ -74,5 +74,6 @@ void pp_cxx_canonical_template_parameter void pp_cxx_trait_expression (cxx_pretty_printer *, tree); void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree); void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree); +void pp_cxx_choose_expression (cxx_pretty_printer *, tree); #endif /* GCC_CXX_PRETTY_PRINT_H */ --- gcc-4.7.0-r180072/gcc/cp/decl.c +++ gcc-4.7.0-patched/gcc/cp/decl.c @@ -13749,6 +13749,7 @@ cp_tree_node_structure (union lang_tree_ case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; + case CHOOSE_EXPR: return TS_CP_CHOOSE_EXPR; default: return TS_CP_GENERIC; } } --- gcc-4.7.0-r180072/gcc/cp/error.c +++ gcc-4.7.0-patched/gcc/cp/error.c @@ -2368,6 +2368,10 @@ dump_expr (tree t, int flags) pp_cxx_offsetof_expression (cxx_pp, t); break; + case CHOOSE_EXPR: + pp_cxx_choose_expression (cxx_pp, t); + break; + case SCOPE_REF: dump_decl (t, flags); break; --- gcc-4.7.0-r180072/gcc/cp/parser.c +++ gcc-4.7.0-patched/gcc/cp/parser.c @@ -1595,6 +1595,8 @@ static tree cp_parser_expression (cp_parser *, bool, cp_id_kind *); static tree cp_parser_constant_expression (cp_parser *, bool, bool *); +static tree cp_parser_builtin_choose_expr + (cp_parser *); static tree cp_parser_builtin_offsetof (cp_parser *); static tree cp_parser_lambda_expression @@ -2023,6 +2025,8 @@ static bool cp_parser_parse_and_diagnose (cp_parser *); static int cp_parser_skip_to_closing_parenthesis (cp_parser *, bool, bool, bool); +static bool cp_parser_skip_to_end_of_parameter + (cp_parser *); static void cp_parser_skip_to_end_of_statement (cp_parser *); static void cp_parser_consume_semicolon_at_end_of_statement @@ -2678,7 +2682,7 @@ cp_parser_skip_to_closing_parenthesis (c break; case CPP_COMMA: - if (recovering && or_comma && !brace_depth && !paren_depth + if (or_comma && !brace_depth && !paren_depth && !square_depth) return -1; break; @@ -2706,6 +2710,18 @@ cp_parser_skip_to_closing_parenthesis (c } } +/* Consume tokens until we reach the end of the current parameter, + which will be just before consuming a `)' or a `,'. Will abort + if a non-nested `}', `]' or `;' is reached or we run out of + tokens. Returns true on success, false otherwise. */ + +static bool +cp_parser_skip_to_end_of_parameter (cp_parser* parser) +{ + return (cp_parser_skip_to_closing_parenthesis (parser, + false, true, false) != 0); +} + /* Consume tokens until we reach the end of the current statement. Normally, that will be just before consuming a `;'. However, if a non-nested `}' comes first, then we stop before consuming that. */ @@ -3287,6 +3303,7 @@ cp_parser_translation_unit (cp_parser* p ( compound-statement ) __builtin_va_arg ( assignment-expression , type-id ) __builtin_offsetof ( type-id , offsetof-expression ) + __builtin_choose_expr ( constant-expression , assignment-expression , assignment-expression ) C++ Extensions: __has_nothrow_assign ( type-id ) @@ -3619,6 +3636,9 @@ cp_parser_primary_expression (cp_parser case RID_OFFSETOF: return cp_parser_builtin_offsetof (parser); + case RID_CHOOSE_EXPR: + return cp_parser_builtin_choose_expr (parser); + case RID_HAS_NOTHROW_ASSIGN: case RID_HAS_NOTHROW_CONSTRUCTOR: case RID_HAS_NOTHROW_COPY: @@ -7223,6 +7243,84 @@ cp_parser_builtin_offsetof (cp_parser *p return expr; } + +/* Parse __builtin_choose_expr. + + __builtin_choose_expr ( constant-expression , + assignment-expression , + assignment-expression ) */ + +static tree +cp_parser_builtin_choose_expr (cp_parser *parser) +{ + tree expr, condition; + + /* Peek at the "__builtin_choose_expr" token so we can + keep track of exactly where it started. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t saved_loc = token->location; + + /* Consume the "__builtin_choose_expr" token. */ + cp_lexer_consume_token (parser->lexer); + + /* Parse expressions. */ + cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + condition = cp_parser_constant_expression (parser, false, NULL); + cp_parser_require (parser, CPP_COMMA, RT_COMMA); + + if (processing_template_decl && + (type_dependent_expression_p (condition) || + value_dependent_expression_p (condition))) + { + /* We're in a template and can't evaluate direcly; build a + CHOOSE_EXPR node instead. In doing so, we lose some + flexibility since both expressions are parsed and may + generate errors. */ + tree expr_true, expr_false; + + expr_true = cp_parser_assignment_expression (parser, false, NULL); + cp_parser_require (parser, CPP_COMMA, RT_COMMA); + expr_false = cp_parser_assignment_expression (parser, false, NULL); + + expr = make_node (CHOOSE_EXPR); + CHOOSE_EXPR_CONDITION (expr) = condition; + CHOOSE_EXPR_TRUE (expr) = expr_true; + CHOOSE_EXPR_FALSE (expr) = expr_false; + CHOOSE_EXPR_SOURCE_LOCATION (expr) = saved_loc; + } + else + { + /* We can evaluate directly which enables us the flexibility of + only parsing the expression to be evaluated. */ + bool error = false; + bool cond_eval = evaluate_builtin_choose_expr_condition (condition, + saved_loc, &error); + if (error) + { + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + return error_mark_node; + } + + if (cond_eval) + { + expr = cp_parser_assignment_expression (parser, false, NULL); + cp_parser_require (parser, CPP_COMMA, RT_COMMA); + cp_parser_skip_to_end_of_parameter (parser); + } + else + { + cp_parser_skip_to_end_of_parameter (parser); + cp_parser_require (parser, CPP_COMMA, RT_COMMA); + expr = cp_parser_assignment_expression (parser, false, NULL); + } + } + + /* Reach end of expression */ + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + + return expr; +} /* Parse a trait expression. --- gcc-4.7.0-r180072/gcc/cp/pt.c +++ gcc-4.7.0-patched/gcc/cp/pt.c @@ -13901,6 +13901,20 @@ tsubst_copy_and_build (tree t, case OFFSETOF_EXPR: return finish_offsetof (RECUR (TREE_OPERAND (t, 0))); + case CHOOSE_EXPR: + { + tree condition = + tsubst_expr (CHOOSE_EXPR_CONDITION (t), args, complain, in_decl, + /*integral_constant_expression_p=*/true); + tree expr_true = + tsubst_expr (CHOOSE_EXPR_TRUE (t), args, complain, in_decl, false); + tree expr_false = + tsubst_expr (CHOOSE_EXPR_FALSE (t), args, complain, in_decl, false); + + return finish_builtin_choose_expr (condition, expr_true, expr_false, + CHOOSE_EXPR_SOURCE_LOCATION (t)); + } + case TRAIT_EXPR: { tree type1 = tsubst_copy (TRAIT_EXPR_TYPE1 (t), args, --- gcc-4.7.0-r180072/gcc/cp/semantics.c +++ gcc-4.7.0-patched/gcc/cp/semantics.c @@ -3427,6 +3427,43 @@ finish_offsetof (tree expr) return fold_offsetof (expr, NULL_TREE); } +/* Evaluate the condition clause of __builtin_choose_expr. */ + +bool +evaluate_builtin_choose_expr_condition (tree condition, location_t location, bool *error_p) +{ + location_t saved_loc = input_location; + + /* Fold the condition expression and convert it to a boolean value. */ + condition = fold_non_dependent_expr (condition); + condition = cp_convert (boolean_type_node, condition); + condition = maybe_constant_value (condition); + + if (TREE_CODE (condition) == INTEGER_CST) + { + if (error_p) *error_p = false; + return !integer_zerop (condition); + } + + input_location = location; + error ("first argument to %<__builtin_choose_expr%> not a constant"); + cxx_constant_value (condition); + input_location = saved_loc; + if (error_p) *error_p = true; + return false; +} + +/* Finish __builtin_choose_expr. */ + +tree +finish_builtin_choose_expr (tree condition, tree expr_true, tree expr_false, + location_t location) +{ + bool error = false; + bool result = evaluate_builtin_choose_expr_condition (condition, location, &error); + return error ? error_mark_node : (result ? expr_true : expr_false); +} + /* Replace the AGGR_INIT_EXPR at *TP with an equivalent CALL_EXPR. This function is broken out from the above for the benefit of the tree-ssa project. */ @@ -7717,6 +7754,7 @@ potential_constant_expression_1 (tree t, case SIZEOF_EXPR: case ALIGNOF_EXPR: case OFFSETOF_EXPR: + case CHOOSE_EXPR: case NOEXCEPT_EXPR: case TEMPLATE_PARM_INDEX: case TRAIT_EXPR: --- gcc-4.7.0-r180072/gcc/doc/extend.texi +++ gcc-4.7.0-patched/gcc/doc/extend.texi @@ -7544,10 +7544,9 @@ Example: (void)0)) @end smallexample -@emph{Note:} This construct is only available for C@. Furthermore, the -unused expression (@var{exp1} or @var{exp2} depending on the value of -@var{const_exp}) may still generate syntax errors. This may change in -future revisions. +@emph{Note:} The unused expression (@var{exp1} or @var{exp2} depending +on the value of @var{const_exp}) may still generate syntax errors. +This may change in future revisions. @end deftypefn --- gcc-4.7.0-r180072/gcc/testsuite/gcc.dg/builtin-choose-expr.c +++ /dev/null @@ -1,90 +0,0 @@ -/* { dg-do run } */ -/* { dg-options "-O1 -Wall" } */ - -#define choose __builtin_choose_expr - -/* Check the type of __builtin_choose_expr between E1 and E2, both - ways round and with both 0 and 1 as the condition. */ -#define ASSERT_COND_TYPE(E1, E2) \ - do { \ - typedef __typeof(E1) T1; \ - typedef __typeof(E2) T2; \ - typedef T1 **T1pp; \ - typedef T2 **T2pp; \ - typedef __typeof(choose (1, (E1), (E2))) T1a; \ - typedef __typeof(choose (0, (E2), (E1))) T1b; \ - typedef __typeof(choose (1, (E2), (E1))) T2a; \ - typedef __typeof(choose (0, (E1), (E2))) T2b; \ - typedef T1a **T1app; \ - typedef T1b **T1bpp; \ - typedef T2a **T2app; \ - typedef T2b **T2bpp; \ - T1pp t1 = 0; \ - T2pp t2 = 0; \ - T1app t1a = 0; \ - T1bpp t1b = 0; \ - T2app t2a = 0; \ - T2bpp t2b = 0; \ - t1 = t1a; \ - t1 = t1b; \ - t2 = t2a; \ - t2 = t2b; \ - (void) t1; \ - (void) t2; \ - } while (0) - - -extern void abort (); -extern void exit (); - -void bad () -{ - abort (); -} - -void good () -{ - exit (0); -} - -int main (void) -{ - signed char sc1, sc2; - void *v1; - int i, j; - double dd; - float f; - typedef void (*fpt)(void); - fpt triple; - struct S { int x, y; } pour, some, sugar; - union u { int p; } united, nations; - - if (__builtin_choose_expr (0, 12, 0) - || !__builtin_choose_expr (45, 5, 0) - || !__builtin_choose_expr (45, 3, 0)) - abort (); - - ASSERT_COND_TYPE (sc1, sc2); - ASSERT_COND_TYPE (v1, sc1); - ASSERT_COND_TYPE (i, j); - ASSERT_COND_TYPE (dd, main); - ASSERT_COND_TYPE ((float)dd, i); - ASSERT_COND_TYPE (4, f); - ASSERT_COND_TYPE (triple, some); - ASSERT_COND_TYPE (united, nations); - ASSERT_COND_TYPE (nations, main); - - pour.y = 69; - __builtin_choose_expr (0, bad (), sugar) = pour; - if (sugar.y != 69) - abort (); - - __builtin_choose_expr (sizeof (int), f, bad ()) = 3.5F; - - if (f != 3.5F) - abort (); - - __builtin_choose_expr (1, good, bad)(); - - exit (0); -} --- gcc-4.7.0-r180072/gcc/testsuite/gcc.dg/builtin-choose-expr-2.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Test diagnostic for invalid use of __builtin_choose_expr. */ -/* Origin: Joseph Myers */ -/* { dg-do compile } */ -/* { dg-options "" } */ - -int a, b, c, d; - -void -f (void) -{ - a = __builtin_choose_expr (b, c, d); /* { dg-error "first argument to '__builtin_choose_expr' not a constant" } */ -} --- gcc-4.7.0-r180072/gcc/testsuite/gcc.dg/Wunused-var-2.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-Wunused" } */ - -int -f1 (void) -{ - int a; - int b; - int c; - int d; - int e; - a = 1; - b = 2; - c = 3; - d = 4; - e = 5; - return sizeof (a) + ((__typeof (b)) 1) + __alignof__ (c) - + __builtin_choose_expr (1, d, e); -} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/c-c++-common/builtin-choose-expr.c @@ -0,0 +1,100 @@ +/* Test for valid use of __builtin_choose_expr. */ +/* { dg-do run } */ +/* { dg-options "-O1 -Wall" } */ + +#define choose __builtin_choose_expr + +/* Check the type of __builtin_choose_expr between E1 and E2, both + ways round and with both 0 and 1 as the condition. */ +#define ASSERT_COND_TYPE(E1, E2) \ + do { \ + typedef __typeof(E1) T1; \ + typedef __typeof(E2) T2; \ + typedef T1 **T1pp; \ + typedef T2 **T2pp; \ + typedef __typeof(choose (1, (E1), (E2))) T1a; \ + typedef __typeof(choose (0, (E2), (E1))) T1b; \ + typedef __typeof(choose (1, (E2), (E1))) T2a; \ + typedef __typeof(choose (0, (E1), (E2))) T2b; \ + typedef T1a **T1app; \ + typedef T1b **T1bpp; \ + typedef T2a **T2app; \ + typedef T2b **T2bpp; \ + T1pp t1 = 0; \ + T2pp t2 = 0; \ + T1app t1a = 0; \ + T1bpp t1b = 0; \ + T2app t2a = 0; \ + T2bpp t2b = 0; \ + t1 = t1a; \ + t1 = t1b; \ + t2 = t2a; \ + t2 = t2b; \ + (void) t1; \ + (void) t2; \ + } while (0) + +#ifdef __cplusplus +extern "C" { +#endif +void abort (); +void exit (int); +#ifdef __cplusplus +} +#endif + +int bad () +{ + return 0; +} + +int good () +{ + return 1; +} + +int main (void) +{ + signed char sc1, sc2; + void *v1; + int i, j; + double dd; + float f; + typedef void (*fpt)(void); + fpt triple; + struct S { int x, y; } pour, some, sugar; + union u { int p; } united, nations; + + if (__builtin_choose_expr (0, 12, 0) + || !__builtin_choose_expr (45, 5, 0) + || !__builtin_choose_expr (45, 3, 0)) + abort (); + + ASSERT_COND_TYPE (sc1, sc2); + ASSERT_COND_TYPE (v1, sc1); + ASSERT_COND_TYPE (i, j); + ASSERT_COND_TYPE (dd, main); + ASSERT_COND_TYPE ((float)dd, i); + ASSERT_COND_TYPE (4, f); + ASSERT_COND_TYPE (triple, some); + ASSERT_COND_TYPE (united, nations); + ASSERT_COND_TYPE (nations, main); + + pour.y = 69; + __builtin_choose_expr (0, bad (), sugar) = pour; + if (sugar.y != 69) + abort (); + + __builtin_choose_expr (sizeof (int), f, bad ()) = 3.5F; + + if (f != 3.5F) + abort (); + + if (!__builtin_choose_expr (1, good, bad)()) + abort (); + + if (!__builtin_choose_expr (0, bad, good)()) + abort (); + + exit (0); +} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/c-c++-common/builtin-choose-expr-2.c @@ -0,0 +1,16 @@ +/* Test for invalid use of __builtin_choose_expr. */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +int a, b, c, d; + +void +f (void) +{ + a = __builtin_choose_expr (b, c, d); /* { dg-error "first argument to '__builtin_choose_expr' not a constant" } */ + /* { dg-error "'b' cannot appear in a constant-expression" "" { target c++ } 10 } */ + a = __builtin_choose_expr (1, c); /* { dg-error "expected ','" "" { target c++ } } */ + /* { dg-error "wrong number of arguments" "" { target c } 12 } */ + a = __builtin_choose_expr (1, b, c, d); /* { dg-error "expected '\\)'" "" { target c++ } } */ + /* { dg-error "wrong number of arguments" "" { target c } 14 } */ +} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/c-c++-common/Wunused-var-15.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-Wunused" } */ + +int +f1 (void) +{ + int a; + int b; + int c; + int d; + int e; /* { dg-warning "set but not used" "" { target c++ } } */ + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + return sizeof (a) + ((__typeof (b)) 1) + __alignof__ (c) + + __builtin_choose_expr (1, d, e); +} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/g++.dg/ext/builtin-choose-expr1.C @@ -0,0 +1,28 @@ +/* Test for invalid use of __builtin_choose_expr. */ +/* { dg-do compile } */ +/* { dg-options "-pedantic-errors" } */ + +#include + +int a, b, c; + +void +f (void) +{ + /* __builtin_choose_expr acts exactly like the chosen argument for + all constant expression purposes. */ + enum e { + E1 = __builtin_choose_expr (1, 1, ++b), + E2 = __builtin_choose_expr (0, 1, ++b) /* { dg-error "cannot appear" } */ + }; + /* The first argument to __builtin_choose_expr must be an integer + constant expression. */ + a = __builtin_choose_expr ((void *)0, b, c); /* { dg-error "cannot appear" } */ + /* { dg-error "first argument" "" { target *-*-* } 20 } */ + a = __builtin_choose_expr (0 * (INT_MAX + 1), b, c); /* { dg-warning "integer overflow in expression" } */ + a = __builtin_choose_expr (1 / 0, 0, 0); /* { dg-warning "division by zero" } */ + /* { dg-error "first argument" "" { target *-*-* } 23 } */ + /* { dg-error "not a constant" "" { target *-*-* } 23 } */ + a = __builtin_choose_expr ((1 ? 1 : a), b, c); /* { dg-error "cannot appear" } */ + /* { dg-error "first argument" "" { target *-*-* } 26 } */ +} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/g++.dg/ext/builtin-choose-expr2.C @@ -0,0 +1,27 @@ +/* Test for invalid use of __builtin_choose_expr. */ +/* { dg-do compile } */ +/* { dg-options "-std=c++0x -pedantic-errors" } */ + +#include + +int a, b, c; + +void +f (void) +{ + /* __builtin_choose_expr acts exactly like the chosen argument for + all constant expression purposes. */ + enum e { + E1 = __builtin_choose_expr (1, 1, ++b), + E2 = __builtin_choose_expr (0, 1, ++b) /* { dg-error "not a constant-expression" } */ + /* { dg-error "enumerator value" "" { target *-*-* } 16 } */ + }; + /* The first argument to __builtin_choose_expr must be an integer + constant expression. */ + a = __builtin_choose_expr ((void *)0, b, c); + a = __builtin_choose_expr (0 * (INT_MAX + 1), b, c); /* { dg-warning "overflow" } */ + /* { dg-error "overflow" "" { target *-*-* } 22 } */ + a = __builtin_choose_expr (1 / 0, 0, 0); /* { dg-warning "division by zero" } */ + /* { dg-error "not a constant" "" { target *-*-* } 24 } */ + a = __builtin_choose_expr ((1 ? 1 : a), b, c); +} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/g++.dg/ext/builtin-choose-expr3.C @@ -0,0 +1,140 @@ +/* Test for valid use of __builtin_choose_expr. */ +/* { dg-do compile } */ +/* { dg-options "-std=c++0x" } */ + +template struct is_same { enum : bool { value = false }; }; +template struct is_same { enum : bool { value = true }; }; + +#define CHECK(expr, type, val) \ + static_assert(is_same::value && (expr == val), "oops"); + +#define CHECK_TYPE(expr, type) \ + static_assert(is_same::value, "oops"); + +int a, c, d; +constexpr int b = 0; + +template +struct s { static constexpr int value = i; }; + +template +inline T declval_noref() + { + struct helper + { + enum { protector = false }; + static T declval_noref(); + }; + + static_assert(helper::protector, "declval_noref() must not be called"); + return helper::declval_noref(); + } + +void +f (void) + { + constexpr int b2 = 0; + a = __builtin_choose_expr (b, c++, ++d); + a = __builtin_choose_expr (b2, --c, d--); + a = __builtin_choose_expr (s::value, c, d); + a = __builtin_choose_expr (__builtin_choose_expr(b, b2, 1), + __builtin_choose_expr(b, c, d), + __builtin_choose_expr(b, c, d)); + } + +CHECK(__builtin_choose_expr(0, 1, 2.0), double, 2.0); +CHECK(__builtin_choose_expr(1, 1, 2.0), int, 1 ); +CHECK(__builtin_choose_expr(0, cause error, 1), int, 1); +CHECK(__builtin_choose_expr(1, 1, cause error), int, 1); + +constexpr auto c1 = __builtin_choose_expr(0, 1, 2.0); +constexpr auto c2 = __builtin_choose_expr(1, 1, 2.0); +constexpr auto c3 = __builtin_choose_expr(__builtin_choose_expr(0, 1, 0), 1, 2.0); +constexpr auto c4 = __builtin_choose_expr(__builtin_choose_expr(1, 1, 0), 1, 2.0); +static const auto c5 = [](){ return __builtin_choose_expr(0, 1, 2.0); }(); +static const auto c6 = [](){ return __builtin_choose_expr(1, 1, 2.0); }(); + +CHECK(c1, const double, 2.0); +CHECK(c2, const int, 1 ); +CHECK(c3, const double, 2.0); +CHECK(c4, const int, 1 ); +CHECK_TYPE(c5, const double); +CHECK_TYPE(c6, const int ); + +template +constexpr int test1() + { return __builtin_choose_expr(i < 5, i * 2, i * 3); } + +CHECK(test1<1>(), int, 2 ); +CHECK(test1<10>(), int, 30); + +struct test2 + { + static constexpr int j = 0; + static constexpr int value = __builtin_choose_expr(j < 5, j + 2, j); + + static constexpr auto fn1() + -> decltype(__builtin_choose_expr(j < 5, int(), double())) + { return __builtin_choose_expr(j < 5, 1, 2.0); } + + static constexpr auto fn2() + -> decltype(__builtin_choose_expr(j > 5, int(), double())) + { return __builtin_choose_expr(j > 5, 1, 2.0); } + }; + +CHECK(test2::value, const int, 2 ); +CHECK(test2::fn1(), int, 1 ); +CHECK(test2::fn2(), double, 2.0); + +template +struct test3 + { + static constexpr int j = i * 3; + static constexpr int value = __builtin_choose_expr(i < 5, i * 2, i * 3); + + static constexpr auto fn() + -> decltype(__builtin_choose_expr(i, declval_noref(), declval_noref())) + { return __builtin_choose_expr(i, value, value); } + + template + struct child + { + /* nested template class, nested __builtin_choose_expr */ + static constexpr int value = __builtin_choose_expr( + __builtin_choose_expr((i < 5), (j < 5), (k < 5)), + 2 * __builtin_choose_expr((i < j), (j - i), (i - j)), + 3 * __builtin_choose_expr((i < k), (k - i), (i - k))); + }; + }; + +CHECK(test3<1>::value, const int, 2 ); +CHECK(test3<10>::value, const int, 30); +CHECK(test3<1>::fn(), int, 2 ); +CHECK(test3<10>::fn(), int, 30); +CHECK(test3<0>::fn(), double, 0 ); + +static_assert(test3<1>::child<3, 0>::value == 4, "oops"); +static_assert(test3<3>::child<1, 0>::value == 4, "oops"); +static_assert(test3<1>::child<5, 4>::value == 9, "oops"); +static_assert(test3<4>::child<5, 1>::value == 9, "oops"); +static_assert(test3<5>::child<4, 1>::value == 2, "oops"); +static_assert(test3<5>::child<6, 1>::value == 2, "oops"); +static_assert(test3<5>::child<0, 10>::value == 15, "oops"); +static_assert(test3<10>::child<0, 5>::value == 15, "oops"); + +template +__attribute__((gnu_inline)) /* necessary to avoid mangling */ +constexpr auto test4() + -> decltype(__builtin_choose_expr(i, 1, 2.0)) + { return __builtin_choose_expr(i, 1, 2.0); } + +CHECK(test4<0>(), double, 2.0); +CHECK(test4<1>(), int, 1 ); + +struct T1; +struct T2; + +template (), declval_noref()))> +struct X { typedef T type; }; + +static_assert(is_same::type, T1>::value, "oops"); --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/g++.dg/ext/builtin-choose-expr4.C @@ -0,0 +1,87 @@ +/* Test for valid use of __builtin_choose_expr. */ +/* { dg-do run } */ +/* { dg-options "-O1 -Wall -std=c++0x" } */ + +extern "C" void abort (); +extern "C" void exit (int); + +bool bad () +{ + return false; +} + +bool good () +{ + return true; +} + +template +struct wrapper +{ + static constexpr T value = t; +}; + +struct T +{ + explicit constexpr T(int i) : i(i) { } + int i; + static bool t() { return true; } +}; + +struct S +{ + static bool s() { return true; } +}; + +#define TS(a,b) __builtin_choose_expr((a), b::t, b::s) + +#define TEST(c,v) __builtin_choose_expr((c), \ + (wrapper::value), \ + [&](){ constexpr auto o = (v); return o; }()) + +constexpr T t = T(TEST(1, 10)); + +int main (void) +{ + T tt = TEST(0, t); + + constexpr int one = 1; + float f; + + __builtin_choose_expr (sizeof (int), f, bad ()) = 3.5F; + + if (f != 3.5F) + abort (); + + if (tt.i != 10) + abort (); + + if (!__builtin_choose_expr (!one, bad, [=](){ return f == 3.5F; })()) + abort (); + + if (!__builtin_choose_expr (!one, bad, [&](){ return f == 3.5F; })()) + abort (); + + if (!__builtin_choose_expr (one, [](float g){ return g == 3.5F; }, bad)(f)) + abort (); + + if (!__builtin_choose_expr (one, good, bad)()) + abort (); + + if (!__builtin_choose_expr (!one, bad, good)()) + abort (); + + /* the following condition evaluates since the compiler can + * determine that `1' is always true and so `tt.i' need not + * be evaluated */ + if (!__builtin_choose_expr (1 ? 0 : tt.i, bad, good)()) + abort (); + + if (!TS(1, T)()) + abort (); + + if (!TS(0, S)()) + abort (); + + exit (0); +} --- /dev/null +++ gcc-4.7.0-patched/gcc/testsuite/g++.dg/ext/builtin-choose-expr5.C @@ -0,0 +1,113 @@ +/* Test for parsing of __builtin_choose_expr. */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#define JOIN(a,b) JOIN2(a,b) +#define JOIN2(a,b) a ## b +#define causes_error JOIN(causes_error_, __COUNTER__) + +#define STATIC_ASSERT(a) \ + typedef char JOIN(assertion_failed_at_line_, __LINE__) \ + [(a) ? 1 : -1] + +template +struct s { static int x(); }; + +int x() { return 0; } + +struct A + { + static const int a = __builtin_choose_expr(0, 1, causes_error); /* { dg-error "causes_error" } */ + static const int b = __builtin_choose_expr(1, 1, causes_error); + static const int c = __builtin_choose_expr(0, causes_error, 0); + static const int d = __builtin_choose_expr(1, causes_error, 0); /* { dg-error "causes_error" } */ + + static const int k = __builtin_choose_expr(b, 1, causes_error); + static const int l = __builtin_choose_expr(b, causes_error, 0); /* { dg-error "causes_error" } */ + static const int o = __builtin_choose_expr(b, b, causes_error); + static const int p = __builtin_choose_expr(b, causes_error, b); /* { dg-error "causes_error" } */ + }; + +template +struct B + { + static const int a = __builtin_choose_expr(0, 1, causes_error); /* { dg-error "causes_error" } */ + static const int b = __builtin_choose_expr(1, 1, causes_error); + static const int c = __builtin_choose_expr(0, causes_error, 0); + static const int d = __builtin_choose_expr(1, causes_error, 0); /* { dg-error "causes_error" } */ + + static const int e = __builtin_choose_expr(I, 1, causes_error); /* { dg-error "causes_error" } */ + static const int f = __builtin_choose_expr(I, causes_error, 0); /* { dg-error "causes_error" } */ + static const int g = __builtin_choose_expr(I, I, causes_error); /* { dg-error "causes_error" } */ + static const int h = __builtin_choose_expr(I, causes_error, I); /* { dg-error "causes_error" } */ + static const int i = __builtin_choose_expr(I, b, causes_error); /* { dg-error "causes_error" } */ + static const int j = __builtin_choose_expr(I, causes_error, b); /* { dg-error "causes_error" } */ + + static const int k = __builtin_choose_expr(b, 1, causes_error); + static const int l = __builtin_choose_expr(b, causes_error, 0); /* { dg-error "causes_error" } */ + static const int m = __builtin_choose_expr(b, I, causes_error); + static const int n = __builtin_choose_expr(b, causes_error, I); /* { dg-error "causes_error" } */ + static const int o = __builtin_choose_expr(b, b, causes_error); + static const int p = __builtin_choose_expr(b, causes_error, b); /* { dg-error "causes_error" } */ + + static const int q = I; + static const int r = __builtin_choose_expr(q, 1, causes_error); /* { dg-error "causes_error" } */ + static const int s = __builtin_choose_expr(q, causes_error, 0); /* { dg-error "causes_error" } */ + static const int t = __builtin_choose_expr(q, I, causes_error); /* { dg-error "causes_error" } */ + static const int u = __builtin_choose_expr(q, causes_error, I); /* { dg-error "causes_error" } */ + static const int v = __builtin_choose_expr(q, b, causes_error); /* { dg-error "causes_error" } */ + static const int w = __builtin_choose_expr(q, causes_error, b); /* { dg-error "causes_error" } */ +}; + +void f() + { + A aa; + B<0> ab; + B<1> ac; + int t = 0; + + STATIC_ASSERT(aa.o == 1); + STATIC_ASSERT(ab.m == 0); + STATIC_ASSERT(ac.m == 1); + STATIC_ASSERT(ab.o == 1); + STATIC_ASSERT(ac.o == 1); + + (void)__builtin_choose_expr(0, 1, causes_error); /* { dg-error "causes_error" } */ + (void)__builtin_choose_expr(1, 1, causes_error); + (void)__builtin_choose_expr(0, causes_error, 0); + (void)__builtin_choose_expr(1, causes_error, 0); /* { dg-error "causes_error" } */ + + /* Test for expressions containing comma in strings or character literals */ + (void)__builtin_choose_expr(1, ',', 0); + (void)__builtin_choose_expr(1, ",", 0); + (void)__builtin_choose_expr(0, ',', 0); + (void)__builtin_choose_expr(0, ",", 0); + (void)__builtin_choose_expr(1, 0, ','); + (void)__builtin_choose_expr(1, 0, ","); + (void)__builtin_choose_expr(0, 0, ','); + (void)__builtin_choose_expr(0, 0, ","); + + /* Test for expressions containing commas inside brackets */ + (void)__builtin_choose_expr(0, [,], 1); + (void)__builtin_choose_expr(1, 1, [,]); + (void)__builtin_choose_expr(0, {,}, 1); + (void)__builtin_choose_expr(1, 1, {,}); + (void)__builtin_choose_expr(0, (,), 1); + (void)__builtin_choose_expr(1, 1, (,)); + (void)__builtin_choose_expr(1, s<0,1>(), 1); + (void)__builtin_choose_expr(0, 1, s<0,1>()); + (void)__builtin_choose_expr(0, (s<0,1>()), 1); + (void)__builtin_choose_expr(1, (s<0,1>()), 1); + (void)__builtin_choose_expr(0, 1, (s<0,1>())); + (void)__builtin_choose_expr(1, 1, (s<0,1>())); + + /* The following are undesired fails due to lexer not being able to + differentiate between s<0 as a comparison expression and s<0,1>::x() + as a template class static function expression */ + (void)__builtin_choose_expr(0, s<0,1>::x(), 1); /* { dg-error "expected" } */ + (void)__builtin_choose_expr(1, 1, s<0,1>::x()); /* { dg-error "expected" } */ + + /* Valid comparison expressions that look like template expressions */ + (void)__builtin_choose_expr(0, t<0, 1>::x()); + (void)__builtin_choose_expr(1, t<0, 1>::x()); + }