From patchwork Tue Aug 6 14:28:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 1142823 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-506319-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="nA0HmUrb"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 462xp25gxwz9sDB for ; Wed, 7 Aug 2019 00:28:42 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=RtoosGIvqcvXApAD1l5WBUmZaKR+fiiwGr/G5go874ojcTNllquq4 EPUkrUUGhyCIanU23CuD1S4mm/s0KwRT0buH4pSSeUpFYKe58ZonGofU3ALc07wC BdB4i2xn4JJLOOeyx3+P5M7nGT2I5XD4wHTzKLy9/XMgA/bajiMxBA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=aWw+MBf/1pc+ybOIyn48yDz2qO0=; b=nA0HmUrbkKWC/BDQ/VVF t/NRQHItP2QNZES70LeqThi1Q+Kd+Qo31FHPrQBlejYFKgklSGtR0i+pE0KKUI1m 6Zy0HbP0tk1UsESOgUurOndGpY76DyrL6Wc+BzLMQPltmQ0oD7vABrqbsaV56KiN OXkAqsUfs/fdfkXYVg6L0wg= Received: (qmail 11211 invoked by alias); 6 Aug 2019 14:28:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 11150 invoked by uid 89); 6 Aug 2019 14:28:18 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=want_rval X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 06 Aug 2019 14:28:15 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DDF7E309C387 for ; Tue, 6 Aug 2019 14:28:13 +0000 (UTC) Received: from redhat.com (unknown [10.20.4.51]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 50DA25DE5B; Tue, 6 Aug 2019 14:28:13 +0000 (UTC) Date: Tue, 6 Aug 2019 10:28:11 -0400 From: Marek Polacek To: GCC Patches , Jason Merrill Subject: C++ PATCH for c++/91346 - Implement C++2a P1668R1, allow unevaluated asm in constexpr Message-ID: <20190806142811.GG28284@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.12.1 (2019-06-15) This patch implements another C++2a feature, P1668R1: Permit unevaluated inline asm in constexpr functions. It's really straightforward so not much to say; we need to allow ASM_EXPRs in potential_constant_expression_1, but since only unevaluated asm is allowed, cxx_eval_constant_expression must give an error when it encounters an ASM_EXPR. I've improved location for "asm", so that the error points to "asm" rather than to ";". Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-08-06 Marek Polacek PR c++/91346 - Implement P1668R1, allow unevaluated asm in constexpr. * constexpr.c (cxx_eval_constant_expression): Handle ASM_EXPR. (potential_constant_expression_1) : Allow in C++2a, give an error otherwise. * cp-tree.h (finish_asm_stmt): Adjust. * parser.c (cp_parser_asm_definition): Grab the locaion of "asm" and use it. Adjust an error message. Allow asm in C++2a. * pt.c (tsubst_expr): Pass a location down to finish_asm_stmt. * semantics.c (finish_asm_stmt): New location_t parameter. Use it. * g++.dg/cpp2a/inline-asm1.C: New test. * g++.dg/cpp2a/inline-asm2.C: New test. * g++.dg/cpp1y/constexpr-neg1.C: Adjust dg-error. diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 36a66337433..d45e65df400 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -5289,6 +5289,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = void_node; break; + case ASM_EXPR: + if (!ctx->quiet) + { + error_at (cp_expr_loc_or_input_loc (t), + "inline assembly is not a constant expression"); + inform (cp_expr_loc_or_input_loc (t), + "only unevaluated inline assembly is allowed in a " + "% function in C++2a"); + } + *non_constant_p = true; + return t; + default: if (STATEMENT_CODE_P (TREE_CODE (t))) { @@ -6469,13 +6481,22 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, /* GCC internal stuff. */ case VA_ARG_EXPR: case TRANSACTION_EXPR: - case ASM_EXPR: case AT_ENCODE_EXPR: fail: if (flags & tf_error) error_at (loc, "expression %qE is not a constant expression", t); return false; + case ASM_EXPR: + if (cxx_dialect >= cxx2a) + /* In C++2a, unevaluated inline assembly is permitted in constexpr + functions. */ + return true; + else if (flags & tf_error) + error_at (loc, "inline assembly is not allowed in % " + "functions before C++2a"); + return false; + case OBJ_TYPE_REF: if (cxx_dialect >= cxx2a) /* In C++2a virtual calls can be constexpr, don't give up yet. */ diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index d4e67cdfd96..72ee1d61e97 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -7052,8 +7052,8 @@ enum { extern tree begin_compound_stmt (unsigned int); extern void finish_compound_stmt (tree); -extern tree finish_asm_stmt (int, tree, tree, tree, tree, - tree, bool); +extern tree finish_asm_stmt (location_t, int, tree, tree, + tree, tree, tree, bool); extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); extern cp_expr finish_parenthesized_expr (cp_expr); diff --git gcc/cp/parser.c gcc/cp/parser.c index 79da7b52eb9..2d0e6a0c931 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -19817,14 +19817,19 @@ cp_parser_asm_definition (cp_parser* parser) bool invalid_inputs_p = false; bool invalid_outputs_p = false; required_token missing = RT_NONE; + location_t asm_loc = cp_lexer_peek_token (parser->lexer)->location; /* Look for the `asm' keyword. */ cp_parser_require_keyword (parser, RID_ASM, RT_ASM); if (parser->in_function_body - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + /* In C++2a, unevaluated inline assembly is permitted in constexpr + functions. */ + && (cxx_dialect < cxx2a)) { - error ("% in % function"); + error_at (asm_loc, "% in % function only available " + "with %<-std=c++2a%> or %<-std=gnu++2a%>"); cp_function_chain->invalid_constexpr = true; } @@ -20032,7 +20037,7 @@ cp_parser_asm_definition (cp_parser* parser) /* Create the ASM_EXPR. */ if (parser->in_function_body) { - asm_stmt = finish_asm_stmt (volatile_p, string, outputs, + asm_stmt = finish_asm_stmt (asm_loc, volatile_p, string, outputs, inputs, clobbers, labels, inline_p); /* If the extended syntax was not used, mark the ASM_EXPR. */ if (!extended_p) diff --git gcc/cp/pt.c gcc/cp/pt.c index 903e589b663..85cff96c1b6 100644 --- gcc/cp/pt.c +++ gcc/cp/pt.c @@ -17394,8 +17394,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, complain, in_decl); tree labels = tsubst_copy_asm_operands (ASM_LABELS (t), args, complain, in_decl); - tmp = finish_asm_stmt (ASM_VOLATILE_P (t), string, outputs, inputs, - clobbers, labels, ASM_INLINE_P (t)); + tmp = finish_asm_stmt (EXPR_LOCATION (t), ASM_VOLATILE_P (t), string, + outputs, inputs, clobbers, labels, + ASM_INLINE_P (t)); tree asm_expr = tmp; if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR) asm_expr = TREE_OPERAND (asm_expr, 0); diff --git gcc/cp/semantics.c gcc/cp/semantics.c index fa6962454bf..83dc122e0bd 100644 --- gcc/cp/semantics.c +++ gcc/cp/semantics.c @@ -1484,8 +1484,9 @@ finish_compound_stmt (tree stmt) 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; @@ -1532,7 +1533,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, 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) @@ -1585,8 +1586,9 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, resolve the overloading. */ if (TREE_TYPE (operand) == unknown_type_node) { - error ("type of % operand %qE could not be determined", - TREE_VALUE (t)); + error_at (loc, + "type of % operand %qE could not be determined", + TREE_VALUE (t)); operand = error_mark_node; } @@ -1634,7 +1636,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, } } - 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; diff --git gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C index ae3dcc69cf0..d82dbada1bf 100644 --- gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C +++ gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C @@ -7,7 +7,7 @@ constexpr int f(int i) { thread_local int l = i; // { dg-error "thread_local" } goto foo; // { dg-error "goto" } foo: - asm("foo"); // { dg-error "asm" } + asm("foo"); // { dg-error "asm" "" { target c++17_down } } int k; // { dg-error "uninitialized" } A a; // { dg-error "non-literal" } return i; diff --git gcc/testsuite/g++.dg/cpp2a/inline-asm1.C gcc/testsuite/g++.dg/cpp2a/inline-asm1.C new file mode 100644 index 00000000000..9ac588f0ecc --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/inline-asm1.C @@ -0,0 +1,12 @@ +// P1668R1: Permit unevaluated inline asm in constexpr functions +// PR c++/91346 +// { dg-do compile { target c++11 } } + +constexpr int +foo (int a, int b) +{ + if (__builtin_is_constant_evaluated ()) + return a + b; + asm (""); // { dg-error ".asm. in .constexpr. function only available with" "" { target c++17_down } } + return a; +} diff --git gcc/testsuite/g++.dg/cpp2a/inline-asm2.C gcc/testsuite/g++.dg/cpp2a/inline-asm2.C new file mode 100644 index 00000000000..6038c111eb0 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/inline-asm2.C @@ -0,0 +1,17 @@ +// P1668R1: Permit unevaluated inline asm in constexpr functions +// PR c++/91346 +// { dg-do compile { target c++2a } } + +constexpr int +foo (bool b) +{ + if (b) + return 42; + asm (""); // { dg-error "inline assembly is not a constant expression" } +// { dg-message "only unevaluated inline assembly" "" { target *-*-* } .-1 } + return -1; +} + +constexpr int i = foo (true); +static_assert(i == 42, ""); +constexpr int j = foo (false); // { dg-message "in .constexpr. expansion of" }