/* Subroutines shared by all languages that are variants of C.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
#include "c-pragma.h"
#include "ggc.h"
#include "c-common.h"
+#include "c-objc.h"
#include "tm_p.h"
#include "obstack.h"
#include "cpplib.h"
enum cxx_dialect cxx_dialect = cxx98;
/* Maximum template instantiation depth. This limit exists to limit the
- time it takes to notice infinite template instantiations; the default
- value of 1024 is likely to be in the next C++ standard. */
+ time it takes to notice excessively recursive template instantiations;
+ the default value of 1024 is likely to be in the next C++ standard. */
int max_tinst_depth = 1024;
-
-
/* The elements of `ridpointers' are identifier nodes for the reserved
type names and storage classes. It is indexed by a RID_... value. */
tree *ridpointers;
executed. */
int c_inhibit_evaluation_warnings;
+/* Whether we are building a boolean conversion inside
+ convert_for_assignment, or some other late binary operation. If
+ build_binary_op is called for C (from code shared by C and C++) in
+ this case, then the operands have already been folded and the
+ result will not be folded again, so C_MAYBE_CONST_EXPR should not
+ be generated. */
+bool in_late_binary_op;
+
/* Whether lexing has been completed, so subsequent preprocessor
errors should use the compiler's input_location. */
bool done_lexing = false;
{NULL, 0, 0},
};
+/* Global visibility options. */
+struct visibility_flags visibility_options;
+
static tree c_fully_fold_internal (tree expr, bool, bool *, bool *);
static tree check_case_value (tree);
static bool check_case_bounds (tree, tree, tree *, tree *);
{ "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY },
{ "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY },
{ "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY },
+ { "__imag", RID_IMAGPART, 0 },
+ { "__imag__", RID_IMAGPART, 0 },
+ { "__inline", RID_INLINE, 0 },
+ { "__inline__", RID_INLINE, 0 },
{ "__int128", RID_INT128, 0 },
{ "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY },
{ "__is_base_of", RID_IS_BASE_OF, D_CXXONLY },
{ "__is_convertible_to", RID_IS_CONVERTIBLE_TO, D_CXXONLY },
{ "__is_empty", RID_IS_EMPTY, D_CXXONLY },
{ "__is_enum", RID_IS_ENUM, D_CXXONLY },
+ { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY },
{ "__is_pod", RID_IS_POD, D_CXXONLY },
{ "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY },
{ "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY },
{ "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY },
{ "__is_union", RID_IS_UNION, D_CXXONLY },
- { "__imag", RID_IMAGPART, 0 },
- { "__imag__", RID_IMAGPART, 0 },
- { "__inline", RID_INLINE, 0 },
- { "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
{ "__null", RID_NULL, 0 },
{ "__real", RID_REALPART, 0 },
{ "__thread", RID_THREAD, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
+ { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
{ "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX0X | D_CXXWARN },
{ "synchronized", RID_AT_SYNCHRONIZED, D_OBJC },
{ "optional", RID_AT_OPTIONAL, D_OBJC },
{ "required", RID_AT_REQUIRED, D_OBJC },
+ { "property", RID_AT_PROPERTY, D_OBJC },
+ { "package", RID_AT_PACKAGE, D_OBJC },
+ { "synthesize", RID_AT_SYNTHESIZE, D_OBJC },
+ { "dynamic", RID_AT_DYNAMIC, D_OBJC },
/* These are recognized only in protocol-qualifier context
(see above) */
{ "bycopy", RID_BYCOPY, D_OBJC },
{ "inout", RID_INOUT, D_OBJC },
{ "oneway", RID_ONEWAY, D_OBJC },
{ "out", RID_OUT, D_OBJC },
+ /* These are recognized inside a property attribute list */
+ { "assign", RID_ASSIGN, D_OBJC },
+ { "copy", RID_COPY, D_OBJC },
+ { "getter", RID_GETTER, D_OBJC },
+ { "nonatomic", RID_NONATOMIC, D_OBJC },
+ { "readonly", RID_READONLY, D_OBJC },
+ { "readwrite", RID_READWRITE, D_OBJC },
+ { "retain", RID_RETAIN, D_OBJC },
+ { "setter", RID_SETTER, D_OBJC },
};
const unsigned int num_c_common_reswords =
/* Table of machine-independent attributes common to all C-like languages. */
const struct attribute_spec c_common_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
{ "packed", 0, 0, false, false, false,
- handle_packed_attribute },
+ handle_packed_attribute , false},
{ "nocommon", 0, 0, true, false, false,
- handle_nocommon_attribute },
+ handle_nocommon_attribute, false},
{ "common", 0, 0, true, false, false,
- handle_common_attribute },
+ handle_common_attribute, false },
/* FIXME: logically, noreturn attributes should be listed as
"false, true, true" and apply to function types. But implementing this
would require all the places in the compiler that use TREE_THIS_VOLATILE
on a decl to identify non-returning functions to be located and fixed
to check the function type instead. */
{ "noreturn", 0, 0, true, false, false,
- handle_noreturn_attribute },
+ handle_noreturn_attribute, false },
{ "volatile", 0, 0, true, false, false,
- handle_noreturn_attribute },
+ handle_noreturn_attribute, false },
{ "noinline", 0, 0, true, false, false,
- handle_noinline_attribute },
+ handle_noinline_attribute, false },
{ "noclone", 0, 0, true, false, false,
- handle_noclone_attribute },
+ handle_noclone_attribute, false },
{ "leaf", 0, 0, true, false, false,
- handle_leaf_attribute },
+ handle_leaf_attribute, false },
{ "always_inline", 0, 0, true, false, false,
- handle_always_inline_attribute },
+ handle_always_inline_attribute, false },
{ "gnu_inline", 0, 0, true, false, false,
- handle_gnu_inline_attribute },
+ handle_gnu_inline_attribute, false },
{ "artificial", 0, 0, true, false, false,
- handle_artificial_attribute },
+ handle_artificial_attribute, false },
{ "flatten", 0, 0, true, false, false,
- handle_flatten_attribute },
+ handle_flatten_attribute, false },
{ "used", 0, 0, true, false, false,
- handle_used_attribute },
+ handle_used_attribute, false },
{ "unused", 0, 0, false, false, false,
- handle_unused_attribute },
+ handle_unused_attribute, false },
{ "externally_visible", 0, 0, true, false, false,
- handle_externally_visible_attribute },
+ handle_externally_visible_attribute, false },
/* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false,
- handle_const_attribute },
+ handle_const_attribute, false },
{ "transparent_union", 0, 0, false, false, false,
- handle_transparent_union_attribute },
+ handle_transparent_union_attribute, false },
{ "constructor", 0, 1, true, false, false,
- handle_constructor_attribute },
+ handle_constructor_attribute, false },
{ "destructor", 0, 1, true, false, false,
- handle_destructor_attribute },
+ handle_destructor_attribute, false },
{ "mode", 1, 1, false, true, false,
- handle_mode_attribute },
+ handle_mode_attribute, false },
{ "section", 1, 1, true, false, false,
- handle_section_attribute },
+ handle_section_attribute, false },
{ "aligned", 0, 1, false, false, false,
- handle_aligned_attribute },
+ handle_aligned_attribute, false },
{ "weak", 0, 0, true, false, false,
- handle_weak_attribute },
+ handle_weak_attribute, false },
{ "ifunc", 1, 1, true, false, false,
- handle_ifunc_attribute },
+ handle_ifunc_attribute, false },
{ "alias", 1, 1, true, false, false,
- handle_alias_attribute },
+ handle_alias_attribute, false },
{ "weakref", 0, 1, true, false, false,
- handle_weakref_attribute },
+ handle_weakref_attribute, false },
{ "no_instrument_function", 0, 0, true, false, false,
- handle_no_instrument_function_attribute },
+ handle_no_instrument_function_attribute,
+ false },
{ "malloc", 0, 0, true, false, false,
- handle_malloc_attribute },
+ handle_malloc_attribute, false },
{ "returns_twice", 0, 0, true, false, false,
- handle_returns_twice_attribute },
+ handle_returns_twice_attribute, false },
{ "no_stack_limit", 0, 0, true, false, false,
- handle_no_limit_stack_attribute },
+ handle_no_limit_stack_attribute, false },
{ "pure", 0, 0, true, false, false,
- handle_pure_attribute },
+ handle_pure_attribute, false },
/* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */
{ "no vops", 0, 0, true, false, false,
- handle_novops_attribute },
+ handle_novops_attribute, false },
{ "deprecated", 0, 1, false, false, false,
- handle_deprecated_attribute },
+ handle_deprecated_attribute, false },
{ "vector_size", 1, 1, false, true, false,
- handle_vector_size_attribute },
+ handle_vector_size_attribute, false },
{ "visibility", 1, 1, false, false, false,
- handle_visibility_attribute },
+ handle_visibility_attribute, false },
{ "tls_model", 1, 1, true, false, false,
- handle_tls_model_attribute },
+ handle_tls_model_attribute, false },
{ "nonnull", 0, -1, false, true, true,
- handle_nonnull_attribute },
+ handle_nonnull_attribute, false },
{ "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute },
- { "may_alias", 0, 0, false, true, false, NULL },
+ handle_nothrow_attribute, false },
+ { "may_alias", 0, 0, false, true, false, NULL, false },
{ "cleanup", 1, 1, true, false, false,
- handle_cleanup_attribute },
+ handle_cleanup_attribute, false },
{ "warn_unused_result", 0, 0, false, true, true,
- handle_warn_unused_result_attribute },
+ handle_warn_unused_result_attribute, false },
{ "sentinel", 0, 1, false, true, true,
- handle_sentinel_attribute },
+ handle_sentinel_attribute, false },
/* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */
{ "type generic", 0, 0, false, true, true,
- handle_type_generic_attribute },
+ handle_type_generic_attribute, false },
{ "alloc_size", 1, 2, false, true, true,
- handle_alloc_size_attribute },
+ handle_alloc_size_attribute, false },
{ "cold", 0, 0, true, false, false,
- handle_cold_attribute },
+ handle_cold_attribute, false },
{ "hot", 0, 0, true, false, false,
- handle_hot_attribute },
+ handle_hot_attribute, false },
{ "warning", 1, 1, true, false, false,
- handle_error_attribute },
+ handle_error_attribute, false },
{ "error", 1, 1, true, false, false,
- handle_error_attribute },
+ handle_error_attribute, false },
{ "target", 1, -1, true, false, false,
- handle_target_attribute },
+ handle_target_attribute, false },
{ "optimize", 1, -1, true, false, false,
- handle_optimize_attribute },
+ handle_optimize_attribute, false },
{ "no_split_stack", 0, 0, true, false, false,
- handle_no_split_stack_attribute },
+ handle_no_split_stack_attribute, false },
/* For internal use (marking of builtins and runtime functions) only.
The name contains space to prevent its usage in source code. */
{ "fn spec", 1, 1, false, true, true,
- handle_fnspec_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ handle_fnspec_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
};
/* Give the specifications for the format attributes, used by C and all
const struct attribute_spec c_common_format_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
{ "format", 3, 3, false, true, true,
- handle_format_attribute },
+ handle_format_attribute, false },
{ "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ handle_format_arg_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
};
/* Return identifier for address space AS. */
if (decl)
{
- saved = tree_cons (decl, build_int_cst (NULL_TREE, ix), saved);
+ saved = tree_cons (decl, build_int_cst (integer_type_node, ix),
+ saved);
*fname_vars[ix].decl = NULL_TREE;
}
}
construct the matching unqualified array type first. The C front
end does not require this, but it does no harm, so we do it
unconditionally. */
- i_type = build_index_type (build_int_cst (NULL_TREE, nchars - 1));
+ i_type = build_index_type (size_int (nchars - 1));
a_type = build_array_type (e_type, i_type);
if (c_dialect_cxx() || warn_write_strings)
a_type = c_build_qualified_type (a_type, TYPE_QUAL_CONST);
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
CASE_CONVERT:
+ case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
case NEGATE_EXPR:
case BIT_NOT_EXPR:
void
check_main_parameter_types (tree decl)
{
- tree args;
+ function_args_iterator iter;
+ tree type;
int argct = 0;
- for (args = TYPE_ARG_TYPES (TREE_TYPE (decl)); args;
- args = TREE_CHAIN (args))
- {
- tree type = args ? TREE_VALUE (args) : 0;
-
- if (type == void_type_node || type == error_mark_node )
- break;
-
- ++argct;
- switch (argct)
- {
- case 1:
- if (TYPE_MAIN_VARIANT (type) != integer_type_node)
- pedwarn (input_location, OPT_Wmain, "first argument of %q+D should be %<int%>",
- decl);
- break;
-
- case 2:
- if (TREE_CODE (type) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
- != char_type_node))
- pedwarn (input_location, OPT_Wmain, "second argument of %q+D should be %<char **%>",
- decl);
- break;
-
- case 3:
- if (TREE_CODE (type) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
- != char_type_node))
- pedwarn (input_location, OPT_Wmain, "third argument of %q+D should probably be "
- "%<char **%>", decl);
- break;
- }
- }
+ FOREACH_FUNCTION_ARGS (TREE_TYPE (decl), type, iter)
+ {
+ /* XXX void_type_node belies the abstraction. */
+ if (type == void_type_node || type == error_mark_node )
+ break;
+
+ ++argct;
+ switch (argct)
+ {
+ case 1:
+ if (TYPE_MAIN_VARIANT (type) != integer_type_node)
+ pedwarn (input_location, OPT_Wmain,
+ "first argument of %q+D should be %<int%>", decl);
+ break;
+
+ case 2:
+ if (TREE_CODE (type) != POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+ != char_type_node))
+ pedwarn (input_location, OPT_Wmain,
+ "second argument of %q+D should be %<char **%>", decl);
+ break;
+
+ case 3:
+ if (TREE_CODE (type) != POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+ != char_type_node))
+ pedwarn (input_location, OPT_Wmain,
+ "third argument of %q+D should probably be "
+ "%<char **%>", decl);
+ break;
+ }
+ }
/* It is intentional that this message does not mention the third
argument because it's only mentioned in an appendix of the
standard. */
if (argct > 0 && (argct < 2 || argct > 3))
- pedwarn (input_location, OPT_Wmain, "%q+D takes only zero or two arguments", decl);
+ pedwarn (input_location, OPT_Wmain,
+ "%q+D takes only zero or two arguments", decl);
}
/* True if pointers to distinct types T1 and T2 can be converted to
return false;
}
+/* Like tree.c:get_narrower, but retain conversion from C++0x scoped enum
+ to integral type. */
+
+static tree
+c_common_get_narrower (tree op, int *unsignedp_ptr)
+{
+ op = get_narrower (op, unsignedp_ptr);
+
+ if (TREE_CODE (TREE_TYPE (op)) == ENUMERAL_TYPE
+ && ENUM_IS_SCOPED (TREE_TYPE (op)))
+ {
+ /* C++0x scoped enumerations don't implicitly convert to integral
+ type; if we stripped an explicit conversion to a larger type we
+ need to replace it so common_type will still work. */
+ tree type = (lang_hooks.types.type_for_size
+ (TYPE_PRECISION (TREE_TYPE (op)),
+ TYPE_UNSIGNED (TREE_TYPE (op))));
+ op = fold_convert (type, op);
+ }
+ return op;
+}
+
/* This is a helper function of build_binary_op.
For certain operations if both args were extended from the same
Eg, (short)-1 | (unsigned short)-1 is (int)-1
but calculated in (unsigned short) it would be (unsigned short)-1.
*/
-tree shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
+tree
+shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
{
int unsigned0, unsigned1;
tree arg0, arg1;
op0 = convert (result_type, op0);
op1 = convert (result_type, op1);
- arg0 = get_narrower (op0, &unsigned0);
- arg1 = get_narrower (op1, &unsigned1);
+ arg0 = c_common_get_narrower (op0, &unsigned0);
+ arg1 = c_common_get_narrower (op1, &unsigned1);
/* UNS is 1 if the operation to be done is an unsigned one. */
uns = TYPE_UNSIGNED (result_type);
int i;
const int expr_num_operands = TREE_OPERAND_LENGTH (expr);
tree expr_type = TREE_TYPE (expr);
- location_t loc = EXPR_HAS_LOCATION (expr)
- ? EXPR_LOCATION (expr) : input_location;
+ location_t loc = EXPR_LOC_OR_HERE (expr);
if (!warn_conversion && !warn_sign_conversion)
return;
&& (!only_writes || list->writer))
{
warned_ids = new_tlist (warned_ids, written, NULL_TREE);
- warning_at (EXPR_HAS_LOCATION (writer)
- ? EXPR_LOCATION (writer) : input_location,
+ warning_at (EXPR_LOC_OR_HERE (writer),
OPT_Wsequence_point, "operation on %qE may be undefined",
list->expr);
}
static int
warning_candidate_p (tree x)
{
- /* !VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c
+ if (DECL_P (x) && DECL_ARTIFICIAL (x))
+ return 0;
+
+ if (TREE_CODE (x) == BLOCK)
+ return 0;
+
+ /* VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c
(lvalue_p) crash on TRY/CATCH. */
- return !(DECL_P (x) && DECL_ARTIFICIAL (x))
- && TREE_TYPE (x) && !VOID_TYPE_P (TREE_TYPE (x)) && lvalue_p (x);
+ if (TREE_TYPE (x) == NULL_TREE || VOID_TYPE_P (TREE_TYPE (x)))
+ return 0;
+
+ if (!lvalue_p (x))
+ return 0;
+
+ /* No point to track non-const calls, they will never satisfy
+ operand_equal_p. */
+ if (TREE_CODE (x) == CALL_EXPR && (call_expr_flags (x) & ECF_CONST) == 0)
+ return 0;
+
+ if (TREE_CODE (x) == STRING_CST)
+ return 0;
+
+ return 1;
}
/* Return nonzero if X and Y appear to be the same candidate (or NULL) */
if (value == NULL_TREE)
return value;
- /* ??? Can we ever get nops here for a valid case value? We
- shouldn't for C. */
- STRIP_TYPE_NOPS (value);
- /* In C++, the following is allowed:
-
- const int i = 3;
- switch (...) { case i: ... }
-
- So, we try to reduce the VALUE to a constant that way. */
- if (c_dialect_cxx ())
- {
- value = decl_constant_value (value);
- STRIP_TYPE_NOPS (value);
- value = fold (value);
- }
-
if (TREE_CODE (value) == INTEGER_CST)
/* Promote char or short to int. */
value = perform_integral_promotions (value);
/* Throw away any conversions to wider types
already present in the operands. */
- primop0 = get_narrower (op0, &unsignedp0);
- primop1 = get_narrower (op1, &unsignedp1);
+ primop0 = c_common_get_narrower (op0, &unsignedp0);
+ primop1 = c_common_get_narrower (op1, &unsignedp1);
+
+ /* If primopN is first sign-extended from primopN's precision to opN's
+ precision, then zero-extended from opN's precision to
+ *restype_ptr precision, shortenings might be invalid. */
+ if (TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (TREE_TYPE (op0))
+ && TYPE_PRECISION (TREE_TYPE (op0)) < TYPE_PRECISION (*restype_ptr)
+ && !unsignedp0
+ && TYPE_UNSIGNED (TREE_TYPE (op0)))
+ primop0 = op0;
+ if (TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (TREE_TYPE (op1))
+ && TYPE_PRECISION (TREE_TYPE (op1)) < TYPE_PRECISION (*restype_ptr)
+ && !unsignedp1
+ && TYPE_UNSIGNED (TREE_TYPE (op1)))
+ primop1 = op1;
/* Handle the case that OP0 does not *contain* a conversion
but it *requires* conversion to FINAL_TYPE. */
/* Distribute the conversion into the arms of a COND_EXPR. */
if (c_dialect_cxx ())
{
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ /* In C++ one of the arms might have void type if it is throw. */
+ if (!VOID_TYPE_P (TREE_TYPE (op1)))
+ op1 = c_common_truthvalue_conversion (location, op1);
+ if (!VOID_TYPE_P (TREE_TYPE (op2)))
+ op2 = c_common_truthvalue_conversion (location, op2);
expr = fold_build3_loc (location, COND_EXPR, truthvalue_type_node,
- TREE_OPERAND (expr, 0),
- c_common_truthvalue_conversion (location,
- TREE_OPERAND (expr,
- 1)),
- c_common_truthvalue_conversion (location,
- TREE_OPERAND (expr,
- 2)));
+ TREE_OPERAND (expr, 0), op1, op2);
goto ret;
}
else
}
CASE_CONVERT:
- /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
- since that affects how `default_conversion' will behave. */
- if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
- || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
- break;
- /* If this is widening the argument, we can ignore it. */
- if (TYPE_PRECISION (TREE_TYPE (expr))
- >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
- return c_common_truthvalue_conversion (location,
- TREE_OPERAND (expr, 0));
+ {
+ tree totype = TREE_TYPE (expr);
+ tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0));
+
+ /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+ since that affects how `default_conversion' will behave. */
+ if (TREE_CODE (totype) == REFERENCE_TYPE
+ || TREE_CODE (fromtype) == REFERENCE_TYPE)
+ break;
+ /* Don't strip a conversion from C++0x scoped enum, since they
+ don't implicitly convert to other types. */
+ if (TREE_CODE (fromtype) == ENUMERAL_TYPE
+ && ENUM_IS_SCOPED (fromtype))
+ break;
+ /* If this isn't narrowing the argument, we can ignore it. */
+ if (TYPE_PRECISION (totype) >= TYPE_PRECISION (fromtype))
+ return c_common_truthvalue_conversion (location,
+ TREE_OPERAND (expr, 0));
+ }
break;
case MODIFY_EXPR:
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
- tree t = c_save_expr (expr);
+ tree t = (in_late_binary_op ? save_expr (expr) : c_save_expr (expr));
expr = (build_binary_op
(EXPR_LOCATION (expr),
(TREE_SIDE_EFFECTS (expr)
static hashval_t
c_type_hash (const void *p)
{
- int i = 0;
+ int n_elements;
int shift, size;
const_tree const t = (const_tree) p;
tree t2;
default:
gcc_unreachable ();
}
- for (; t2; t2 = DECL_CHAIN (t2))
- i++;
+ /* FIXME: We want to use a DECL_CHAIN iteration method here, but
+ TYPE_VALUES of ENUMERAL_TYPEs is stored as a TREE_LIST. */
+ n_elements = list_length (t2);
/* We might have a VLA here. */
if (TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST)
size = 0;
else
size = TREE_INT_CST_LOW (TYPE_SIZE (t));
- return ((size << 24) | (i << shift));
+ return ((size << 24) | (n_elements << shift));
}
static GTY((param_is (union tree_node))) htab_t type_hash_table;
static void
def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
{
- tree args = NULL, t;
+ tree t;
+ tree *args = XALLOCAVEC (tree, n);
va_list list;
int i;
t = builtin_types[a];
if (t == error_mark_node)
goto egress;
- args = tree_cons (NULL_TREE, t, args);
+ args[i] = t;
}
- va_end (list);
-
- args = nreverse (args);
- if (!var)
- args = chainon (args, void_list_node);
t = builtin_types[ret];
if (t == error_mark_node)
goto egress;
- t = build_function_type (t, args);
+ if (var)
+ t = build_varargs_function_type_array (t, n, args);
+ else
+ t = build_function_type_array (t, n, args);
egress:
builtin_types[def] = t;
+ va_end (list);
}
/* Build builtin functions common to both C and C++ language
uintptr_type_node =
TREE_TYPE (identifier_global_value (c_get_ident (UINTPTR_TYPE)));
- default_function_type = build_function_type (integer_type_node, NULL_TREE);
+ default_function_type
+ = build_varargs_function_type_list (integer_type_node, NULL_TREE);
ptrdiff_type_node
= TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
}
/* Add a CASE_LABEL to the statement-tree. */
- case_label = add_stmt (build_case_label (loc, low_value, high_value, label));
+ case_label = add_stmt (build_case_label (low_value, high_value, label));
/* Register this case label in the splay tree. */
splay_tree_insert (cases,
(splay_tree_key) low_value,
#define DEF_ATTR_NULL_TREE(ENUM) \
built_in_attributes[(int) ENUM] = NULL_TREE;
#define DEF_ATTR_INT(ENUM, VALUE) \
- built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
+ built_in_attributes[(int) ENUM] = build_int_cst (integer_type_node, VALUE);
#define DEF_ATTR_IDENT(ENUM, STRING) \
built_in_attributes[(int) ENUM] = get_identifier (STRING);
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
bool
attribute_takes_identifier_p (const_tree attr_id)
{
- if (is_attribute_p ("mode", attr_id)
- || is_attribute_p ("format", attr_id)
- || is_attribute_p ("cleanup", attr_id))
+ const struct attribute_spec *spec = lookup_attribute_spec (attr_id);
+ if (spec == NULL)
+ /* Unknown attribute that we'll end up ignoring, return true so we
+ don't complain about an identifier argument. */
+ return true;
+ else if (!strcmp ("mode", spec->name)
+ || !strcmp ("format", spec->name)
+ || !strcmp ("cleanup", spec->name))
return true;
else
return targetm.attribute_takes_identifier_p (attr_id);
tree type = TREE_TYPE (*node);
/* See FIXME comment in c_common_attribute_table. */
- if (TREE_CODE (*node) == FUNCTION_DECL)
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ || objc_method_decl (TREE_CODE (*node)))
TREE_THIS_VOLATILE (*node) = 1;
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
{
if (TYPE_FIELDS (type) == NULL_TREE
+ || c_dialect_cxx ()
|| TYPE_MODE (type) != DECL_MODE (TYPE_FIELDS (type)))
goto ignored;
if (ALL_FIXED_POINT_MODE_P (mode)
&& TYPE_UNSIGNED (type) != UNSIGNED_FIXED_POINT_MODE_P (mode))
{
- error ("signness of type and machine mode %qs don't match", p);
+ error ("signedness of type and machine mode %qs don%'t match", p);
return NULL_TREE;
}
/* For fixed-point modes, we need to pass saturating info. */
if (TREE_CODE (*node) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (*node))
{
- error ("inline function %q+D cannot be declared weak", *node);
+ warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
*no_add_attrs = true;
}
else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
will have the correct types when we actually check them later. */
if (!args)
{
- if (!TYPE_ARG_TYPES (type))
+ if (!prototype_p (type))
{
error ("nonnull attribute without arguments on a non-prototype");
*no_add_attrs = true;
a pointer argument. */
for (attr_arg_num = 1; args; args = TREE_CHAIN (args))
{
- tree argument;
unsigned HOST_WIDE_INT arg_num = 0, ck_num;
if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
return NULL_TREE;
}
- argument = TYPE_ARG_TYPES (type);
- if (argument)
+ if (prototype_p (type))
{
- for (ck_num = 1; ; ck_num++)
+ function_args_iterator iter;
+ tree argument;
+
+ function_args_iter_init (&iter, type);
+ for (ck_num = 1; ; ck_num++, function_args_iter_next (&iter))
{
- if (!argument || ck_num == arg_num)
+ argument = function_args_iter_cond (&iter);
+ if (argument == NULL_TREE || ck_num == arg_num)
break;
- argument = TREE_CHAIN (argument);
}
if (!argument
- || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
+ || TREE_CODE (argument) == VOID_TYPE)
{
error ("nonnull argument with out-of-range operand number (argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
return NULL_TREE;
}
- if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
+ if (TREE_CODE (argument) != POINTER_TYPE)
{
error ("nonnull argument references non-pointer operand (argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
array ARGARRAY. */
static void
-check_function_sentinel (tree attrs, int nargs, tree *argarray, tree typelist)
+check_function_sentinel (const_tree fntype, int nargs, tree *argarray)
{
- tree attr = lookup_attribute ("sentinel", attrs);
+ tree attr = lookup_attribute ("sentinel", TYPE_ATTRIBUTES (fntype));
if (attr)
{
int len = 0;
int pos = 0;
tree sentinel;
+ function_args_iterator iter;
+ tree t;
/* Skip over the named arguments. */
- while (typelist && len < nargs)
+ FOREACH_FUNCTION_ARGS (fntype, t, iter)
{
- typelist = TREE_CHAIN (typelist);
+ if (len == nargs)
+ break;
len++;
}
handle_sentinel_attribute (tree *node, tree name, tree args,
int ARG_UNUSED (flags), bool *no_add_attrs)
{
- tree params = TYPE_ARG_TYPES (*node);
-
- if (!params)
+ if (!prototype_p (*node))
{
warning (OPT_Wattributes,
"%qE attribute requires prototypes with named arguments", name);
}
else
{
- while (TREE_CHAIN (params))
- params = TREE_CHAIN (params);
-
- if (VOID_TYPE_P (TREE_VALUE (params)))
+ if (!stdarg_p (*node))
{
warning (OPT_Wattributes,
"%qE attribute only applies to variadic functions", name);
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs))
{
- tree params;
-
/* Ensure we have a function type. */
gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
- params = TYPE_ARG_TYPES (*node);
- while (params && ! VOID_TYPE_P (TREE_VALUE (params)))
- params = TREE_CHAIN (params);
-
/* Ensure we have a variadic function. */
- gcc_assert (!params);
+ gcc_assert (!prototype_p (*node) || stdarg_p (*node));
return NULL_TREE;
}
&decoded_options,
&decoded_options_count);
decode_options (&global_options, &global_options_set,
- decoded_options, decoded_options_count);
+ decoded_options, decoded_options_count,
+ input_location, global_dc);
targetm.override_options_after_change();
return NULL_TREE;
}
\f
-/* Check for valid arguments being passed to a function.
- ATTRS is a list of attributes. There are NARGS arguments in the array
- ARGARRAY. TYPELIST is the list of argument types for the function.
- */
+/* Check for valid arguments being passed to a function with FNTYPE.
+ There are NARGS arguments in the array ARGARRAY. */
void
-check_function_arguments (tree attrs, int nargs, tree *argarray, tree typelist)
+check_function_arguments (const_tree fntype, int nargs, tree *argarray)
{
/* Check for null being passed in a pointer argument that must be
non-null. We also need to do this if format checking is enabled. */
if (warn_nonnull)
- check_function_nonnull (attrs, nargs, argarray);
+ check_function_nonnull (TYPE_ATTRIBUTES (fntype), nargs, argarray);
/* Check for errors in format strings. */
if (warn_format || warn_missing_format_attribute)
- check_function_format (attrs, nargs, argarray);
+ check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray);
if (warn_format)
- check_function_sentinel (attrs, nargs, argarray, typelist);
+ check_function_sentinel (fntype, nargs, argarray);
}
/* Generic argument checking recursion routine. PARAM is the argument to
"suggest explicit middle operand");
}
+/* Give an error for storing into ARG, which is 'const'. USE indicates
+ how ARG was being used. */
+
+void
+readonly_error (tree arg, enum lvalue_use use)
+{
+ gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
+ || use == lv_asm);
+ /* Using this macro rather than (for example) arrays of messages
+ ensures that all the format strings are checked at compile
+ time. */
+#define READONLY_MSG(A, I, D, AS) (use == lv_assign ? (A) \
+ : (use == lv_increment ? (I) \
+ : (use == lv_decrement ? (D) : (AS))))
+ if (TREE_CODE (arg) == COMPONENT_REF)
+ {
+ if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
+ error (READONLY_MSG (G_("assignment of member "
+ "%qD in read-only object"),
+ G_("increment of member "
+ "%qD in read-only object"),
+ G_("decrement of member "
+ "%qD in read-only object"),
+ G_("member %qD in read-only object "
+ "used as %<asm%> output")),
+ TREE_OPERAND (arg, 1));
+ else
+ error (READONLY_MSG (G_("assignment of read-only member %qD"),
+ G_("increment of read-only member %qD"),
+ G_("decrement of read-only member %qD"),
+ G_("read-only member %qD used as %<asm%> output")),
+ TREE_OPERAND (arg, 1));
+ }
+ else if (TREE_CODE (arg) == VAR_DECL)
+ error (READONLY_MSG (G_("assignment of read-only variable %qD"),
+ G_("increment of read-only variable %qD"),
+ G_("decrement of read-only variable %qD"),
+ G_("read-only variable %qD used as %<asm%> output")),
+ arg);
+ else if (TREE_CODE (arg) == PARM_DECL)
+ error (READONLY_MSG (G_("assignment of read-only parameter %qD"),
+ G_("increment of read-only parameter %qD"),
+ G_("decrement of read-only parameter %qD"),
+ G_("read-only parameter %qD use as %<asm%> output")),
+ arg);
+ else if (TREE_CODE (arg) == RESULT_DECL)
+ {
+ gcc_assert (c_dialect_cxx ());
+ error (READONLY_MSG (G_("assignment of "
+ "read-only named return value %qD"),
+ G_("increment of "
+ "read-only named return value %qD"),
+ G_("decrement of "
+ "read-only named return value %qD"),
+ G_("read-only named return value %qD "
+ "used as %<asm%>output")),
+ arg);
+ }
+ else if (TREE_CODE (arg) == FUNCTION_DECL)
+ error (READONLY_MSG (G_("assignment of function %qD"),
+ G_("increment of function %qD"),
+ G_("decrement of function %qD"),
+ G_("function %qD used as %<asm%> output")),
+ arg);
+ else
+ error (READONLY_MSG (G_("assignment of read-only location %qE"),
+ G_("increment of read-only location %qE"),
+ G_("decrement of read-only location %qE"),
+ G_("read-only location %qE used as %<asm%> output")),
+ arg);
+}
+
/* Print an error message for an invalid lvalue. USE says
- how the lvalue is being used and so selects the error message. */
+ how the lvalue is being used and so selects the error message. LOC
+ is the location for the error. */
void
-lvalue_error (enum lvalue_use use)
+lvalue_error (location_t loc, enum lvalue_use use)
{
switch (use)
{
case lv_assign:
- error ("lvalue required as left operand of assignment");
+ error_at (loc, "lvalue required as left operand of assignment");
break;
case lv_increment:
- error ("lvalue required as increment operand");
+ error_at (loc, "lvalue required as increment operand");
break;
case lv_decrement:
- error ("lvalue required as decrement operand");
+ error_at (loc, "lvalue required as decrement operand");
break;
case lv_addressof:
- error ("lvalue required as unary %<&%> operand");
+ error_at (loc, "lvalue required as unary %<&%> operand");
break;
case lv_asm:
- error ("lvalue required in asm statement");
+ error_at (loc, "lvalue required in asm statement");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Print an error message for an invalid indirection of type TYPE.
+ ERRSTRING is the name of the operator for the indirection. */
+
+void
+invalid_indirection_error (location_t loc, tree type, ref_operator errstring)
+{
+ switch (errstring)
+ {
+ case RO_NULL:
+ gcc_assert (c_dialect_cxx ());
+ error_at (loc, "invalid type argument (have %qT)", type);
+ break;
+ case RO_ARRAY_INDEXING:
+ error_at (loc,
+ "invalid type argument of array indexing (have %qT)",
+ type);
+ break;
+ case RO_UNARY_STAR:
+ error_at (loc,
+ "invalid type argument of unary %<*%> (have %qT)",
+ type);
+ break;
+ case RO_ARROW:
+ error_at (loc,
+ "invalid type argument of %<->%> (have %qT)",
+ type);
+ break;
+ case RO_IMPLICIT_CONVERSION:
+ error_at (loc,
+ "invalid type argument of implicit conversion (have %qT)",
+ type);
break;
default:
gcc_unreachable ();
TYPE_LANG_FLAG_? bits that the front end may have set. */
main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
TREE_TYPE (main_type) = unqual_elt;
- TYPE_DOMAIN (main_type) = build_index_type (maxindex);
+ TYPE_DOMAIN (main_type)
+ = build_range_type (TREE_TYPE (maxindex),
+ build_int_cst (TREE_TYPE (maxindex), 0), maxindex);
layout_type (main_type);
/* Make sure we have the canonical MAIN_TYPE. */
return failure;
}
+/* Like c_mark_addressable but don't check register qualifier. */
+void
+c_common_mark_addressable_vec (tree t)
+{
+ while (handled_component_p (t))
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ return;
+ TREE_ADDRESSABLE (t) = 1;
+}
+
+
\f
/* Used to help initialize the builtin-types.def table. When a type of
the correct size doesn't exist, use error_mark_node instead of NULL.
static bool
sync_resolve_params (tree orig_function, tree function, VEC(tree, gc) *params)
{
- tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
+ function_args_iterator iter;
tree ptype;
unsigned int parmnum;
+ function_args_iter_init (&iter, TREE_TYPE (function));
/* We've declared the implementation functions to use "volatile void *"
as the pointer parameter, so we shouldn't get any complaints from the
call to check_function_arguments what ever type the user used. */
- arg_types = TREE_CHAIN (arg_types);
+ function_args_iter_next (&iter);
ptype = TREE_TYPE (TREE_TYPE (VEC_index (tree, params, 0)));
/* For the rest of the values, we need to cast these to FTYPE, so that we
don't get warnings for passing pointer types, etc. */
parmnum = 0;
- while (arg_types != void_list_node)
+ while (1)
{
- tree val;
+ tree val, arg_type;
+
+ arg_type = function_args_iter_cond (&iter);
+ /* XXX void_type_node belies the abstraction. */
+ if (arg_type == void_type_node)
+ break;
++parmnum;
if (VEC_length (tree, params) <= parmnum)
type. This isn't portable across the C and C++ front ends atm. */
val = VEC_index (tree, params, parmnum);
val = convert (ptype, val);
- val = convert (TREE_VALUE (arg_types), val);
+ val = convert (arg_type, val);
VEC_replace (tree, params, parmnum, val);
- arg_types = TREE_CHAIN (arg_types);
+ function_args_iter_next (&iter);
}
/* The definition of these primitives is variadic, with the remaining
}
}
-#ifndef TARGET_HAS_TARGETCM
-struct gcc_targetcm targetcm = TARGETCM_INITIALIZER;
-#endif
-
/* Warn for division by zero according to the value of DIVISOR. LOC
is the location of the division operator. */
have all bits set that are set in the ~ operand when it is
extended. */
- op0 = get_narrower (op0, &unsignedp0);
- op1 = get_narrower (op1, &unsignedp1);
+ op0 = c_common_get_narrower (op0, &unsignedp0);
+ op1 = c_common_get_narrower (op1, &unsignedp1);
if ((TREE_CODE (op0) == BIT_NOT_EXPR)
^ (TREE_CODE (op1) == BIT_NOT_EXPR))
{
if (TREE_CODE (op0) == BIT_NOT_EXPR)
- op0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
+ op0 = c_common_get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
if (TREE_CODE (op1) == BIT_NOT_EXPR)
- op1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
+ op1 = c_common_get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
if (host_integerp (op0, 0) || host_integerp (op1, 0))
{
return ret;
}
+/* Get a new tree vector of the TREE_VALUEs of a TREE_LIST chain. */
+
+VEC(tree,gc) *
+make_tree_vector_from_list (tree list)
+{
+ VEC(tree,gc) *ret = make_tree_vector ();
+ for (; list; list = TREE_CHAIN (list))
+ VEC_safe_push (tree, gc, ret, TREE_VALUE (list));
+ return ret;
+}
+
/* Get a new tree vector which is a copy of an existing one. */
VEC(tree,gc) *
return ret;
}
+/* Return true if KEYWORD starts a type specifier. */
+
+bool
+keyword_begins_type_specifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_INT128:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_BOOL:
+ case RID_WCHAR:
+ case RID_CHAR16:
+ case RID_CHAR32:
+ case RID_SAT:
+ case RID_COMPLEX:
+ case RID_TYPEOF:
+ case RID_STRUCT:
+ case RID_CLASS:
+ case RID_UNION:
+ case RID_ENUM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a type qualifier. */
+
+bool
+keyword_is_type_qualifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a storage class specifier.
+
+ RID_TYPEDEF is not included in this list despite `typedef' being
+ listed in C99 6.7.1.1. 6.7.1.3 indicates that `typedef' is listed as
+ such for syntactic convenience only. */
+
+bool
+keyword_is_storage_class_specifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_AUTO:
+ case RID_MUTABLE:
+ case RID_THREAD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a function-specifier [dcl.fct.spec]. */
+
+static bool
+keyword_is_function_specifier (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_INLINE:
+ case RID_VIRTUAL:
+ case RID_EXPLICIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return true if KEYWORD names a decl-specifier [dcl.spec] or a
+ declaration-specifier (C99 6.7). */
+
+bool
+keyword_is_decl_specifier (enum rid keyword)
+{
+ if (keyword_is_storage_class_specifier (keyword)
+ || keyword_is_type_qualifier (keyword)
+ || keyword_is_function_specifier (keyword))
+ return true;
+
+ switch (keyword)
+ {
+ case RID_TYPEDEF:
+ case RID_FRIEND:
+ case RID_CONSTEXPR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Initialize language-specific-bits of tree_contains_struct. */
+
+void
+c_common_init_ts (void)
+{
+ MARK_TS_TYPED (C_MAYBE_CONST_EXPR);
+ MARK_TS_TYPED (EXCESS_PRECISION_EXPR);
+}
+
#include "gt-c-family-c-common.h"