aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog69
-rw-r--r--gcc/c/c-decl.cc130
-rw-r--r--gcc/c/c-parser.cc167
-rw-r--r--gcc/c/c-typeck.cc15
4 files changed, 352 insertions, 29 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index f5c9a59..a25e1b4 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,72 @@
+2022-10-07 Qing Zhao <qing.zhao@oracle.com>
+
+ * c-decl.cc (flexible_array_member_type_p): New function.
+ (one_element_array_type_p): Likewise.
+ (zero_length_array_type_p): Likewise.
+ (add_flexible_array_elts_to_size): Call new utility
+ routine flexible_array_member_type_p.
+ (is_flexible_array_member_p): New function.
+ (finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
+
+2022-10-06 Joseph Myers <joseph@codesourcery.com>
+
+ * c-parser.cc (c_parse_init): Add D_EXT11 to mask if flag_no_asm
+ and not C2x.
+ (c_keyword_starts_typename, c_token_starts_declspecs)
+ (c_parser_declspecs, c_parser_objc_selector): Handle
+ RID_TYPEOF_UNQUAL.
+ (c_parser_typeof_specifier): Handle RID_TYPEOF_UNQUAL.
+ Distinguish typeof for C2x from __typeof__ for all standard
+ versions and typeof before C2x.
+ * c-typeck.cc (build_function_call_vec): Use unqualified version
+ of non-void return type.
+ (build_unary_op): Use unqualified type for increment and
+ decrement.
+
+2022-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.cc (c_parser_omp_assumption_clauses): Emit IFN_ASSUME
+ call for holds clause on assume construct.
+
+2022-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/106654
+ * c-parser.cc (handle_assume_attribute): New function.
+ (c_parser_declaration_or_fndef): Handle assume attribute.
+ (c_parser_attribute_arguments): Add assume_attr argument,
+ if true, parse first argument as conditional expression.
+ (c_parser_gnu_attribute, c_parser_std_attribute): Adjust
+ c_parser_attribute_arguments callers.
+ (c_parser_statement_after_labels) <case RID_ATTRIBUTE>: Handle
+ assume attribute.
+
+2022-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ * c-lang.h (struct c_omp_declare_target_attr): New type.
+ (current_omp_declare_target_attribute): Change type from
+ int to vec<c_omp_declare_target_attr, va_gc> *.
+ * c-parser.cc (c_parser_translation_unit): Adjust for that change.
+ If last pushed directive was begin declare target, use different
+ wording and simplify format strings for easier translations.
+ (c_parser_omp_clause_device_type): Uncomment
+ check_no_duplicate_clause call.
+ (c_parser_omp_declare_target): Adjust for the
+ current_omp_declare_target_attribute type change, push { -1 }.
+ Use error_at rather than warning_at for declare target with
+ only device_type clauses.
+ (OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK): Define.
+ (c_parser_omp_begin): Add begin declare target support.
+ (c_parser_omp_end): Adjust for the
+ current_omp_declare_target_attribute type change, adjust
+ diagnostics wording and simplify format strings for easier
+ translations.
+ * c-decl.cc (current_omp_declare_target_attribute): Change type from
+ int to vec<c_omp_declare_target_attr, va_gc> *.
+ (c_decl_attributes): Adjust for the
+ current_omp_declare_target_attribute type change. If device_type
+ was present on begin declare target, add "omp declare target host"
+ and/or "omp declare target nohost" attributes.
+
2022-09-29 Joseph Myers <joseph@codesourcery.com>
* c-decl.cc (handle_std_noreturn_attribute): New function.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index ffa63dc..193e268 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5034,6 +5034,41 @@ set_array_declarator_inner (struct c_declarator *decl,
return decl;
}
+/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]". */
+static bool
+flexible_array_member_type_p (const_tree type)
+{
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_SIZE (type) == NULL_TREE
+ && TYPE_DOMAIN (type) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ return true;
+
+ return false;
+}
+
+/* Determine whether TYPE is a one-element array type "[1]". */
+static bool
+one_element_array_type_p (const_tree type)
+{
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ return false;
+ return integer_zerop (array_type_nelts (type));
+}
+
+/* Determine whether TYPE is a zero-length array type "[0]". */
+static bool
+zero_length_array_type_p (const_tree type)
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ if (tree type_size = TYPE_SIZE_UNIT (type))
+ if ((integer_zerop (type_size))
+ && TYPE_DOMAIN (type) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ return true;
+ return false;
+}
+
/* INIT is a constructor that forms DECL's initializer. If the final
element initializes a flexible array field, add the size of that
initializer to DECL's size. */
@@ -5048,10 +5083,7 @@ add_flexible_array_elts_to_size (tree decl, tree init)
elt = CONSTRUCTOR_ELTS (init)->last ().value;
type = TREE_TYPE (elt);
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_SIZE (type) == NULL_TREE
- && TYPE_DOMAIN (type) != NULL_TREE
- && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ if (flexible_array_member_type_p (type))
{
complete_array_type (&type, elt, false);
DECL_SIZE (decl)
@@ -8755,6 +8787,81 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
}
}
+
+/* Determine whether the FIELD_DECL X is a flexible array member according to
+ the following info:
+ A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
+ B. whether the FIELD_DECL is an array that is declared as "[]", "[0]",
+ or "[1]";
+ C. flag_strict_flex_arrays;
+ D. the attribute strict_flex_array that is attached to the field
+ if presenting.
+ Return TRUE when it's a flexible array member, FALSE otherwise. */
+
+static bool
+is_flexible_array_member_p (bool is_last_field,
+ tree x)
+{
+ /* If not the last field, return false. */
+ if (!is_last_field)
+ return false;
+
+ /* If not an array field, return false. */
+ if (TREE_CODE (TREE_TYPE (x)) != ARRAY_TYPE)
+ return false;
+
+ bool is_zero_length_array = zero_length_array_type_p (TREE_TYPE (x));
+ bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
+ bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
+
+ unsigned int strict_flex_array_level = flag_strict_flex_arrays;
+
+ tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
+ DECL_ATTRIBUTES (x));
+ /* If there is a strict_flex_array attribute attached to the field,
+ override the flag_strict_flex_arrays. */
+ if (attr_strict_flex_array)
+ {
+ /* Get the value of the level first from the attribute. */
+ unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
+ gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+ attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+ gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+ attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+ gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
+ attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
+
+ /* The attribute has higher priority than flag_struct_flex_array. */
+ strict_flex_array_level = attr_strict_flex_array_level;
+ }
+
+ switch (strict_flex_array_level)
+ {
+ case 0:
+ /* Default, all trailing arrays are flexible array members. */
+ return true;
+ case 1:
+ /* Level 1: all "[1]", "[0]", and "[]" are flexible array members. */
+ if (is_one_element_array)
+ return true;
+ /* FALLTHROUGH. */
+ case 2:
+ /* Level 2: all "[0]", and "[]" are flexible array members. */
+ if (is_zero_length_array)
+ return true;
+ /* FALLTHROUGH. */
+ case 3:
+ /* Level 3: Only "[]" are flexible array members. */
+ if (is_flexible_array)
+ return true;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return false;
+}
+
+
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
FIELDLIST is a chain of FIELD_DECL nodes for the fields.
@@ -8816,6 +8923,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
bool saw_named_field = false;
for (x = fieldlist; x; x = DECL_CHAIN (x))
{
+ /* Whether this field is the last field of the structure or union.
+ for UNION, any field is the last field of it. */
+ bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
+ || (TREE_CODE (t) == UNION_TYPE);
+
if (TREE_TYPE (x) == error_mark_node)
continue;
@@ -8854,10 +8966,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
DECL_PACKED (x) = 1;
/* Detect flexible array member in an invalid context. */
- if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
- && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
- && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
- && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+ if (flexible_array_member_type_p (TREE_TYPE (x)))
{
if (TREE_CODE (t) == UNION_TYPE)
{
@@ -8865,7 +8974,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
"flexible array member in union");
TREE_TYPE (x) = error_mark_node;
}
- else if (DECL_CHAIN (x) != NULL_TREE)
+ else if (!is_last_field)
{
error_at (DECL_SOURCE_LOCATION (x),
"flexible array member not at end of struct");
@@ -8885,6 +8994,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic,
"invalid use of structure with flexible array member");
+ /* Set DECL_NOT_FLEXARRAY flag for FIELD_DECL x. */
+ DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x);
+
if (DECL_NAME (x)
|| RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
saw_named_field = true;
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index f6a94ba..89e0587 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -127,6 +127,8 @@ c_parse_init (void)
mask |= D_ASM | D_EXT;
if (!flag_isoc99)
mask |= D_EXT89;
+ if (!flag_isoc2x)
+ mask |= D_EXT11;
}
if (!c_dialect_objc ())
mask |= D_OBJC | D_CXX_OBJC;
@@ -580,6 +582,7 @@ c_keyword_starts_typename (enum rid keyword)
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_CONST:
case RID_ATOMIC:
case RID_VOLATILE:
@@ -757,6 +760,7 @@ c_token_starts_declspecs (c_token *token)
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
@@ -1823,6 +1827,46 @@ add_debug_begin_stmt (location_t loc)
add_stmt (stmt);
}
+/* Helper function for c_parser_declaration_or_fndef and
+ Handle assume attribute(s). */
+
+static tree
+handle_assume_attribute (location_t here, tree attrs, bool nested)
+{
+ if (nested)
+ for (tree attr = lookup_attribute ("gnu", "assume", attrs); attr;
+ attr = lookup_attribute ("gnu", "assume", TREE_CHAIN (attr)))
+ {
+ tree args = TREE_VALUE (attr);
+ int nargs = list_length (args);
+ if (nargs != 1)
+ {
+ error_at (here, "wrong number of arguments specified "
+ "for %qE attribute",
+ get_attribute_name (attr));
+ inform (here, "expected %i, found %i", 1, nargs);
+ }
+ else
+ {
+ tree arg = TREE_VALUE (args);
+ arg = c_objc_common_truthvalue_conversion (here, arg);
+ arg = c_fully_fold (arg, false, NULL);
+ if (arg != error_mark_node)
+ {
+ tree fn = build_call_expr_internal_loc (here, IFN_ASSUME,
+ void_type_node, 1,
+ arg);
+ add_stmt (fn);
+ }
+ }
+ }
+ else
+ pedwarn (here, OPT_Wattributes,
+ "%<assume%> attribute at top level");
+
+ return remove_attribute ("gnu", "assume", attrs);
+}
+
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition
is accepted; otherwise (old-style parameter declarations) only other
@@ -2037,6 +2081,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool auto_type_p = specs->typespec_word == cts_auto_type;
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
+ bool handled_assume = false;
+ if (specs->typespec_kind == ctsk_none
+ && lookup_attribute ("gnu", "assume", specs->attrs))
+ {
+ handled_assume = true;
+ specs->attrs
+ = handle_assume_attribute (here, specs->attrs, nested);
+ }
if (auto_type_p)
error_at (here, "%<__auto_type%> in empty declaration");
else if (specs->typespec_kind == ctsk_none
@@ -2054,13 +2106,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
pedwarn (here, OPT_Wattributes,
"%<fallthrough%> attribute at top level");
}
- else if (empty_ok && !(have_attrs
- && specs->non_std_attrs_seen_p))
+ else if (empty_ok
+ && !(have_attrs && specs->non_std_attrs_seen_p)
+ && !handled_assume)
shadow_tag (specs);
else
{
shadow_tag_warned (specs, 1);
- pedwarn (here, 0, "empty declaration");
+ if (!handled_assume)
+ pedwarn (here, 0, "empty declaration");
}
c_parser_consume_token (parser);
if (oacc_routine_data)
@@ -2160,6 +2214,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
else if (attribute_fallthrough_p (specs->attrs))
warning_at (here, OPT_Wattributes,
"%<fallthrough%> attribute not followed by %<;%>");
+ else if (lookup_attribute ("gnu", "assume", specs->attrs))
+ warning_at (here, OPT_Wattributes,
+ "%<assume%> attribute not followed by %<;%>");
pending_xref_error ();
prefix_attrs = specs->attrs;
@@ -3028,6 +3085,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
declspecs_add_type (loc, specs, t);
break;
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
/* ??? The old parser rejected typeof after other type
specifiers, but is a syntax error the best way of
handling this? */
@@ -3715,22 +3773,38 @@ c_parser_struct_declaration (c_parser *parser)
return decls;
}
-/* Parse a typeof specifier (a GNU extension).
+/* Parse a typeof specifier (a GNU extension adopted in C2X).
typeof-specifier:
typeof ( expression )
typeof ( type-name )
+ typeof_unqual ( expression )
+ typeof_unqual ( type-name )
*/
static struct c_typespec
c_parser_typeof_specifier (c_parser *parser)
{
+ bool is_unqual;
+ bool is_std;
struct c_typespec ret;
ret.kind = ctsk_typeof;
ret.spec = error_mark_node;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+ if (c_parser_next_token_is_keyword (parser, RID_TYPEOF))
+ {
+ is_unqual = false;
+ tree spelling = c_parser_peek_token (parser)->value;
+ is_std = (flag_isoc2x
+ && strcmp (IDENTIFIER_POINTER (spelling), "typeof") == 0);
+ }
+ else
+ {
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL));
+ is_unqual = true;
+ is_std = true;
+ }
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
in_typeof++;
@@ -3772,6 +3846,24 @@ c_parser_typeof_specifier (c_parser *parser)
pop_maybe_used (was_vm);
}
parens.skip_until_found_close (parser);
+ if (ret.spec != error_mark_node)
+ {
+ if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+ ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+ if (is_std)
+ {
+ /* In ISO C terms, _Noreturn is not part of the type of
+ expressions such as &abort, but in GCC it is represented
+ internally as a type qualifier. */
+ if (TREE_CODE (ret.spec) == FUNCTION_TYPE
+ && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+ ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+ else if (FUNCTION_POINTER_TYPE_P (ret.spec)
+ && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED)
+ ret.spec
+ = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec)));
+ }
+ }
return ret;
}
@@ -4598,7 +4690,8 @@ c_parser_gnu_attribute_any_word (c_parser *parser)
static tree
c_parser_attribute_arguments (c_parser *parser, bool takes_identifier,
- bool require_string, bool allow_empty_args)
+ bool require_string, bool assume_attr,
+ bool allow_empty_args)
{
vec<tree, va_gc> *expr_list;
tree attr_args;
@@ -4617,6 +4710,7 @@ c_parser_attribute_arguments (c_parser *parser, bool takes_identifier,
== CPP_CLOSE_PAREN))
&& (takes_identifier
|| (c_dialect_objc ()
+ && !assume_attr
&& c_parser_peek_token (parser)->id_kind
== C_ID_CLASSNAME)))
{
@@ -4653,6 +4747,23 @@ c_parser_attribute_arguments (c_parser *parser, bool takes_identifier,
tree string = c_parser_string_literal (parser, false, true).value;
attr_args = build_tree_list (NULL_TREE, string);
}
+ else if (assume_attr)
+ {
+ tree cond
+ = c_parser_conditional_expression (parser, NULL, NULL_TREE).value;
+ if (!c_parser_next_token_is (parser, CPP_COMMA))
+ attr_args = build_tree_list (NULL_TREE, cond);
+ else
+ {
+ tree tree_list;
+ c_parser_consume_token (parser);
+ expr_list = c_parser_expr_list (parser, false, true,
+ NULL, NULL, NULL, NULL);
+ tree_list = build_tree_list_vec (expr_list);
+ attr_args = tree_cons (NULL_TREE, cond, tree_list);
+ release_tree_vector (expr_list);
+ }
+ }
else
{
expr_list = c_parser_expr_list (parser, false, true,
@@ -4736,7 +4847,9 @@ c_parser_gnu_attribute (c_parser *parser, tree attrs,
tree attr_args
= c_parser_attribute_arguments (parser,
attribute_takes_identifier_p (attr_name),
- false, true);
+ false,
+ is_attribute_p ("assume", attr_name),
+ true);
attr = build_tree_list (attr_name, attr_args);
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
@@ -4982,9 +5095,13 @@ c_parser_std_attribute (c_parser *parser, bool for_tm)
= (ns == NULL_TREE
&& (strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0
|| strcmp (IDENTIFIER_POINTER (name), "nodiscard") == 0));
+ bool assume_attr
+ = (ns != NULL_TREE
+ && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0
+ && strcmp (IDENTIFIER_POINTER (name), "assume") == 0);
TREE_VALUE (attribute)
= c_parser_attribute_arguments (parser, takes_identifier,
- require_string, false);
+ require_string, assume_attr, false);
}
else
c_parser_balanced_token_sequence (parser);
@@ -6264,8 +6381,21 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
break;
case RID_ATTRIBUTE:
{
- /* Allow '__attribute__((fallthrough));'. */
+ /* Allow '__attribute__((fallthrough));' or
+ '__attribute__((assume(cond)));'. */
tree attrs = c_parser_gnu_attributes (parser);
+ bool has_assume = lookup_attribute ("assume", attrs);
+ if (has_assume)
+ {
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ attrs = handle_assume_attribute (loc, attrs, true);
+ else
+ {
+ warning_at (loc, OPT_Wattributes,
+ "%<assume%> attribute not followed by %<;%>");
+ has_assume = false;
+ }
+ }
if (attribute_fallthrough_p (attrs))
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -6282,9 +6412,13 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
"%<fallthrough%> attribute not followed "
"by %<;%>");
}
+ else if (has_assume)
+ /* Eat the ';'. */
+ c_parser_consume_token (parser);
else if (attrs != NULL_TREE)
- warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
- " can be applied to a null statement");
+ warning_at (loc, OPT_Wattributes,
+ "only attribute %<fallthrough%> or %<assume%> can "
+ "be applied to a null statement");
break;
}
default:
@@ -11866,7 +12000,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
identifier
one of
enum struct union if else while do for switch case default
- break continue return goto asm sizeof typeof __alignof
+ break continue return goto asm sizeof typeof typeof_unqual __alignof
unsigned long const short volatile signed restrict _Complex
in out inout bycopy byref oneway int char float double void _Bool
_Atomic
@@ -11906,6 +12040,7 @@ c_parser_objc_selector (c_parser *parser)
case RID_ASM:
case RID_SIZEOF:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_ALIGNOF:
case RID_UNSIGNED:
case RID_LONG:
@@ -23476,10 +23611,12 @@ c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume)
tree t = convert_lvalue_to_rvalue (eloc, expr, true, true).value;
t = c_objc_common_truthvalue_conversion (eloc, t);
t = c_fully_fold (t, false, NULL);
- if (is_assume)
+ if (is_assume && t != error_mark_node)
{
- /* FIXME: Emit .ASSUME (t) call here. */
- (void) t;
+ tree fn = build_call_expr_internal_loc (eloc, IFN_ASSUME,
+ void_type_node, 1,
+ t);
+ add_stmt (fn);
}
parens.skip_until_found_close (parser);
}
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ac242b5..f919068 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3187,6 +3187,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
/* fntype now gets the type of function pointed to. */
fntype = TREE_TYPE (fntype);
+ tree return_type = TREE_TYPE (fntype);
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
@@ -3203,8 +3204,6 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
&& TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
&& !comptypes (fntype, TREE_TYPE (tem)))
{
- tree return_type = TREE_TYPE (fntype);
-
/* This situation leads to run-time undefined behavior. We can't,
therefore, simply error unless we can prove that all possible
executions of the program must execute the code. */
@@ -3229,22 +3228,25 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
bool warned_p = check_function_arguments (loc, fundecl, fntype,
nargs, argarray, &arg_loc);
+ if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED
+ && !VOID_TYPE_P (return_type))
+ return_type = c_build_qualified_type (return_type, TYPE_UNQUALIFIED);
if (name != NULL_TREE
&& startswith (IDENTIFIER_POINTER (name), "__builtin_"))
{
if (require_constant_value)
result
- = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
+ = fold_build_call_array_initializer_loc (loc, return_type,
function, nargs, argarray);
else
- result = fold_build_call_array_loc (loc, TREE_TYPE (fntype),
+ result = fold_build_call_array_loc (loc, return_type,
function, nargs, argarray);
if (TREE_CODE (result) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
STRIP_TYPE_NOPS (result);
}
else
- result = build_call_array_loc (loc, TREE_TYPE (fntype),
+ result = build_call_array_loc (loc, return_type,
function, nargs, argarray);
/* If -Wnonnull warning has been diagnosed, avoid diagnosing it again
later. */
@@ -4831,6 +4833,9 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
else
val = build2 (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
+ if (TYPE_QUALS (TREE_TYPE (val)) != TYPE_UNQUALIFIED)
+ TREE_TYPE (val) = c_build_qualified_type (TREE_TYPE (val),
+ TYPE_UNQUALIFIED);
ret = val;
goto return_build_unary_op;
}