* Re: [C++ Patch] __builtin_choose_expr
@ 2011-10-19 12:26 Andy Gibbs
2011-10-21 10:40 ` [C++ Patch] __builtin_choose_expr *bump* Andy Gibbs
0 siblings, 1 reply; 6+ messages in thread
From: Andy Gibbs @ 2011-10-19 12:26 UTC (permalink / raw)
To: gcc-patches; +Cc: paolo.carlini, iant
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 <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/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;
};
\f
@@ -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 <joseph@codesourcery.com> */
-/* { 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 <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 } */
+}
--- /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 <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);
+}
--- /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 <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");
--- /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 <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);
+}
--- /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 <int i, int j>
+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 <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;
+ 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());
+ }
^ permalink raw reply [flat|nested] 6+ messages in thread
* [C++ Patch] __builtin_choose_expr *bump*
2011-10-19 12:26 [C++ Patch] __builtin_choose_expr Andy Gibbs
@ 2011-10-21 10:40 ` Andy Gibbs
2011-10-21 10:47 ` Richard Guenther
2011-10-21 15:28 ` Joseph S. Myers
0 siblings, 2 replies; 6+ messages in thread
From: Andy Gibbs @ 2011-10-21 10:40 UTC (permalink / raw)
To: gcc-patches
Hi,
Please can I "bump" this patch and ask for it to be approved and committed:
http://gcc.gnu.org/ml/gcc-patches/2011-10/msg01711.html
The patch is to implement the C built-in function __builtin_choose_expr(...)
in C++.
I'm afraid I am new to contributing to GCC, so I hope I am going about this
the right way. I also appreciate that this is a very busy mailing list, but
would be very grateful if the patch could be committed so that it can make
it into 4.7.0.
Many thanks
Andy
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [C++ Patch] __builtin_choose_expr *bump*
2011-10-21 10:40 ` [C++ Patch] __builtin_choose_expr *bump* Andy Gibbs
@ 2011-10-21 10:47 ` Richard Guenther
2011-10-21 14:29 ` Andy Gibbs
2011-10-21 15:28 ` Joseph S. Myers
1 sibling, 1 reply; 6+ messages in thread
From: Richard Guenther @ 2011-10-21 10:47 UTC (permalink / raw)
To: Andy Gibbs; +Cc: gcc-patches
On Fri, Oct 21, 2011 at 11:57 AM, Andy Gibbs <andyg1001@hotmail.co.uk> wrote:
> Hi,
>
> Please can I "bump" this patch and ask for it to be approved and committed:
> http://gcc.gnu.org/ml/gcc-patches/2011-10/msg01711.html
>
> The patch is to implement the C built-in function __builtin_choose_expr(...)
> in C++.
>
> I'm afraid I am new to contributing to GCC, so I hope I am going about this
> the right way. I also appreciate that this is a very busy mailing list, but
> would be very grateful if the patch could be committed so that it can make
> it into 4.7.0.
What's the motivation for this? Why can't it be implemented using C++
features such as templates and specialization?
Richard.
> Many thanks
>
> Andy
>
>
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [C++ Patch] __builtin_choose_expr *bump*
2011-10-21 10:47 ` Richard Guenther
@ 2011-10-21 14:29 ` Andy Gibbs
0 siblings, 0 replies; 6+ messages in thread
From: Andy Gibbs @ 2011-10-21 14:29 UTC (permalink / raw)
To: Richard Guenther; +Cc: gcc-patches
On Friday, October 21, 2011 12:04 PM, Richard Guenther wrote:
> What's the motivation for this? Why can't it be implemented using C++
> features such as templates and specialization?
Sorry for the delay in my reply.
The motivation, simply put, is to be able to create both templates and
macros that choose between two or more courses of action at compile time and
do not generate code for the unchosen action(s), nor (importantly) cause
compiler errors if the unchosen action(s) should be ill-formed. The end aim
is in the generation of source code libraries for compile-time evaluation.
An example in the template domain would be, having template specialisation
without actually needing to specialise the template. Ordinarily,
specialising a template requires a copy to be made and modified according to
the specialisation. If the "base" template is changed, the specialisation
also needs to be so adapted. Missing one specialisation in a long list
leads to unpredictable problems (yes, there is bitter experience here!). If
the majority of code is identical then it makes sense to try to either
factor out the identical code and use some meta-template If struct or other
such magic to limit the scope of the template specialisation. This can
become brain-bending if not impossible if, for example, any of the relevant
expressions cannot be parameters into a meta-template construct. It can
also make the code very difficult to follow and debug. In these cases,
__builtin_choose_expr can be beneficial to avoid the need to specialise,
while keeping the clarity and breadth of the template's intended function.
When it comes to macros, the use of __builtin_choose_expr can be very useful
where one of the expressions would cause a compiler error. An example of
such a macro is as follows:
#define CONST(v) \
__builtin_choose_expr(util::can_use_const_wrapper<decltype(v)>::value, \
(util::const_wrapper<decltype(v),(v)>::value) : \
([&](){ constexpr auto o = (v); return o; })())
namespace util
{
template <typename T, T t>
struct const_wrapper
{ static constexpr T value = t; };
template <typename T>
struct can_use_const_wrapper; /* code removed to keep example short! */
/* value = true for types that can be used in template value parameters */
}
This is a part of a larger library of code for constexpr functions, a
majority of which implement algorithms in such a way that the compiler can
evaluate them but which if evaluated at run-time would have a huge
performance hit (e.g. CRC calculation on a string). In this library, a
second macro FORCE_CONSTEXPR is used to ensure these functions cannot be
called at run-time or even inlined, but only evaluated at compile-time. The
CONST macro is then used, among other things, to hint to the compiler that
it needs to evaluate at compile-time.
If __builtin_choose_expr in the CONST macro was replaced with "? :" then the
code using it would fail to compile in certain situations, notably because
C++ only permits certain types as template value parameters. However, it is
not sufficient either to simply use the lambda expression alone since this
fails with compiler errors in other situations. This is, I think, one
example where it is not possible to use templates to get round the
problem?...
There is a further use of __builtin_choose_expr in this constexpr library,
which is similar to its use in C, which is to enable a macro function to
wrap and choose between a compile-time version of the algorithm and a
run-time version of the algorithm, for example:
#define CrcString(str) (__builtin_choose_expr(__builtin_constant_p(str), \
CONST(CrcString_compiler(str)), \
CrcString_runtime(str)))
auto string = CrcString("test");
This might of course be implemented using "? :", but only if
CrcString_compiler(...) and CrcString_runtime(...) return compatible types,
which need not be so with __builtin_choose_expr.
I hope this gives you some feeling for how __builtin_choose_expr may be
used, or for that matter how I use it. I expect that others will find much
more impressive uses!
Thanks
Andy
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [C++ Patch] __builtin_choose_expr *bump*
2011-10-21 10:40 ` [C++ Patch] __builtin_choose_expr *bump* Andy Gibbs
2011-10-21 10:47 ` Richard Guenther
@ 2011-10-21 15:28 ` Joseph S. Myers
2011-10-21 15:39 ` Andy Gibbs
1 sibling, 1 reply; 6+ messages in thread
From: Joseph S. Myers @ 2011-10-21 15:28 UTC (permalink / raw)
To: Andy Gibbs; +Cc: gcc-patches
On Fri, 21 Oct 2011, Andy Gibbs wrote:
> Hi,
>
> Please can I "bump" this patch and ask for it to be approved and committed:
> http://gcc.gnu.org/ml/gcc-patches/2011-10/msg01711.html
Have you sent in your copyright assignment papers to the FSF? The patch
is large enough to need them.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-10-21 14:57 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-19 12:26 [C++ Patch] __builtin_choose_expr Andy Gibbs
2011-10-21 10:40 ` [C++ Patch] __builtin_choose_expr *bump* Andy Gibbs
2011-10-21 10:47 ` Richard Guenther
2011-10-21 14:29 ` Andy Gibbs
2011-10-21 15:28 ` Joseph S. Myers
2011-10-21 15:39 ` Andy Gibbs
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).