building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998-2019 Free Software Foundation, Inc.
+ Copyright (C) 1998-2020 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
A::B* A::f() { return 0; }
is valid, even though `A::B' is not generally accessible. */
- vec<deferred_access_check, va_gc> * GTY(()) deferred_access_checks;
+ vec<deferred_access_check, va_gc> *deferred_access_checks;
/* The current mode of access checks. */
enum deferring_kind deferring_access_checks_kind;
-
};
/* Data for deferred access checking. */
}
}
+/* If the current scope isn't allowed to access DECL along
+ BASETYPE_PATH, give an error, or if we're parsing a function or class
+ template, defer the access check to be performed at instantiation time.
+ The most derived class in BASETYPE_PATH is the one used to qualify DECL.
+ DIAG_DECL is the declaration to use in the error diagnostic. */
+
+static bool
+enforce_access (tree basetype_path, tree decl, tree diag_decl,
+ tsubst_flags_t complain, access_failure_info *afi = NULL)
+{
+ gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
+
+ if (flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (decl))
+ {
+ /* 7.3.3/18: The additional constructors are accessible if they would be
+ accessible when used to construct an object of the corresponding base
+ class. */
+ decl = strip_inheriting_ctors (decl);
+ basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
+ ba_any, NULL, complain);
+ }
+
+ tree cs = current_scope ();
+ if (processing_template_decl
+ && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
+ if (tree template_info = get_template_info (cs))
+ {
+ /* When parsing a function or class template, we in general need to
+ defer access checks until template instantiation time, since a friend
+ declaration may grant access only to a particular specialization of
+ the template. */
+
+ if (accessible_p (basetype_path, decl, /*consider_local_p=*/true))
+ /* But if the member is deemed accessible at parse time, then we can
+ assume it'll be accessible at instantiation time. */
+ return true;
+
+ /* Access of a dependent decl should be rechecked after tsubst'ing
+ into the user of the decl, rather than explicitly deferring the
+ check here. */
+ gcc_assert (!uses_template_parms (decl));
+ if (TREE_CODE (decl) == FIELD_DECL)
+ gcc_assert (!uses_template_parms (DECL_CONTEXT (decl)));
+
+ /* Defer this access check until instantiation time. */
+ deferred_access_check access_check;
+ access_check.binfo = basetype_path;
+ access_check.decl = decl;
+ access_check.diag_decl = diag_decl;
+ access_check.loc = input_location;
+ vec_safe_push (TI_DEFERRED_ACCESS_CHECKS (template_info), access_check);
+ return true;
+ }
+
+ if (!accessible_p (basetype_path, decl, /*consider_local_p=*/true))
+ {
+ if (flag_new_inheriting_ctors)
+ diag_decl = strip_inheriting_ctors (diag_decl);
+ if (complain & tf_error)
+ complain_about_access (decl, diag_decl, true);
+ if (afi)
+ afi->record_access_failure (basetype_path, decl, diag_decl);
+ return false;
+ }
+
+ return true;
+}
+
/* Perform the access checks in CHECKS. The TREE_PURPOSE of each node
is the BINFO indicating the qualifying scope used to access the
DECL node stored in the TREE_VALUE of the node. If CHECKS is empty
deferred_access *ptr;
deferred_access_check *chk;
-
- /* Exit if we are in a context that no access checking is performed.
- */
+ /* Exit if we are in a context that no access checking is performed. */
if (deferred_access_no_check)
return true;
/* When we expand a statement-tree, we must know whether or not the
statements are full-expressions. We record that fact here. */
- STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p ();
+ if (STATEMENT_CODE_P (TREE_CODE (t)))
+ STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p ();
}
if (code == LABEL_EXPR || code == CASE_LABEL_EXPR)
return false;
tree fndecl = cp_get_callee_fndecl_nofold (fn);
+ if (fndecl == NULL_TREE)
+ return false;
+
if (fndecl_built_in_p (fndecl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
BUILT_IN_FRONTEND))
return true;
if (CLASS_TYPE_P (orig_type))
{
if (TYPE_POLYMORPHIC_P (orig_type))
- warning (OPT_Wcatch_value_,
- "catching polymorphic type %q#T by value", orig_type);
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wcatch_value_,
+ "catching polymorphic type %q#T by value",
+ orig_type);
else if (warn_catch_value > 1)
- warning (OPT_Wcatch_value_,
- "catching type %q#T by value", orig_type);
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wcatch_value_,
+ "catching type %q#T by value", orig_type);
}
else if (warn_catch_value > 2)
- warning (OPT_Wcatch_value_,
- "catching non-reference type %q#T", orig_type);
+ warning_at (DECL_SOURCE_LOCATION (decl),
+ OPT_Wcatch_value_,
+ "catching non-reference type %q#T", orig_type);
}
}
HANDLER_TYPE (handler) = type;
/* Obfuscate EXPR if it looks like an id-expression or member access so
that the call to finish_decltype in do_auto_deduction will give the
- right result. */
+ right result. If EVEN_UNEVAL, do this even in unevaluated context. */
tree
-force_paren_expr (tree expr)
+force_paren_expr (tree expr, bool even_uneval)
{
/* This is only needed for decltype(auto) in C++14. */
if (cxx_dialect < cxx14)
/* If we're in unevaluated context, we can't be deducing a
return/initializer type, so we don't need to mess with this. */
- if (cp_unevaluated_operand)
+ if (cp_unevaluated_operand && !even_uneval)
return expr;
if (!DECL_P (tree_strip_any_location_wrapper (expr))
return ret;
}
-/* If we are currently parsing a template and we encountered a typedef
- TYPEDEF_DECL that is being accessed though CONTEXT, this function
- adds the typedef to a list tied to the current template.
- At template instantiation time, that list is walked and access check
- performed for each typedef.
- LOCATION is the location of the usage point of TYPEDEF_DECL. */
-
-void
-add_typedef_to_current_template_for_access_check (tree typedef_decl,
- tree context,
- location_t location)
-{
- tree template_info = NULL;
- tree cs = current_scope ();
-
- if (!is_typedef_decl (typedef_decl)
- || !context
- || !CLASS_TYPE_P (context)
- || !cs)
- return;
-
- if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)
- template_info = get_template_info (cs);
-
- if (template_info
- && TI_TEMPLATE (template_info)
- && !currently_open_class (context))
- append_type_to_template_for_access_check (cs, typedef_decl,
- context, location);
-}
-
/* DECL was the declaration to which a qualified-id resolved. Issue
an error message if it is not accessible. If OBJECT_TYPE is
non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
type of `*x', or `x', respectively. If the DECL was named as
- `A::B' then NESTED_NAME_SPECIFIER is `A'. */
+ `A::B' then NESTED_NAME_SPECIFIER is `A'. Return value is like
+ perform_access_checks above. */
-void
+bool
check_accessibility_of_qualified_id (tree decl,
tree object_type,
- tree nested_name_specifier)
+ tree nested_name_specifier,
+ tsubst_flags_t complain)
{
- tree scope;
- tree qualifying_type = NULL_TREE;
-
- /* If we are parsing a template declaration and if decl is a typedef,
- add it to a list tied to the template.
- At template instantiation time, that list will be walked and
- access check performed. */
- add_typedef_to_current_template_for_access_check (decl,
- nested_name_specifier
- ? nested_name_specifier
- : DECL_CONTEXT (decl),
- input_location);
-
/* If we're not checking, return immediately. */
if (deferred_access_no_check)
- return;
+ return true;
/* Determine the SCOPE of DECL. */
- scope = context_for_name_lookup (decl);
+ tree scope = context_for_name_lookup (decl);
/* If the SCOPE is not a type, then DECL is not a member. */
- if (!TYPE_P (scope))
- return;
+ if (!TYPE_P (scope)
+ /* If SCOPE is dependent then we can't perform this access check now,
+ and since we'll perform this access check again after substitution
+ there's no need to explicitly defer it. */
+ || dependent_type_p (scope))
+ return true;
+
+ tree qualifying_type = NULL_TREE;
/* Compute the scope through which DECL is being accessed. */
if (object_type
/* OBJECT_TYPE might not be a class type; consider:
if (qualifying_type
/* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
or similar in a default argument value. */
- && CLASS_TYPE_P (qualifying_type)
- && !dependent_type_p (qualifying_type))
- perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
- decl, tf_warning_or_error);
+ && CLASS_TYPE_P (qualifying_type))
+ return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
+ decl, complain);
+
+ return true;
}
/* EXPR is the result of a qualified-id. The QUALIFYING_CLASS was the
bool abnormal = true;
for (lkp_iterator iter (fn); abnormal && iter; ++iter)
{
- tree fndecl = *iter;
+ tree fndecl = STRIP_TEMPLATE (*iter);
if (TREE_CODE (fndecl) != FUNCTION_DECL
|| !TREE_THIS_VOLATILE (fndecl))
abnormal = false;
/*fn_p=*/NULL,
complain);
}
+ else if (concept_check_p (fn))
+ {
+ /* FN is actually a template-id referring to a concept definition. */
+ tree id = unpack_concept_check (fn);
+ tree tmpl = TREE_OPERAND (id, 0);
+ tree args = TREE_OPERAND (id, 1);
+
+ if (!function_concept_p (tmpl))
+ {
+ error_at (EXPR_LOC_OR_LOC (fn, input_location),
+ "cannot call a concept as a function");
+ return error_mark_node;
+ }
+
+ /* Ensure the result is wrapped as a call expression. */
+ result = build_concept_check (tmpl, args, tf_warning_or_error);
+ }
else if (is_overloaded_fn (fn))
{
/* If the function is an overloaded builtin, resolve it. */
tree arg2 = (*orig_args)[2];
int literal_mask = ((literal_integer_zerop (arg1) << 1)
| (literal_integer_zerop (arg2) << 2));
- arg2 = instantiate_non_dependent_expr (arg2);
warn_for_memset (input_location, arg0, arg2, literal_mask);
}
{
if (!vec_safe_is_empty (*args))
error ("arguments to destructor are not allowed");
- /* Mark the pseudo-destructor call as having side-effects so
- that we do not issue warnings about its use. */
- result = build1 (NOP_EXPR,
- void_type_node,
- TREE_OPERAND (fn, 0));
- TREE_SIDE_EFFECTS (result) = 1;
+ /* C++20/DR: If the postfix-expression names a pseudo-destructor (in
+ which case the postfix-expression is a possibly-parenthesized class
+ member access), the function call destroys the object of scalar type
+ denoted by the object expression of the class member access. */
+ tree ob = TREE_OPERAND (fn, 0);
+ if (obvalue_p (ob))
+ result = build_trivial_dtor_call (ob);
+ else
+ /* No location to clobber. */
+ result = convert_to_void (ob, ICV_STATEMENT, complain);
}
else if (CLASS_TYPE_P (TREE_TYPE (fn)))
/* If the "function" is really an object of class type, it might
}
}
- return build3_loc (loc, PSEUDO_DTOR_EXPR, void_type_node, object,
+ tree type = (type_dependent_expression_p (object)
+ ? NULL_TREE : void_type_node);
+
+ return build3_loc (loc, PSEUDO_DTOR_EXPR, type, object,
scope, destructor);
}
that it came from T{} rather than T({}). */
CONSTRUCTOR_IS_DIRECT_INIT (compound_literal) = 1;
compound_literal = build_tree_list (NULL_TREE, compound_literal);
- return build_functional_cast (type, compound_literal, complain);
+ return build_functional_cast (input_location, type,
+ compound_literal, complain);
}
if (TREE_CODE (type) == ARRAY_TYPE
/* Do file scope __FUNCTION__ et al. */
finish_fname_decls ();
+
+ if (scope_chain->omp_declare_target_attribute)
+ {
+ if (!errorcount)
+ error ("%<#pragma omp declare target%> without corresponding "
+ "%<#pragma omp end declare target%>");
+ scope_chain->omp_declare_target_attribute = 0;
+ }
}
/* Finish a template type parameter, specified as AGGR IDENTIFIER.
DECL_TEMPLATE_RESULT (tmpl) = decl;
DECL_ARTIFICIAL (decl) = 1;
- // Associate the constraints with the underlying declaration,
- // not the template.
+ /* Associate the constraints with the underlying declaration,
+ not the template. */
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
tree constr = build_constraints (reqs, NULL_TREE);
set_constraints (decl, constr);
SET_CLASSTYPE_INTERFACE_UNKNOWN_X
(t, finfo->interface_unknown);
}
- reset_specialization();
+ reset_specialization ();
/* Make a declaration for this class in its own scope. */
build_self_reference ();
process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
{
if (cp_unevaluated_operand)
- /* It's not a use (3.2) if we're in an unevaluated context. */
- return decl;
+ {
+ tree type = TREE_TYPE (decl);
+ if (!dependent_type_p (type)
+ && variably_modified_type_p (type, NULL_TREE))
+ /* VLAs are used even in unevaluated context. */;
+ else
+ /* It's not a use (3.2) if we're in an unevaluated context. */
+ return decl;
+ }
if (decl == error_mark_node)
return decl;
if (! error_operand_p (decl)
&& !dependent_p
&& integral_constant_expression_p
- && ! decl_constant_var_p (decl)
+ && !decl_constant_var_p (decl)
&& TREE_CODE (decl) != CONST_DECL
- && ! builtin_valid_in_constant_expr_p (decl))
+ && !builtin_valid_in_constant_expr_p (decl)
+ && !concept_check_p (decl))
{
if (!allow_non_integral_constant_expression_p)
{
decl = wrap;
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& !dependent_p
- && variable_template_p (TREE_OPERAND (decl, 0)))
+ && variable_template_p (TREE_OPERAND (decl, 0))
+ && !concept_check_p (decl))
{
decl = finish_template_variable (decl);
mark_used (decl);
decl = convert_from_reference (decl);
}
+ else if (concept_check_p (decl))
+ {
+ /* Nothing more to do. All of the analysis for concept checks
+ is done by build_conept_id, called from the parser. */
+ }
else if (scope)
{
if (TREE_CODE (decl) == SCOPE_REF)
if (DECL_INTERFACE_KNOWN (fn))
/* We've already made a decision as to how this function will
be handled. */;
- else if (!at_eof)
+ else if (!at_eof
+ || DECL_IMMEDIATE_FUNCTION_P (fn)
+ || DECL_OMP_DECLARE_REDUCTION_P (fn))
tentative_decl_linkage (fn);
else
import_export_decl (fn);
be emitted; there may be callers in other DLLs. */
if (DECL_DECLARED_INLINE_P (fn)
&& !DECL_REALLY_EXTERN (fn)
+ && !DECL_IMMEDIATE_FUNCTION_P (fn)
+ && !DECL_OMP_DECLARE_REDUCTION_P (fn)
&& (flag_keep_inline_functions
|| (flag_keep_inline_dllexport
&& lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))))
return false;
}
+ if (DECL_OMP_DECLARE_REDUCTION_P (fn))
+ return false;
+
return true;
}
t = TREE_OPERAND (t, 0);
ret = t;
if (TREE_CODE (t) == COMPONENT_REF
- && ort == C_ORT_OMP
&& (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
|| OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO
|| OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)
return error_mark_node;
}
t = TREE_OPERAND (t, 0);
+ if (ort == C_ORT_ACC && TREE_CODE (t) == INDIRECT_REF)
+ t = TREE_OPERAND (t, 0);
}
if (REFERENCE_REF_P (t))
t = TREE_OPERAND (t, 0);
if (low_bound == NULL_TREE)
low_bound = integer_zero_node;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH))
+ {
+ if (length != integer_one_node)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "expected single pointer in %qs clause",
+ c_omp_map_clause_name (c, ort == C_ORT_ACC));
+ return error_mark_node;
+ }
+ }
if (length != NULL_TREE)
{
if (!integer_nonzerop (length))
TREE_PURPOSE (t) = lb;
low_bound = lb;
}
+ /* Temporarily disable -fstrong-eval-order for array reductions.
+ The SAVE_EXPR and COMPOUND_EXPR added if low_bound has side-effects
+ is something the middle-end can't cope with and more importantly,
+ it needs to be the actual base variable that is privatized, not some
+ temporary assigned previous value of it. That, together with OpenMP
+ saying how many times the side-effects are evaluated is unspecified,
+ makes int *a, *b; ... reduction(+:a[a = b, 3:10]) really unspecified. */
+ warning_sentinel s (flag_strong_eval_order,
+ OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION);
ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false);
return ret;
}
switch (OMP_CLAUSE_MAP_KIND (c))
{
case GOMP_MAP_ALLOC:
+ case GOMP_MAP_IF_PRESENT:
case GOMP_MAP_TO:
case GOMP_MAP_FROM:
case GOMP_MAP_TOFROM:
if ((ort & C_ORT_OMP_DECLARE_SIMD) != C_ORT_OMP && ort != C_ORT_ACC)
OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
else if (TREE_CODE (t) == COMPONENT_REF)
- OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER);
+ {
+ gomp_map_kind k = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH
+ : GOMP_MAP_ALWAYS_POINTER;
+ OMP_CLAUSE_SET_MAP_KIND (c2, k);
+ }
else if (REFERENCE_REF_P (t)
&& TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF)
{
t = TREE_OPERAND (t, 0);
- OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER);
+ gomp_map_kind k = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH
+ : GOMP_MAP_ALWAYS_POINTER;
+ OMP_CLAUSE_SET_MAP_KIND (c2, k);
}
else
OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
omp_reduction_id (ERROR_MARK,
TREE_OPERAND (id, 1),
type),
- false, false);
+ LOOK_want::NORMAL, false);
tree fns = id;
id = NULL_TREE;
if (fns && is_overloaded_fn (fns))
if (need_static_cast)
{
tree rtype = build_reference_type (atype);
- omp_out = build_static_cast (rtype, omp_out,
+ omp_out = build_static_cast (input_location,
+ rtype, omp_out,
tf_warning_or_error);
- omp_in = build_static_cast (rtype, omp_in,
+ omp_in = build_static_cast (input_location,
+ rtype, omp_in,
tf_warning_or_error);
if (omp_out == error_mark_node || omp_in == error_mark_node)
return true;
return true;
}
tree rtype = build_reference_type (atype);
- omp_priv = build_static_cast (rtype, omp_priv,
+ omp_priv = build_static_cast (input_location,
+ rtype, omp_priv,
tf_warning_or_error);
- omp_orig = build_static_cast (rtype, omp_orig,
+ omp_orig = build_static_cast (input_location,
+ rtype, omp_orig,
tf_warning_or_error);
if (omp_priv == error_mark_node
|| omp_orig == error_mark_node)
begin = mark_rvalue_use (begin);
end = mark_rvalue_use (end);
step = mark_rvalue_use (step);
- begin = cp_build_c_cast (type, begin, tf_warning_or_error);
- end = cp_build_c_cast (type, end, tf_warning_or_error);
+ begin = cp_build_c_cast (input_location, type, begin,
+ tf_warning_or_error);
+ end = cp_build_c_cast (input_location, type, end,
+ tf_warning_or_error);
orig_step = step;
if (!processing_template_decl)
step = orig_step = save_expr (step);
tree stype = POINTER_TYPE_P (type) ? sizetype : type;
- step = cp_build_c_cast (stype, step, tf_warning_or_error);
+ step = cp_build_c_cast (input_location, stype, step,
+ tf_warning_or_error);
if (POINTER_TYPE_P (type) && !processing_template_decl)
{
begin = save_expr (begin);
return ret;
}
+/* Ensure that pointers are used in OpenACC attach and detach clauses.
+ Return true if an error has been detected. */
+
+static bool
+cp_oacc_check_attachments (tree c)
+{
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ return false;
+
+ /* OpenACC attach / detach clauses must be pointers. */
+ if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)
+ {
+ tree t = OMP_CLAUSE_DECL (c);
+ tree type;
+
+ while (TREE_CODE (t) == TREE_LIST)
+ t = TREE_CHAIN (t);
+
+ type = TREE_TYPE (t);
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c), "expected pointer in %qs clause",
+ c_omp_map_clause_name (c, true));
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* For all elements of CLAUSES, validate them vs OpenMP constraints.
Remove any elements from the list that are invalid. */
t = OMP_CLAUSE_DECL (c);
check_dup_generic_t:
if (t == current_class_ptr
- && (ort != C_ORT_OMP_DECLARE_SIMD
+ && ((ort != C_ORT_OMP_DECLARE_SIMD && ort != C_ORT_ACC)
|| (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR
&& OMP_CLAUSE_CODE (c) != OMP_CLAUSE_UNIFORM)))
{
handle_field_decl:
if (!remove
&& TREE_CODE (t) == FIELD_DECL
- && t == OMP_CLAUSE_DECL (c)
- && ort != C_ORT_ACC)
+ && t == OMP_CLAUSE_DECL (c))
{
OMP_CLAUSE_DECL (c)
= omp_privatize_field (t, (OMP_CLAUSE_CODE (c)
omp_note_field_privatization (t, OMP_CLAUSE_DECL (c));
else
t = OMP_CLAUSE_DECL (c);
- if (t == current_class_ptr)
+ if (ort != C_ORT_ACC && t == current_class_ptr)
{
error_at (OMP_CLAUSE_LOCATION (c),
"%<this%> allowed in OpenMP only in %<declare simd%>"
}
if (t == error_mark_node)
remove = true;
- else if (t == current_class_ptr)
+ else if (ort != C_ORT_ACC && t == current_class_ptr)
{
error_at (OMP_CLAUSE_LOCATION (c),
"%<this%> allowed in OpenMP only in %<declare simd%>"
remove = true;
else
{
- t = cp_build_indirect_ref (addr, RO_UNARY_STAR,
+ t = cp_build_indirect_ref (OMP_CLAUSE_LOCATION (c),
+ addr, RO_UNARY_STAR,
tf_warning_or_error);
if (t == error_mark_node)
remove = true;
}
}
}
+ if (cp_oacc_check_attachments (c))
+ remove = true;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH))
+ /* In this case, we have a single array element which is a
+ pointer, and we already set OMP_CLAUSE_SIZE in
+ handle_omp_array_sections above. For attach/detach clauses,
+ reset the OMP_CLAUSE_SIZE (representing a bias) to zero
+ here. */
+ OMP_CLAUSE_SIZE (c) = size_zero_node;
break;
}
if (t == error_mark_node)
remove = true;
break;
}
+ /* OpenACC attach / detach clauses must be pointers. */
+ if (cp_oacc_check_attachments (c))
+ {
+ remove = true;
+ break;
+ }
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH))
+ /* For attach/detach clauses, set OMP_CLAUSE_SIZE (representing a
+ bias) to zero here, so it is not set erroneously to the pointer
+ size later on in gimplify.c. */
+ OMP_CLAUSE_SIZE (c) = size_zero_node;
if (REFERENCE_REF_P (t)
&& TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF)
{
t = TREE_OPERAND (t, 0);
OMP_CLAUSE_DECL (c) = t;
}
+ if (ort == C_ORT_ACC
+ && TREE_CODE (t) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF)
+ t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
if (TREE_CODE (t) == COMPONENT_REF
- && (ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
+ && ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
+ || ort == C_ORT_ACC)
&& OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_)
{
if (type_dependent_expression_p (t))
break;
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
&& (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
- || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER))
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH))
break;
if (DECL_P (t))
error_at (OMP_CLAUSE_LOCATION (c),
else
bitmap_set_bit (&generic_head, DECL_UID (t));
}
- else if (bitmap_bit_p (&map_head, DECL_UID (t)))
+ else if (bitmap_bit_p (&map_head, DECL_UID (t))
+ && (ort != C_ORT_ACC
+ || !bitmap_bit_p (&map_field_head, DECL_UID (t))))
{
if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
error_at (OMP_CLAUSE_LOCATION (c),
tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
OMP_CLAUSE_MAP);
if (TREE_CODE (t) == COMPONENT_REF)
- OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER);
+ {
+ gomp_map_kind k
+ = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH
+ : GOMP_MAP_ALWAYS_POINTER;
+ OMP_CLAUSE_SET_MAP_KIND (c2, k);
+ }
else
OMP_CLAUSE_SET_MAP_KIND (c2,
GOMP_MAP_FIRSTPRIVATE_REFERENCE);
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
+ && c_omp_predefined_variable (t))
+ /* The __func__ variable and similar function-local predefined
+ variables may be listed in a shared or firstprivate
+ clause. */
+ break;
if (VAR_P (t)
&& OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
&& TREE_STATIC (t)
if (init && EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
- cond = cp_fully_fold (cond);
switch (TREE_CODE (cond))
{
case GT_EXPR:
TREE_OPERAND (cond, 1), iter);
return true;
}
- if (!c_omp_check_loop_iv_exprs (locus, orig_declv,
+ if (!c_omp_check_loop_iv_exprs (locus, orig_declv, i,
TREE_VEC_ELT (declv, i), NULL_TREE,
cond, cp_walk_subtrees))
return true;
tree orig_init;
FOR_EACH_VEC_ELT (*orig_inits, i, orig_init)
if (orig_init
- && !c_omp_check_loop_iv_exprs (locus, orig_declv
- ? orig_declv : declv,
+ && !c_omp_check_loop_iv_exprs (locus,
+ orig_declv ? orig_declv : declv, i,
TREE_VEC_ELT (declv, i), orig_init,
NULL_TREE, cp_walk_subtrees))
fail = true;
return NULL;
}
- if (!processing_template_decl)
- {
- init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
- init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
- tf_warning_or_error);
- }
+ if (!processing_template_decl && TREE_CODE (init) != TREE_VEC)
+ init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
+ tf_warning_or_error);
else
init = build2 (MODIFY_EXPR, void_type_node, decl, init);
- if (cond
- && TREE_SIDE_EFFECTS (cond)
- && COMPARISON_CLASS_P (cond)
- && !processing_template_decl)
- {
- tree t = TREE_OPERAND (cond, 0);
- if (TREE_SIDE_EFFECTS (t)
- && t != decl
- && (TREE_CODE (t) != NOP_EXPR
- || TREE_OPERAND (t, 0) != decl))
- TREE_OPERAND (cond, 0)
- = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-
- t = TREE_OPERAND (cond, 1);
- if (TREE_SIDE_EFFECTS (t)
- && t != decl
- && (TREE_CODE (t) != NOP_EXPR
- || TREE_OPERAND (t, 0) != decl))
- TREE_OPERAND (cond, 1)
- = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
- }
if (decl == error_mark_node || init == error_mark_node)
return NULL;
for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)); i++)
{
- decl = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i), 0);
+ init = TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i);
+ decl = TREE_OPERAND (init, 0);
+ cond = TREE_VEC_ELT (OMP_FOR_COND (omp_for), i);
incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i);
+ if (!processing_template_decl)
+ {
+ if (TREE_CODE (TREE_OPERAND (init, 1)) == TREE_VEC)
+ {
+ tree t = TREE_VEC_ELT (TREE_OPERAND (init, 1), 1);
+ TREE_VEC_ELT (TREE_OPERAND (init, 1), 1)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ t = TREE_VEC_ELT (TREE_OPERAND (init, 1), 2);
+ TREE_VEC_ELT (TREE_OPERAND (init, 1), 2)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ else
+ {
+ tree t = TREE_OPERAND (init, 1);
+ TREE_OPERAND (init, 1)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ if (TREE_CODE (TREE_OPERAND (cond, 1)) == TREE_VEC)
+ {
+ tree t = TREE_VEC_ELT (TREE_OPERAND (cond, 1), 1);
+ TREE_VEC_ELT (TREE_OPERAND (cond, 1), 1)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ t = TREE_VEC_ELT (TREE_OPERAND (cond, 1), 2);
+ TREE_VEC_ELT (TREE_OPERAND (cond, 1), 2)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ else
+ {
+ tree t = TREE_OPERAND (cond, 1);
+ TREE_OPERAND (cond, 1)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ }
+
if (TREE_CODE (incr) != MODIFY_EXPR)
continue;
if (addr == error_mark_node)
depobj = error_mark_node;
else
- depobj = cp_build_indirect_ref (addr, RO_UNARY_STAR,
+ depobj = cp_build_indirect_ref (loc, addr, RO_UNARY_STAR,
tf_warning_or_error);
}
return;
}
+ /* Save the condition in case it was a concept check. */
+ tree orig_condition = condition;
+
/* Fold the expression and convert it to a boolean value. */
condition = perform_implicit_conversion_flags (boolean_type_node, condition,
complain, LOOKUP_NORMAL);
else
error ("static assertion failed: %s",
TREE_STRING_POINTER (message));
+
+ /* Actually explain the failure if this is a concept check or a
+ requires-expression. */
+ if (concept_check_p (orig_condition)
+ || TREE_CODE (orig_condition) == REQUIRES_EXPR)
+ diagnose_constraints (location, orig_condition, NULL_TREE);
}
else if (condition && condition != error_mark_node)
{
return type;
}
+ else if (processing_template_decl)
+ {
+ ++cp_unevaluated_operand;
+ expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+ --cp_unevaluated_operand;
+ if (expr == error_mark_node)
+ return error_mark_node;
+ }
/* The type denoted by decltype(e) is defined as follows: */
#endif
cfun->returns_struct = aggr;
}
-
}
/* DECL is a local variable or parameter from the surrounding scope of a
capture_decltype (tree decl)
{
tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
- tree cap = lookup_name_real (DECL_NAME (decl), /*type*/0, /*nonclass*/1,
- /*block_p=*/true, /*ns*/0, LOOKUP_HIDDEN);
+ tree cap = lookup_name_real (DECL_NAME (decl), LOOK_where::BLOCK,
+ LOOK_want::NORMAL | LOOK_want::HIDDEN_LAMBDA);
tree type;
if (cap && is_capture_proxy (cap))
static tree
finish_unary_fold_expr (tree expr, int op, tree_code dir)
{
- // Build a pack expansion (assuming expr has pack type).
+ /* Build a pack expansion (assuming expr has pack type). */
if (!uses_parameter_packs (expr))
{
error_at (location_of (expr), "operand of fold expression has no "
}
tree pack = make_pack_expansion (expr);
- // Build the fold expression.
+ /* Build the fold expression. */
tree code = build_int_cstu (integer_type_node, abs (op));
tree fold = build_min_nt_loc (UNKNOWN_LOCATION, dir, code, pack);
FOLD_EXPR_MODIFY_P (fold) = (op < 0);
tree ret = NULL_TREE;
if (!type_dependent_expression_p (arg) && !dependent_type_p (type))
- ret = c_build_vec_convert (cp_expr_loc_or_input_loc (arg), arg,
+ ret = c_build_vec_convert (cp_expr_loc_or_input_loc (arg),
+ decay_conversion (arg, complain),
loc, type, (complain & tf_error) != 0);
if (!processing_template_decl)