=====
Changelog:
2011-10-17 Andy Gibbs <andyg1001@hotmail.co.uk>
* 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/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
* testsuite/g++.dg/ext/builtin-choose-expr6.C: New test
* testsuite/g++.dg/ext/builtin-choose-expr7.C: New test
* testsuite/g++.dg/ext/builtin-choose-expr8.C: New test
@@ -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 },
@@ -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"
@@ -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)
@@ -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);
@@ -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)
{
@@ -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 */
@@ -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;
}
}
@@ -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;
@@ -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,20 @@ 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)
+{
+ /* FIXME Uses cp_parser_skip_to_closing_parenthesis, but this fails
+ to correctly interpret nested commas inside template `<' and `>' */
+ 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 +3305,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 +3638,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 +7245,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.
@@ -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,
@@ -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:
@@ -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
@@ -0,0 +1,28 @@
+/* Test for invalid use of __builtin_choose_expr. */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors" } */
+
+#include <limits.h>
+
+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 } */
+}
@@ -0,0 +1,27 @@
+/* Test for invalid use of __builtin_choose_expr. */
+/* { dg-do compile } */
+/* { dg-options "-std=c++0x -pedantic-errors" } */
+
+#include <limits.h>
+
+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);
+}
@@ -0,0 +1,20 @@
+/* Test for valid use of __builtin_choose_expr. */
+/* { 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" } */
+ a = 1;
+ b = 2;
+ c = 3;
+ d = 4;
+ e = 5;
+ return sizeof (a) + ((__typeof (b)) 1) + __alignof__ (c)
+ + __builtin_choose_expr (1, d, e);
+}
@@ -0,0 +1,95 @@
+/* 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)
+
+
+extern "C" void abort ();
+extern "C" void exit (int);
+
+bool bad ()
+{
+ return false;
+}
+
+bool good ()
+{
+ return true;
+}
+
+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);
+}
@@ -0,0 +1,14 @@
+/* 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 "'b' cannot appear in a constant-expression" } */
+ /* { dg-error "first argument to '__builtin_choose_expr' not a constant" "" { target *-*-* } 10 } */
+ a = __builtin_choose_expr (1, c); /* { dg-error "expected ','" } */
+ a = __builtin_choose_expr (1, b, c, d); /* { dg-error "expected '\\)'" } */
+}
@@ -0,0 +1,141 @@
+/* Test for valid use of __builtin_choose_expr. */
+/* { dg-do compile } */
+/* { dg-options "-std=c++0x" } */
+
+template <typename, typename> struct is_same { enum : bool { value = false }; };
+template <typename T> struct is_same<T, T> { enum : bool { value = true }; };
+
+#define CHECK(expr, type, val) \
+ static_assert(is_same<decltype(expr), type>::value && (expr == val), "oops");
+
+#define CHECK_TYPE(expr, type) \
+ static_assert(is_same<decltype(expr), type>::value, "oops");
+
+int a, c, d;
+constexpr int b = 0;
+
+template <int i>
+struct s { static constexpr int value = i; };
+
+template <typename T>
+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<b2>::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 <int i>
+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 <int i>
+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<int>(), declval_noref<double>()))
+ { return __builtin_choose_expr(i, value, value); }
+
+ template <int j, int k>
+ 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 <int i>
+__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 <typename T = decltype(__builtin_choose_expr(1, declval_noref<T1>(), declval_noref<T2>()))>
+struct X { typedef T type; };
+
+static_assert(is_same<typename X<>::type, T1>::value, "oops");
+
@@ -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 <typename T, T t>
+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<decltype(v),(v)>::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);
+}
@@ -0,0 +1,107 @@
+/* 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 <int i, int j>
+struct s {};
+
+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 <int I>
+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;
+
+ 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>()
+ as a template class contructor expression */
+ (void)__builtin_choose_expr(0, s<0,1>(), 1); /* { dg-error "expected" } */
+ (void)__builtin_choose_expr(1, 1, s<0,1>()); /* { dg-error "expected" } */
+ }