return r;
}
+/* Returns true if FN, a CALL_EXPR, is a call to
+ std::is_constant_evaluated or __builtin_is_constant_evaluated. */
+
+static bool
+is_std_constant_evaluated_p (tree fn)
+{
+ /* std::is_constant_evaluated takes no arguments. */
+ if (call_expr_nargs (fn) != 0)
+ return false;
+
+ tree fndecl = cp_get_callee_fndecl_nofold (fn);
+ if (fndecl_built_in_p (fndecl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
+ BUILT_IN_FRONTEND))
+ return true;
+
+ if (!decl_in_std_namespace_p (fndecl))
+ return false;
+
+ tree name = DECL_NAME (fndecl);
+ return name && id_equal (name, "is_constant_evaluated");
+}
+
/* Process the COND of an if-statement, which may be given by
IF_STMT. */
converted to bool. */
&& TYPE_MAIN_VARIANT (TREE_TYPE (cond)) == boolean_type_node)
{
+ /* if constexpr (std::is_constant_evaluated()) is always true,
+ so give the user a clue. */
+ if (warn_tautological_compare)
+ {
+ tree t = cond;
+ if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == CALL_EXPR
+ && is_std_constant_evaluated_p (t))
+ warning_at (EXPR_LOCATION (cond), OPT_Wtautological_compare,
+ "%qs always evaluates to true in %<if constexpr%>",
+ "std::is_constant_evaluated");
+ }
+
cond = instantiate_non_dependent_expr (cond);
cond = cxx_constant_value (cond, NULL_TREE);
}
ELSE_CLAUSE (if_stmt) = pop_stmt_list (ELSE_CLAUSE (if_stmt));
}
+/* Callback for cp_walk_tree to mark all {VAR,PARM}_DECLs in a tree as
+ read. */
+
+static tree
+maybe_mark_exp_read_r (tree *tp, int *, void *)
+{
+ tree t = *tp;
+ if (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
+ mark_exp_read (t);
+ return NULL_TREE;
+}
+
/* Finish an if-statement. */
void
{
tree scope = IF_SCOPE (if_stmt);
IF_SCOPE (if_stmt) = NULL;
+ if (IF_STMT_CONSTEXPR_P (if_stmt))
+ {
+ /* Prevent various -Wunused warnings. We might not instantiate
+ either of these branches, so we would not mark the variables
+ used in that branch as read. */
+ cp_walk_tree_without_duplicates (&THEN_CLAUSE (if_stmt),
+ maybe_mark_exp_read_r, NULL);
+ cp_walk_tree_without_duplicates (&ELSE_CLAUSE (if_stmt),
+ maybe_mark_exp_read_r, NULL);
+ }
add_stmt (do_poplevel (scope));
}
if (!processing_template_decl)
{
/* Convert the condition to an integer or enumeration type. */
+ tree orig_cond = cond;
cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, true);
if (cond == NULL_TREE)
{
- error ("switch quantity not an integer");
+ error_at (cp_expr_loc_or_input_loc (orig_cond),
+ "switch quantity not an integer");
cond = error_mark_node;
}
/* We want unlowered type here to handle enum bit-fields. */
considered volatile, and whether it is asm inline. */
tree
-finish_asm_stmt (int volatile_p, tree string, tree output_operands,
- tree input_operands, tree clobbers, tree labels, bool inline_p)
+finish_asm_stmt (location_t loc, int volatile_p, tree string,
+ tree output_operands, tree input_operands, tree clobbers,
+ tree labels, bool inline_p)
{
tree r;
tree t;
effectively const. */
|| (CLASS_TYPE_P (TREE_TYPE (operand))
&& C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
- cxx_readonly_error (input_location, operand, lv_asm);
+ cxx_readonly_error (loc, operand, lv_asm);
tree *op = &operand;
while (TREE_CODE (*op) == COMPOUND_EXPR)
resolve the overloading. */
if (TREE_TYPE (operand) == unknown_type_node)
{
- error ("type of %<asm%> operand %qE could not be determined",
- TREE_VALUE (t));
+ error_at (loc,
+ "type of %<asm%> operand %qE could not be determined",
+ TREE_VALUE (t));
operand = error_mark_node;
}
}
}
- r = build_stmt (input_location, ASM_EXPR, string,
+ r = build_stmt (loc, ASM_EXPR, string,
output_operands, input_operands,
clobbers, labels);
ASM_VOLATILE_P (r) = volatile_p || noutputs == 0;
/* 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))
/*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. */
/* 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);
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 (TREE_CODE (decl) == FUNCTION_DECL)
mark_used (decl);
+ cp_warn_deprecated_use_scopes (scope);
+
if (TYPE_P (scope))
decl = finish_qualified_id_expr (scope,
decl,
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;
}
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;
}
/* If ort == C_ORT_OMP_DECLARE_SIMD used as uniform_head instead. */
bitmap_initialize (&map_head, &bitmap_default_obstack);
bitmap_initialize (&map_field_head, &bitmap_default_obstack);
- /* If ort == C_ORT_OMP used as nontemporal_head instead. */
+ /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head
+ instead. */
bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack);
if (ort & C_ORT_ACC)
omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
- else if (ort == C_ORT_ACC
- && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+ else if ((ort == C_ORT_ACC
+ && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+ || (ort == C_ORT_OMP
+ && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR
+ || (OMP_CLAUSE_CODE (c)
+ == OMP_CLAUSE_USE_DEVICE_ADDR))))
{
if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t)))
{
error_at (OMP_CLAUSE_LOCATION (c),
- "%qD appears more than once in reduction clauses",
+ ort == C_ORT_ACC
+ ? "%qD appears more than once in reduction clauses"
+ : "%qD appears more than once in data clauses",
t);
remove = true;
}
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;
{
tree type = TREE_TYPE (t);
if (!TYPE_PTR_P (type)
- && TREE_CODE (type) != ARRAY_TYPE
- && (!TYPE_REF_P (type)
- || (!TYPE_PTR_P (TREE_TYPE (type))
- && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE)))
+ && (!TYPE_REF_P (type) || !TYPE_PTR_P (TREE_TYPE (type))))
{
- error_at (OMP_CLAUSE_LOCATION (c),
- "%qs variable is neither a pointer, nor an array "
- "nor reference to pointer or array",
- omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
- remove = true;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR
+ && ort == C_ORT_OMP)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qs variable is neither a pointer "
+ "nor reference to pointer",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (TREE_CODE (type) != ARRAY_TYPE
+ && (!TYPE_REF_P (type)
+ || TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qs variable is neither a pointer, nor an "
+ "array nor reference to pointer or array",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
}
}
goto check_dup_generic;
+ case OMP_CLAUSE_USE_DEVICE_ADDR:
+ field_ok = true;
+ t = OMP_CLAUSE_DECL (c);
+ if (!processing_template_decl
+ && (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
+ && !TYPE_REF_P (TREE_TYPE (t))
+ && !cxx_mark_addressable (t))
+ remove = true;
+ goto check_dup_generic;
+
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
case OMP_CLAUSE_SECTIONS:
case OMP_CLAUSE_TASKGROUP:
case OMP_CLAUSE_PROC_BIND:
+ case OMP_CLAUSE_DEVICE_TYPE:
case OMP_CLAUSE_NOGROUP:
case OMP_CLAUSE_THREADS:
case OMP_CLAUSE_SIMD:
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:
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. */
+ if (concept_check_p (orig_condition))
+ diagnose_constraints (location, orig_condition, NULL_TREE);
}
else if (condition && condition != error_mark_node)
{
/* Process a trait expression. */
tree
-finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
+finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
{
if (type1 == error_mark_node
|| type2 == error_mark_node)
TRAIT_EXPR_TYPE1 (trait_expr) = type1;
TRAIT_EXPR_TYPE2 (trait_expr) = type2;
TRAIT_EXPR_KIND (trait_expr) = kind;
+ TRAIT_EXPR_LOCATION (trait_expr) = loc;
return trait_expr;
}
gcc_unreachable ();
}
- return (trait_expr_value (kind, type1, type2)
- ? boolean_true_node : boolean_false_node);
+tree val = (trait_expr_value (kind, type1, type2)
+ ? boolean_true_node : boolean_false_node);
+ return maybe_wrap_with_location (val, loc);
}
/* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
#endif
cfun->returns_struct = aggr;
}
-
}
/* DECL is a local variable or parameter from the surrounding scope of a
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);