#endif
#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "c-family/c-pragma.h"
#include "c-family/c-format.h"
#include "flags.h"
static char *errbuf; /* Buffer for error diagnostics */
+/* An array of all the local variables in the current function that
+ need to be marked as volatile. */
+VEC(tree,gc) *local_variables_to_volatilize = NULL;
+
\f
static int flag_typed_selectors;
/* An existing property was found; check that it has the same
types, or it is compatible. */
location_t original_location = DECL_SOURCE_LOCATION (x);
-
+
if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic)
{
warning_at (location, 0,
PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
PROPERTY_DYNAMIC (property_decl) = 0;
+ /* Remember the fact that the property was found in the @optional
+ section in a @protocol, or not. */
+ if (objc_method_optional_flag)
+ PROPERTY_OPTIONAL (property_decl) = 1;
+ else
+ PROPERTY_OPTIONAL (property_decl) = 0;
+
/* Note that PROPERTY_GETTER_NAME is always set for all
PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all
PROPERTY_DECLs where PROPERTY_READONLY == 0. Any time we deal
in the implementation, and failing that, the protocol list)
provided for a 'setter' or 'getter' for 'component' with default
names (ie, if 'component' is "name", then search for "name" and
- "setName:"). If any is found, then create an artificial property
- that uses them. Return NULL_TREE if 'getter' or 'setter' could not
- be found. */
+ "setName:"). It is also possible to specify a different
+ 'getter_name' (this is used for @optional readonly properties). If
+ any is found, then create an artificial property that uses them.
+ Return NULL_TREE if 'getter' or 'setter' could not be found. */
static tree
maybe_make_artificial_property_decl (tree interface, tree implementation,
- tree protocol_list, tree component, bool is_class)
+ tree protocol_list, tree component, bool is_class,
+ tree getter_name)
{
- tree getter_name = component;
tree setter_name = get_identifier (objc_build_property_setter_name (component));
tree getter = NULL_TREE;
tree setter = NULL_TREE;
+ if (getter_name == NULL_TREE)
+ getter_name = component;
+
/* First, check the @interface and all superclasses. */
if (interface)
{
PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0;
PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
PROPERTY_DYNAMIC (property_decl) = 0;
+ PROPERTY_OPTIONAL (property_decl) = 0;
if (!getter)
PROPERTY_HAS_NO_GETTER (property_decl) = 1;
properties. */
if (!IS_CLASS (rtype))
x = lookup_property_in_protocol_list (rprotos, property_ident);
-
+
if (x == NULL_TREE)
{
/* Ok, no property. Maybe it was an
NULL_TREE,
rprotos,
property_ident,
- IS_CLASS (rtype));
+ IS_CLASS (rtype),
+ NULL_TREE);
+ }
+ else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+ {
+ /* This is a special, complicated case. If the
+ property is optional, and is read-only, then the
+ property is always used for reading, but an
+ eventual existing non-property setter can be used
+ for writing. We create an artificial property
+ decl copying the getter from the optional
+ property, and looking up the setter in the
+ interface. */
+ x = maybe_make_artificial_property_decl (NULL_TREE,
+ NULL_TREE,
+ rprotos,
+ property_ident,
+ false,
+ PROPERTY_GETTER_NAME (x));
}
}
}
|| TREE_CODE (t) == COMPONENT_REF)
t = TREE_OPERAND (t, 0);
- if (t == UOBJC_SUPER_decl)
- {
- /* TODO: Check if this is correct also for 'super' in categories. */
- interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template));
- }
+ if (t == UOBJC_SUPER_decl)
+ interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template));
else if (t == self_decl)
interface_type = lookup_interface (CLASS_NAME (implementation_template));
x = maybe_make_artificial_property_decl
(interface_type, implementation, NULL_TREE,
property_ident,
- (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL));
+ (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL),
+ NULL_TREE);
+ }
+ else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+ {
+ tree implementation = NULL_TREE;
+
+ if (t == self_decl)
+ implementation = objc_implementation_context;
+
+ x = maybe_make_artificial_property_decl (interface_type,
+ implementation,
+ NULL_TREE,
+ property_ident,
+ false,
+ PROPERTY_GETTER_NAME (x));
}
}
}
implementation,
protocol_list,
property_ident,
- IS_CLASS (rtype));
+ IS_CLASS (rtype),
+ NULL_TREE);
}
+ else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+ {
+ tree implementation = NULL_TREE;
+
+ if (objc_implementation_context
+ && CLASS_NAME (objc_implementation_context)
+ == OBJC_TYPE_NAME (interface_type))
+ implementation = objc_implementation_context;
+
+ x = maybe_make_artificial_property_decl (interface_type,
+ implementation,
+ protocol_list,
+ property_ident,
+ false,
+ PROPERTY_GETTER_NAME (x));
+ }
}
}
}
x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE,
property_ident,
- true);
+ true, NULL_TREE);
if (x)
{
return s;
}
-/* Build a type differing from TYPE only in that TYPE_VOLATILE is set.
- Unlike tree.c:build_qualified_type(), preserve TYPE_LANG_SPECIFIC in the
- process. */
-static tree
-objc_build_volatilized_type (tree type)
-{
- tree t;
-
- /* Check if we have not constructed the desired variant already. */
- for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- {
- /* The type qualifiers must (obviously) match up. */
- if (!TYPE_VOLATILE (t)
- || (TYPE_READONLY (t) != TYPE_READONLY (type))
- || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type)))
- continue;
-
- /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC
- info, if any) must match up. */
- if (POINTER_TYPE_P (t)
- && (TREE_TYPE (t) != TREE_TYPE (type)))
- continue;
-
- /* Only match up the types which were previously volatilized in similar fashion and not
- because they were declared as such. */
- if (!lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (t)))
- continue;
-
- /* Everything matches up! */
- return t;
- }
-
- /* Ok, we could not re-use any of the pre-existing variants. Create
- a new one. */
- t = build_variant_type_copy (type);
- TYPE_VOLATILE (t) = 1;
-
- TYPE_ATTRIBUTES (t) = merge_attributes (TYPE_ATTRIBUTES (type),
- tree_cons (get_identifier ("objc_volatilized"),
- NULL_TREE,
- NULL_TREE));
- if (TREE_CODE (t) == ARRAY_TYPE)
- TREE_TYPE (t) = objc_build_volatilized_type (TREE_TYPE (t));
-
- /* Set up the canonical type information. */
- if (TYPE_STRUCTURAL_EQUALITY_P (type))
- SET_TYPE_STRUCTURAL_EQUALITY (t);
- else if (TYPE_CANONICAL (type) != type)
- TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type));
- else
- TYPE_CANONICAL (t) = t;
-
- return t;
-}
-
/* Mark DECL as being 'volatile' for purposes of Darwin
_setjmp()/_longjmp() exception handling. Called from
objc_mark_locals_volatile(). */
&& (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL))
{
- tree t = TREE_TYPE (decl);
+ if (local_variables_to_volatilize == NULL)
+ local_variables_to_volatilize = VEC_alloc (tree, gc, 8);
+
+ VEC_safe_push (tree, gc, local_variables_to_volatilize, decl);
+ }
+}
- t = objc_build_volatilized_type (t);
+/* Called when parsing of a function completes; if any local variables
+ in the function were marked as variables to volatilize, change them
+ to volatile. We do this at the end of the function when the
+ warnings about discarding 'volatile' have already been produced.
+ We are making the variables as volatile just to force the compiler
+ to preserve them between setjmp/longjmp, but we don't want warnings
+ for them as they aren't really volatile. */
+void
+objc_finish_function (void)
+{
+ /* If there are any local variables to volatilize, volatilize them. */
+ if (local_variables_to_volatilize)
+ {
+ int i;
+ tree decl;
+ FOR_EACH_VEC_ELT (tree, local_variables_to_volatilize, i, decl)
+ {
+ tree t = TREE_TYPE (decl);
- TREE_TYPE (decl) = t;
- TREE_THIS_VOLATILE (decl) = 1;
- TREE_SIDE_EFFECTS (decl) = 1;
- DECL_REGISTER (decl) = 0;
+ t = build_qualified_type (t, TYPE_QUALS (t) | TYPE_QUAL_VOLATILE);
+ TREE_TYPE (decl) = t;
+ TREE_THIS_VOLATILE (decl) = 1;
+ TREE_SIDE_EFFECTS (decl) = 1;
+ DECL_REGISTER (decl) = 0;
#ifndef OBJCPLUS
- C_DECL_REGISTER (decl) = 0;
+ C_DECL_REGISTER (decl) = 0;
#endif
+ }
+
+ /* Now we delete the vector. This sets it to NULL as well. */
+ VEC_free (tree, gc, local_variables_to_volatilize);
}
}
return false;
}
-/* Check if LTYP and RTYP have the same type qualifiers. If either type
- lives in the volatilized hash table, ignore the 'volatile' bit when
- making the comparison. */
-
-bool
-objc_type_quals_match (tree ltyp, tree rtyp)
-{
- int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp);
-
- if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (ltyp)))
- lquals &= ~TYPE_QUAL_VOLATILE;
-
- if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (rtyp)))
- rquals &= ~TYPE_QUAL_VOLATILE;
-
- return (lquals == rquals);
-}
-
#ifndef OBJCPLUS
/* Determine if CHILD is derived from PARENT. The routine assumes that
both parameters are RECORD_TYPEs, and is non-reflexive. */
error ("redeclaration of Objective-C class %qs", IDENTIFIER_POINTER (id));
}
-/* Return a non-volatalized version of TYPE. */
-
-tree
-objc_non_volatilized_type (tree type)
-{
- if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (type)))
- type = build_qualified_type (type, (TYPE_QUALS (type) & ~TYPE_QUAL_VOLATILE));
- return type;
-}
-
/* Construct a PROTOCOLS-qualified variant of INTERFACE, where
INTERFACE may either name an Objective-C class, or refer to the
special 'id' or 'Class' types. If INTERFACE is not a valid ObjC
tree
objc_eh_runtime_type (tree type)
{
- return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
+ /* Use 'ErrorMarkNode' as class name when error_mark_node is found
+ to prevent an ICE. Note that we know that the compiler will
+ terminate with an error and this 'ErrorMarkNode' class name will
+ never be actually used. */
+ if (type == error_mark_node)
+ return add_objc_string (get_identifier ("ErrorMarkNode"), class_names);
+ else
+ return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
}
tree
error_at (try_locus, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
}
+ /* Collect the list of local variables. We'll mark them as volatile
+ at the end of compilation of this function to prevent them being
+ clobbered by setjmp/longjmp. */
if (flag_objc_sjlj_exceptions)
objc_mark_locals_volatile (NULL);
}
/* Called just after parsing "@catch (parm)". Open a binding level,
enter DECL into the binding level, and initialize it. Leave the
- binding level open while the body of the compound statement is parsed. */
+ binding level open while the body of the compound statement is
+ parsed. If DECL is NULL_TREE, then we are compiling "@catch(...)"
+ which we compile as "@catch(id tmp_variable)". */
void
objc_begin_catch_clause (tree decl)
/* Begin a new scope that the entire catch clause will live in. */
compound = c_begin_compound_stmt (true);
- /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL. */
- decl = build_decl (input_location,
- VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
- lang_hooks.decls.pushdecl (decl);
+ /* Create the appropriate declaration for the argument. */
+ if (decl == error_mark_node)
+ type = error_mark_node;
+ else
+ {
+ if (decl == NULL_TREE)
+ {
+ /* If @catch(...) was specified, create a temporary variable of
+ type 'id' and use it. */
+ decl = objc_create_temporary_var (objc_object_type, "__objc_generic_catch_var");
+ DECL_SOURCE_LOCATION (decl) = input_location;
+ }
+ else
+ {
+ /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL. */
+ decl = build_decl (input_location,
+ VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+ }
+ lang_hooks.decls.pushdecl (decl);
- /* Since a decl is required here by syntax, don't warn if its unused. */
- /* ??? As opposed to __attribute__((unused))? Anyway, this appears to
- be what the previous objc implementation did. */
- TREE_USED (decl) = 1;
- DECL_READ_P (decl) = 1;
+ /* Mark the declaration as used so you never any warnings whether
+ you use the exception argument or not. TODO: Implement a
+ -Wunused-exception-parameter flag, which would cause warnings
+ if exception parameter is not used. */
+ TREE_USED (decl) = 1;
+ DECL_READ_P (decl) = 1;
- /* Verify that the type of the catch is valid. It must be a pointer
- to an Objective-C class, or "id" (which is catch-all). */
- type = TREE_TYPE (decl);
+ type = TREE_TYPE (decl);
+ }
- if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
- type = NULL;
- else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
+ /* Verify that the type of the catch is valid. It must be a pointer
+ to an Objective-C class, or "id" (which is catch-all). */
+ if (type == error_mark_node)
+ {
+ ;/* Just keep going. */
+ }
+ else if (!objc_type_valid_for_messaging (type, false))
{
error ("@catch parameter is not a known Objective-C class type");
type = error_mark_node;
}
- else if (cur_try_context->catch_list)
+ else if (TYPE_HAS_OBJC_INFO (TREE_TYPE (type))
+ && TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (type)))
+ {
+ error ("@catch parameter can not be protocol-qualified");
+ type = error_mark_node;
+ }
+ else if (objc_is_object_id (TREE_TYPE (type)))
+ type = NULL;
+ else
{
- /* Examine previous @catch clauses and see if we've already
- caught the type in question. */
- tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
- for (; !tsi_end_p (i); tsi_next (&i))
+ /* If 'type' was built using typedefs, we need to get rid of
+ them and get a simple pointer to the class. */
+ bool is_typedef = false;
+ tree x = TYPE_MAIN_VARIANT (type);
+
+ /* Skip from the pointer to the pointee. */
+ if (TREE_CODE (x) == POINTER_TYPE)
+ x = TREE_TYPE (x);
+
+ /* Traverse typedef aliases */
+ while (TREE_CODE (x) == RECORD_TYPE && OBJC_TYPE_NAME (x)
+ && TREE_CODE (OBJC_TYPE_NAME (x)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x)))
{
- tree stmt = tsi_stmt (i);
- t = CATCH_TYPES (stmt);
- if (t == error_mark_node)
- continue;
- if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+ is_typedef = true;
+ x = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x));
+ }
+
+ /* If it was a typedef, build a pointer to the final, original
+ class. */
+ if (is_typedef)
+ type = build_pointer_type (x);
+
+ if (cur_try_context->catch_list)
+ {
+ /* Examine previous @catch clauses and see if we've already
+ caught the type in question. */
+ tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+ for (; !tsi_end_p (i); tsi_next (&i))
{
- warning (0, "exception of type %<%T%> will be caught",
- TREE_TYPE (type));
- warning_at (EXPR_LOCATION (stmt), 0, " by earlier handler for %<%T%>",
- TREE_TYPE (t ? t : objc_object_type));
- break;
+ tree stmt = tsi_stmt (i);
+ t = CATCH_TYPES (stmt);
+ if (t == error_mark_node)
+ continue;
+ if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+ {
+ warning (0, "exception of type %<%T%> will be caught",
+ TREE_TYPE (type));
+ warning_at (EXPR_LOCATION (stmt), 0, " by earlier handler for %<%T%>",
+ TREE_TYPE (t ? t : objc_object_type));
+ break;
+ }
}
}
}
|| cur_try_context->current_catch == NULL)
{
error_at (loc, "%<@throw%> (rethrow) used outside of a @catch block");
- return NULL_TREE;
+ return error_mark_node;
}
/* Otherwise the object is still sitting in the EXC_PTR_EXPR
{
error ("reimplementation of class %qE",
class_name);
- return error_mark_node;
+ /* TODO: error message saying where it was previously
+ implemented. */
+ break;
}
- implemented_classes = tree_cons (NULL_TREE, class_name,
- implemented_classes);
+ if (chain == NULL_TREE)
+ implemented_classes = tree_cons (NULL_TREE, class_name,
+ implemented_classes);
}
/* Reset for multiple classes per file. */
getter_decl = build_method_decl (INSTANCE_METHOD_DECL,
rettype, PROPERTY_GETTER_NAME (x),
NULL_TREE, false);
- objc_add_method (objc_interface_context, getter_decl, false, false);
+ if (PROPERTY_OPTIONAL (x))
+ objc_add_method (objc_interface_context, getter_decl, false, true);
+ else
+ objc_add_method (objc_interface_context, getter_decl, false, false);
METHOD_PROPERTY_CONTEXT (getter_decl) = x;
}
ret_type, selector,
build_tree_list (NULL_TREE, NULL_TREE),
false);
- objc_add_method (objc_interface_context, setter_decl, false, false);
+ if (PROPERTY_OPTIONAL (x))
+ objc_add_method (objc_interface_context, setter_decl, false, true);
+ else
+ objc_add_method (objc_interface_context, setter_decl, false, false);
METHOD_PROPERTY_CONTEXT (setter_decl) = x;
}
}
{
char *demangled, *cp;
+ /* First of all, if the name is too short it can't be an Objective-C
+ mangled method name. */
+ if (mangled[0] == '\0' || mangled[1] == '\0' || mangled[2] == '\0')
+ return NULL;
+
+ /* If the name looks like an already demangled one, return it
+ unchanged. This should only happen on Darwin, where method names
+ are mangled differently into a pretty-print form (such as
+ '+[NSObject class]', see darwin.h). In that case, demangling is
+ a no-op, but we need to return the demangled name if it was an
+ ObjC one, and return NULL if not. We should be safe as no C/C++
+ function can start with "-[" or "+[". */
+ if ((mangled[0] == '-' || mangled[0] == '+')
+ && (mangled[1] == '['))
+ return mangled;
+
if (mangled[0] == '_' &&
(mangled[1] == 'i' || mangled[1] == 'c') &&
mangled[2] == '_')
if (!objc_type_valid_for_messaging (TREE_TYPE (object_expression), true))
{
- error ("iterating variable in fast enumeration is not an object");
+ error_at (location, "iterating variable in fast enumeration is not an object");
return;
}
if (!objc_type_valid_for_messaging (TREE_TYPE (collection_expression), true))
{
- error ("collection in fast enumeration is not an object");
+ error_at (location, "collection in fast enumeration is not an object");
return;
}
/* type object; */
/* Done by c-parser.c. */
+ /* Disable warnings that 'object' is unused. For example the code
+
+ for (id object in collection)
+ i++;
+
+ which can be used to count how many objects there are in the
+ collection is fine and should generate no warnings even if
+ 'object' is technically unused. */
+ TREE_USED (object_expression) = 1;
+ if (DECL_P (object_expression))
+ DECL_READ_P (object_expression) = 1;
+
/* id __objc_foreach_collection */
objc_foreach_collection_decl = objc_create_temporary_var (objc_object_type, "__objc_foreach_collection");