Message ID | 20190823163230.GM14737@redhat.com |
---|---|
State | New |
Headers | show |
Series | C++ PATCH for P1152R4: Deprecating some uses of volatile (PR c++/91361) | expand |
On 8/23/19 9:32 AM, Marek Polacek wrote: > This patch implements another C++20 feature, partially deprecating volatile. > You can read the proposal here: <http://wg21.link/p1152r4>. I encourage > interested people to read the background in <http://wg21.link/p1152r0> which > provides a lot of interesting volatile-related information. > > Note that P1152R4 differs slightly from what's now in the standard: the mention > of "non-class type" was dropped. (Assignment to objects of a class type is > defined by the copy/move assignment operator.) > > The gist is that expressions that involve both load and store of a volatile > lvalue, such as ++ or += are deprecated, as are volatile-qualified parameter > and return types. Chained assignments of the form "a = b = c" are also > deprecated because there's some confusion as to if 'b' is re-read before storing > the value to 'a' (GCC claims not to do it). See Annex D [depr.volatile.type]. > > [expr.ass] further says that "A simple assignment whose left operand is of > a volatile-qualified type is deprecated unless the assignment is either > a discarded-value expression or appears in an unevaluated context." > and therein lies the rub. When parsing/building the MODIFY_EXPR, we don't know > if the assignment's value is going to be discared. We only know that after > mark_discarded_use has run, which for expression-statements takes place in > finish_expr_stmt -> conver_to_void, and that is quite late. It wouldn't work to warn in mark_[lr]value_use? Jason
On Fri, Aug 23, 2019 at 02:43:42PM -0700, Jason Merrill wrote: > On 8/23/19 9:32 AM, Marek Polacek wrote: > > This patch implements another C++20 feature, partially deprecating volatile. > > You can read the proposal here: <http://wg21.link/p1152r4>. I encourage > > interested people to read the background in <http://wg21.link/p1152r0> which > > provides a lot of interesting volatile-related information. > > > > Note that P1152R4 differs slightly from what's now in the standard: the mention > > of "non-class type" was dropped. (Assignment to objects of a class type is > > defined by the copy/move assignment operator.) > > > > The gist is that expressions that involve both load and store of a volatile > > lvalue, such as ++ or += are deprecated, as are volatile-qualified parameter > > and return types. Chained assignments of the form "a = b = c" are also > > deprecated because there's some confusion as to if 'b' is re-read before storing > > the value to 'a' (GCC claims not to do it). See Annex D [depr.volatile.type]. > > > > [expr.ass] further says that "A simple assignment whose left operand is of > > a volatile-qualified type is deprecated unless the assignment is either > > a discarded-value expression or appears in an unevaluated context." > > and therein lies the rub. When parsing/building the MODIFY_EXPR, we don't know > > if the assignment's value is going to be discared. We only know that after > > mark_discarded_use has run, which for expression-statements takes place in > > finish_expr_stmt -> conver_to_void, and that is quite late. > > It wouldn't work to warn in mark_[lr]value_use? My worry is that we might be calling those too often and generate redundant diagnostics but I'll have to play with that a bit before I can say for sure. Marek
On Fri, Aug 23, 2019 at 07:39:57PM -0400, Marek Polacek wrote: > On Fri, Aug 23, 2019 at 02:43:42PM -0700, Jason Merrill wrote: > > On 8/23/19 9:32 AM, Marek Polacek wrote: > > > This patch implements another C++20 feature, partially deprecating volatile. > > > You can read the proposal here: <http://wg21.link/p1152r4>. I encourage > > > interested people to read the background in <http://wg21.link/p1152r0> which > > > provides a lot of interesting volatile-related information. > > > > > > Note that P1152R4 differs slightly from what's now in the standard: the mention > > > of "non-class type" was dropped. (Assignment to objects of a class type is > > > defined by the copy/move assignment operator.) > > > > > > The gist is that expressions that involve both load and store of a volatile > > > lvalue, such as ++ or += are deprecated, as are volatile-qualified parameter > > > and return types. Chained assignments of the form "a = b = c" are also > > > deprecated because there's some confusion as to if 'b' is re-read before storing > > > the value to 'a' (GCC claims not to do it). See Annex D [depr.volatile.type]. > > > > > > [expr.ass] further says that "A simple assignment whose left operand is of > > > a volatile-qualified type is deprecated unless the assignment is either > > > a discarded-value expression or appears in an unevaluated context." > > > and therein lies the rub. When parsing/building the MODIFY_EXPR, we don't know > > > if the assignment's value is going to be discared. We only know that after > > > mark_discarded_use has run, which for expression-statements takes place in > > > finish_expr_stmt -> conver_to_void, and that is quite late. > > > > It wouldn't work to warn in mark_[lr]value_use? > > My worry is that we might be calling those too often and generate redundant > diagnostics but I'll have to play with that a bit before I can say for sure. So indeed we call mark_use multiple times on the same expr, but that is not an unsurmountable problem, I just need to use TREE_THIS_VOLATILE to prevent that. FWIW, using TREE_NO_WARNING didn't work for &(vi = i); because finish_parenthesized_expr sets TREE_NO_WARNING and so we wouldn't warn at all. But warning in mark_use did simplify things a bit, thanks for the suggestion. One nit is that we emit two warnings for vi = vi += 10; which could be fixed but I'm not entirely sure it's even worth it. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-08-26 Marek Polacek <polacek@redhat.com> Implement P1152R4: Deprecating some uses of volatile. PR c++/91361 * c-opts.c (c_common_post_options): Enable -Wvolatile by default for C++2a, unless -Wno-deprecated. * c.opt (Wvolatile): New warning. * cp-gimplify.c (cp_fold): Set TREE_THIS_VOLATILE. * decl.c (grokdeclarator): Warn about a volatile-qualified structured binding and return type. (grokparms): Warn about a volatile-qualified function parameter. * expr.c (mark_use) <case MODIFY_EXPR>: Emit a -Wvolatile warning. * typeck.c (cp_build_unary_op): Emit a -Wvolatile warning for pre and post ++/-- on a volatile operand. (genericize_compound_lvalue): Use a better location. Don't lose TREE_THIS_VOLATILE. (cp_build_modify_expr): Emit a -Wvolatile warning for a compound assignment whose LHS is volatile-qualified. Build the assignment with a more precise location. * doc/invoke.texi: Document -Wvolatile. * c-c++-common/Wbool-operation-1.c: Use -Wno-volatile in C++. * c-c++-common/gomp/atomic-1.c: Likewise. * c-c++-common/gomp/atomic-9.c: Likewise. * c-c++-common/gomp/depend-iterator-1.c: Likewise. * c-c++-common/gomp/loop-1.c: Adjust warning location for C++. * c-c++-common/gomp/order-3.c: Likewise. * c-c++-common/pr69733.c: Use -Wno-volatile in C++. * c-c++-common/spec-barrier-2.c: Likewise. * c-c++-common/tm/pr54893.c: Likewise. * g++.dg/cpp0x/pr65327.C: Add dg-warning. * g++.dg/cpp0x/rv-conv2.C: Likewise. * g++.dg/cpp0x/rv1n.C: Likewise. * g++.dg/cpp0x/rv1p.C: Likewise. * g++.dg/cpp0x/rv2n.C: Likewise. * g++.dg/cpp0x/rv2p.C: Likewise. * g++.dg/cpp0x/rv3n.C: Likewise. * g++.dg/cpp0x/rv3p.C: Likewise. * g++.dg/cpp0x/rv4n.C: Likewise. * g++.dg/cpp0x/rv4p.C: Likewise. * g++.dg/cpp0x/rv5n.C: Likewise. * g++.dg/cpp0x/rv5p.C: Likewise. * g++.dg/cpp0x/rv6n.C: Likewise. * g++.dg/cpp0x/rv6p.C: Likewise. * g++.dg/cpp0x/rv7n.C: Likewise. * g++.dg/cpp0x/rv7p.C: Likewise. * g++.dg/cpp0x/rv8p.C: Likewise. * g++.dg/cpp0x/trailing14.C: Use -Wno-volatile. * g++.dg/cpp1y/new1.C: Add dg-warning. * g++.dg/cpp2a/volatile1.C: New test. * g++.dg/cpp2a/volatile2.C: New test. * g++.dg/cpp2a/volatile3.C: New test. * g++.dg/cpp2a/volatile4.C: New test. * g++.dg/expr/bool3.C: Add dg-warning. * g++.dg/expr/bool4.C: Likewise. * g++.dg/expr/cond9.C: Likewise. * g++.dg/ext/vector25.C: Likewise. * g++.dg/gomp/depend-iterator-1.C: Use -Wno-volatile. * g++.dg/inherit/covariant21.C: Add dg-warning. * g++.dg/init/ref18.C: Likewise. * g++.dg/ipa/pr63838.C: Likewise. * g++.dg/overload/rvalue2.C: Likewise. * g++.dg/parse/semicolon4.C: Likewise. * g++.dg/warn/Wreturn-type-4.C: Likewise. * g++.dg/warn/pr36069.C: Likewise. * g++.old-deja/g++.mike/p9506.C: Likewise. * g++.old-deja/g++.other/volatile1.C: Likewise. diff --git gcc/c-family/c-opts.c gcc/c-family/c-opts.c index da783e4990c..fa8cd0ccb09 100644 --- gcc/c-family/c-opts.c +++ gcc/c-family/c-opts.c @@ -919,6 +919,10 @@ c_common_post_options (const char **pfilename) if (!global_options_set.x_warn_comma_subscript) warn_comma_subscript = (cxx_dialect >= cxx2a && warn_deprecated); + /* -Wvolatile is enabled by default in C++20. */ + if (!global_options_set.x_warn_volatile) + warn_volatile = (cxx_dialect >= cxx2a && warn_deprecated); + /* Declone C++ 'structors if -Os. */ if (flag_declone_ctor_dtor == -1) flag_declone_ctor_dtor = optimize_size; diff --git gcc/c-family/c.opt gcc/c-family/c.opt index 257cadfa5f1..5adb3c1bcd5 100644 --- gcc/c-family/c.opt +++ gcc/c-family/c.opt @@ -1221,6 +1221,10 @@ Wno-vla-larger-than C ObjC C++ LTO ObjC++ Alias(Wvla-larger-than=,18446744073709551615EiB,none) Warning -Wno-vla-larger-than Disable Wvla-larger-than= warning. Equivalent to Wvla-larger-than=<SIZE_MAX> or larger. +Wvolatile +C++ ObjC++ Var(warn_volatile) Warning +Warn about certain uses of volatile qualifier. + Wvolatile-register-var C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn when a register variable is declared volatile. diff --git gcc/cp/cp-gimplify.c gcc/cp/cp-gimplify.c index 065dcb7ba06..49fa47ac3af 100644 --- gcc/cp/cp-gimplify.c +++ gcc/cp/cp-gimplify.c @@ -2507,6 +2507,9 @@ cp_fold (tree x) else x = org_x; } + if (code == MODIFY_EXPR && TREE_CODE (x) == MODIFY_EXPR) + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); + break; case VEC_COND_EXPR: diff --git gcc/cp/decl.c gcc/cp/decl.c index 9f7923871db..de312c47c21 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -11189,6 +11189,10 @@ grokdeclarator (const cp_declarator *declarator, if (concept_p) error_at (declspecs->locations[ds_concept], "structured binding declaration cannot be %qs", "concept"); + /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ + if (type_quals & TYPE_QUAL_VOLATILE) + warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, + "%<volatile%>-qualified structured binding is deprecated"); switch (storage_class) { case sc_none: @@ -11579,6 +11583,13 @@ grokdeclarator (const cp_declarator *declarator, if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " "qualifiers ignored on function return type"); + /* [dcl.fct] "A volatile-qualified return type is + deprecated." */ + if (type_quals & TYPE_QUAL_VOLATILE) + warning_at (typespec_loc, OPT_Wvolatile, + "%<volatile%>-qualified return type is " + "deprecated"); + /* We now know that the TYPE_QUALS don't apply to the decl, but to its return type. */ type_quals = TYPE_UNQUALIFIED; @@ -13320,6 +13331,13 @@ grokparms (tree parmlist, tree *parms) cp_warn_deprecated_use (deptype); } + /* [dcl.fct] "A parameter with volatile-qualified type is + deprecated." */ + if (CP_TYPE_VOLATILE_P (type)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wvolatile, + "%<volatile%>-qualified parameter is " + "deprecated"); + /* Top-level qualifiers on the parameters are ignored for function types. */ type = cp_build_qualified_type (type, 0); diff --git gcc/cp/expr.c gcc/cp/expr.c index 9160043ed11..bb5097c988d 100644 --- gcc/cp/expr.c +++ gcc/cp/expr.c @@ -207,6 +207,27 @@ mark_use (tree expr, bool rvalue_p, bool read_p, recurse_op[0] = true; break; + case MODIFY_EXPR: + { + tree lhs = TREE_OPERAND (expr, 0); + /* [expr.ass] "A simple assignment whose left operand is of + a volatile-qualified type is deprecated unless the assignment + is either a discarded-value expression or appears in an + unevaluated context." */ + if (read_p + && (TREE_THIS_VOLATILE (lhs) + || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs))) + && !TREE_THIS_VOLATILE (expr)) + { + warning_at (location_of (expr), OPT_Wvolatile, + "assignment with %<volatile%>-qualified left " + "operand is deprecated"); + /* Make sure not to warn about this assignment again. */ + TREE_THIS_VOLATILE (expr) = true; + } + break; + } + default: break; } diff --git gcc/cp/typeck.c gcc/cp/typeck.c index e2a4f285a72..0acdf4e3426 100644 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -6459,6 +6459,17 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, complain)) return error_mark_node; + /* [depr.volatile.type] "Postfix ++ and -- expressions and + prefix ++ and -- expressions of volatile-qualified arithmetic + and pointer types are deprecated." */ + if (TREE_THIS_VOLATILE (arg) || CP_TYPE_VOLATILE_P (TREE_TYPE (arg))) + warning_at (location, OPT_Wvolatile, + "%qs expression of %<volatile%>-qualified type is " + "deprecated", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "++" : "--")); + /* Forbid using -- or ++ in C++17 on `bool'. */ if (TREE_CODE (declared_type) == BOOLEAN_TYPE) { @@ -8278,6 +8289,15 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype))) || MAYBE_CLASS_TYPE_P (lhstype))); + /* An expression of the form E1 op= E2. [expr.ass] says: + "Such expressions are deprecated if E1 has volatile-qualified + type." We warn here rather than in cp_genericize_r because + for compound assignments we are supposed to warn even if the + assignment is a discarded-value expression. */ + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) + warning_at (loc, OPT_Wvolatile, + "assignment with %<volatile%>-qualified left operand " + "is deprecated"); /* Preevaluate the RHS to make sure its evaluation is complete before the lvalue-to-rvalue conversion of the LHS: @@ -8450,8 +8470,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, goto ret; } - result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, - lhstype, lhs, newrhs); + result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, + lhstype, lhs, newrhs); TREE_SIDE_EFFECTS (result) = 1; if (!plain_assign) diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi index 549e043c67c..0ea2ae284ca 100644 --- gcc/doc/invoke.texi +++ gcc/doc/invoke.texi @@ -243,7 +243,7 @@ in the following sections. -Wno-non-template-friend -Wold-style-cast @gol -Woverloaded-virtual -Wno-pmf-conversions @gol -Wno-class-conversion -Wno-terminate @gol --Wsign-promo -Wvirtual-inheritance} +-Wsign-promo -Wvirtual-inheritance -Wvolatile} @item Objective-C and Objective-C++ Language Options @xref{Objective-C and Objective-C++ Dialect Options,,Options Controlling @@ -3515,6 +3515,18 @@ result in a call to @code{terminate}. Disable the warning about the case when a conversion function converts an object to the same type, to a base class of that type, or to void; such a conversion function will never be called. + +@item -Wvolatile @r{(C++ and Objective-C++ only)} +@opindex Wvolatile +@opindex Wno-volatile +Warn about certain uses of volatile qualifier. This includes postfix +@code{++} and @code{--} expressions, prefix @code{++} and @code{--} +expressions, certain assignments where the left operand is a +volatile-qualified non-class type, volatile-qualified function return +type, volatile-qualified parameter type, and a structured binding +of a volatile-qualified type. This usage was deprecated in C++2a. + +Enabled by default with @option{-std=c++2a}. @end table @node Objective-C and Objective-C++ Dialect Options diff --git gcc/testsuite/c-c++-common/Wbool-operation-1.c gcc/testsuite/c-c++-common/Wbool-operation-1.c index 04891878155..ce87705692a 100644 --- gcc/testsuite/c-c++-common/Wbool-operation-1.c +++ gcc/testsuite/c-c++-common/Wbool-operation-1.c @@ -1,6 +1,7 @@ /* PR c/77490 */ /* { dg-do compile } */ /* { dg-options "-Wall -Wno-psabi" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ #ifndef __cplusplus # define bool _Bool diff --git gcc/testsuite/c-c++-common/gomp/atomic-1.c gcc/testsuite/c-c++-common/gomp/atomic-1.c index 3e4bc569ba7..1facf4586f5 100644 --- gcc/testsuite/c-c++-common/gomp/atomic-1.c +++ gcc/testsuite/c-c++-common/gomp/atomic-1.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ int x; volatile int y; diff --git gcc/testsuite/c-c++-common/gomp/atomic-9.c gcc/testsuite/c-c++-common/gomp/atomic-9.c index c07da8fc712..35548395f36 100644 --- gcc/testsuite/c-c++-common/gomp/atomic-9.c +++ gcc/testsuite/c-c++-common/gomp/atomic-9.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-fopenmp -fdump-tree-ompexp" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* { dg-require-effective-target cas_int } */ volatile int *bar(void); diff --git gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c index 4fb01c174ec..6fa60215f43 100644 --- gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ + int arr[64], arr2[64]; struct S { int a[4]; } k; short arr4[4]; diff --git gcc/testsuite/c-c++-common/gomp/loop-1.c gcc/testsuite/c-c++-common/gomp/loop-1.c index d2f943aea54..4fb995c02a7 100644 --- gcc/testsuite/c-c++-common/gomp/loop-1.c +++ gcc/testsuite/c-c++-common/gomp/loop-1.c @@ -100,8 +100,8 @@ f4 (int *a) #pragma omp loop order(concurrent) bind(parallel) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop order(concurrent) bind(parallel) for (i = 0; i < 64; i++) @@ -172,8 +172,8 @@ f5 (int *a) #pragma omp loop for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop for (i = 0; i < 64; i++) @@ -245,8 +245,8 @@ f6 (int *a) #pragma omp loop for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop for (i = 0; i < 64; i++) diff --git gcc/testsuite/c-c++-common/gomp/order-3.c gcc/testsuite/c-c++-common/gomp/order-3.c index 2d51bf37749..e33386dd5cc 100644 --- gcc/testsuite/c-c++-common/gomp/order-3.c +++ gcc/testsuite/c-c++-common/gomp/order-3.c @@ -50,8 +50,8 @@ f1 (int *a) #pragma omp simd order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp simd order(concurrent) for (i = 0; i < 64; i++) @@ -112,8 +112,8 @@ f2 (int *a) #pragma omp for simd order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp for simd order(concurrent) for (i = 0; i < 64; i++) @@ -174,8 +174,8 @@ f3 (int *a) #pragma omp for order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp for order(concurrent) for (i = 0; i < 64; i++) diff --git gcc/testsuite/c-c++-common/pr69733.c gcc/testsuite/c-c++-common/pr69733.c index 57ec1eccb9f..ab70f49009c 100644 --- gcc/testsuite/c-c++-common/pr69733.c +++ gcc/testsuite/c-c++-common/pr69733.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-W -fdiagnostics-show-caret" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ typedef const double cd; double val; @@ -21,4 +22,3 @@ cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ cd val2() {return val;} ^~ { dg-end-multiline-output "" } */ - diff --git gcc/testsuite/c-c++-common/spec-barrier-2.c gcc/testsuite/c-c++-common/spec-barrier-2.c index b09567e62a9..a27ec54f0d3 100644 --- gcc/testsuite/c-c++-common/spec-barrier-2.c +++ gcc/testsuite/c-c++-common/spec-barrier-2.c @@ -1,4 +1,5 @@ /* { dg-do run } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* Even on targets that don't need the optional failval parameter, side-effects on the operand should still be calculated. */ diff --git gcc/testsuite/c-c++-common/tm/pr54893.c gcc/testsuite/c-c++-common/tm/pr54893.c index 3766078d31e..266cbe9c652 100644 --- gcc/testsuite/c-c++-common/tm/pr54893.c +++ gcc/testsuite/c-c++-common/tm/pr54893.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* Test that volatiles are allowed inside relaxed transactions. */ diff --git gcc/testsuite/g++.dg/cpp0x/pr65327.C gcc/testsuite/g++.dg/cpp0x/pr65327.C index 5176b3c3204..6e888ebff2c 100644 --- gcc/testsuite/g++.dg/cpp0x/pr65327.C +++ gcc/testsuite/g++.dg/cpp0x/pr65327.C @@ -11,7 +11,7 @@ foo () static constexpr volatile int k = 5; } -constexpr volatile int +constexpr volatile int // { dg-warning "deprecated" "" { target c++2a } } bar () { return i; diff --git gcc/testsuite/g++.dg/cpp0x/rv-conv2.C gcc/testsuite/g++.dg/cpp0x/rv-conv2.C index 9b9b154995b..2f2a1fa702a 100644 --- gcc/testsuite/g++.dg/cpp0x/rv-conv2.C +++ gcc/testsuite/g++.dg/cpp0x/rv-conv2.C @@ -1,16 +1,16 @@ // PR c++/89705 // { dg-do compile { target c++11 } } -struct W { operator const volatile int(); }; +struct W { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } const int& rci = W(); struct X { operator const int(); }; int&& rri = X(); -struct Y { operator volatile int(); }; +struct Y { operator volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } int&& rri2 = Y(); -struct Z { operator const volatile int(); }; +struct Z { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } volatile int&& rri3 = Z(); enum E { A }; diff --git gcc/testsuite/g++.dg/cpp0x/rv1n.C gcc/testsuite/g++.dg/cpp0x/rv1n.C index f5e75681758..a762fc85862 100644 --- gcc/testsuite/g++.dg/cpp0x/rv1n.C +++ gcc/testsuite/g++.dg/cpp0x/rv1n.C @@ -26,8 +26,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 1 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv1p.C gcc/testsuite/g++.dg/cpp0x/rv1p.C index a9097276d5a..e2a983a7708 100644 --- gcc/testsuite/g++.dg/cpp0x/rv1p.C +++ gcc/testsuite/g++.dg/cpp0x/rv1p.C @@ -26,8 +26,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 1 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv2n.C gcc/testsuite/g++.dg/cpp0x/rv2n.C index 65eda80fba0..2871ccf9ab3 100644 --- gcc/testsuite/g++.dg/cpp0x/rv2n.C +++ gcc/testsuite/g++.dg/cpp0x/rv2n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 2 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv2p.C gcc/testsuite/g++.dg/cpp0x/rv2p.C index 25a42ba2af8..bab0dce3d97 100644 --- gcc/testsuite/g++.dg/cpp0x/rv2p.C +++ gcc/testsuite/g++.dg/cpp0x/rv2p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 2 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv3n.C gcc/testsuite/g++.dg/cpp0x/rv3n.C index 4549438f8ef..35cdba95858 100644 --- gcc/testsuite/g++.dg/cpp0x/rv3n.C +++ gcc/testsuite/g++.dg/cpp0x/rv3n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 3 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv3p.C gcc/testsuite/g++.dg/cpp0x/rv3p.C index 2d7d78df6be..b25aa26c9b0 100644 --- gcc/testsuite/g++.dg/cpp0x/rv3p.C +++ gcc/testsuite/g++.dg/cpp0x/rv3p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 3 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv4n.C gcc/testsuite/g++.dg/cpp0x/rv4n.C index 29deb3fc81b..6941a13de6c 100644 --- gcc/testsuite/g++.dg/cpp0x/rv4n.C +++ gcc/testsuite/g++.dg/cpp0x/rv4n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 4 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv4p.C gcc/testsuite/g++.dg/cpp0x/rv4p.C index 0e4903bc291..cd0d631d780 100644 --- gcc/testsuite/g++.dg/cpp0x/rv4p.C +++ gcc/testsuite/g++.dg/cpp0x/rv4p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 4 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv5n.C gcc/testsuite/g++.dg/cpp0x/rv5n.C index f11d07a3921..086aa460c68 100644 --- gcc/testsuite/g++.dg/cpp0x/rv5n.C +++ gcc/testsuite/g++.dg/cpp0x/rv5n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 5 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv5p.C gcc/testsuite/g++.dg/cpp0x/rv5p.C index 63441a3f0da..34c1017f578 100644 --- gcc/testsuite/g++.dg/cpp0x/rv5p.C +++ gcc/testsuite/g++.dg/cpp0x/rv5p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 5 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv6n.C gcc/testsuite/g++.dg/cpp0x/rv6n.C index 0ebbe33e1d1..b21d22a5b87 100644 --- gcc/testsuite/g++.dg/cpp0x/rv6n.C +++ gcc/testsuite/g++.dg/cpp0x/rv6n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 6 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv6p.C gcc/testsuite/g++.dg/cpp0x/rv6p.C index 26714f0c9aa..fee692bb08f 100644 --- gcc/testsuite/g++.dg/cpp0x/rv6p.C +++ gcc/testsuite/g++.dg/cpp0x/rv6p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 6 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv7n.C gcc/testsuite/g++.dg/cpp0x/rv7n.C index d9e371b8adb..5bc313cc07f 100644 --- gcc/testsuite/g++.dg/cpp0x/rv7n.C +++ gcc/testsuite/g++.dg/cpp0x/rv7n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 7 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv7p.C gcc/testsuite/g++.dg/cpp0x/rv7p.C index 60a35835c7d..b0b8f965498 100644 --- gcc/testsuite/g++.dg/cpp0x/rv7p.C +++ gcc/testsuite/g++.dg/cpp0x/rv7p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 7 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv8p.C gcc/testsuite/g++.dg/cpp0x/rv8p.C index e12da4b8d79..287fb93b432 100644 --- gcc/testsuite/g++.dg/cpp0x/rv8p.C +++ gcc/testsuite/g++.dg/cpp0x/rv8p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 8 at a time diff --git gcc/testsuite/g++.dg/cpp0x/trailing14.C gcc/testsuite/g++.dg/cpp0x/trailing14.C index 2544d0bab5e..4ebb37406ad 100644 --- gcc/testsuite/g++.dg/cpp0x/trailing14.C +++ gcc/testsuite/g++.dg/cpp0x/trailing14.C @@ -1,6 +1,6 @@ // PR c++/65775 // { dg-do compile { target c++11 } } -// { dg-options "-Wignored-qualifiers" } +// { dg-options "-Wignored-qualifiers -Wno-volatile" } using Qi = int const volatile; Qi q1(); // { dg-warning "1: type qualifiers ignored" } diff --git gcc/testsuite/g++.dg/cpp1y/new1.C gcc/testsuite/g++.dg/cpp1y/new1.C index 5e4f1bf6b0b..b9ad64dfcc0 100644 --- gcc/testsuite/g++.dg/cpp1y/new1.C +++ gcc/testsuite/g++.dg/cpp1y/new1.C @@ -65,7 +65,7 @@ void test_unused() { volatile double d = 0.0; double *p = new double (); - d += 1.0; + d += 1.0; // { dg-warning "deprecated" "" { target c++2a } } delete p; } diff --git gcc/testsuite/g++.dg/cpp2a/volatile1.C gcc/testsuite/g++.dg/cpp2a/volatile1.C new file mode 100644 index 00000000000..16c3bb417d3 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile1.C @@ -0,0 +1,140 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++17 } } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } } +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" "" { target c++2a } } +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + (vi = 42, 45); + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + (void)(vi = i); + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + i *= vi; + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + volatile T t; + t.a = 3; + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile2.C gcc/testsuite/g++.dg/cpp2a/volatile2.C new file mode 100644 index 00000000000..31035e22d8f --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile2.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++2a } } +// { dg-options "-Wno-volatile" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int +fn (volatile int i) +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; + ++v; + v--; + --v; + p++; + ++p; + p--; + --p; + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; + &(vi = i); + (vi = 42, 45); + (i = vi = 42, 10); + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); + (void)(vi = i); + (void)(i = vi = 42); + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; + vi -= i; + vi %= i; + vi ^= i; + vi |= i; + vi /= i; + vi = vi += 42; + vi += vi = 42; + i *= vi; + decltype(vi -= 42) x2 = vi; + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; + volatile auto & [vxr, vyr] = a; +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; + u.c += 42; + + volatile T t; + t.a = 3; + j = t.a = 3; + t.a += 3; + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; + t &= 42; +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile3.C gcc/testsuite/g++.dg/cpp2a/volatile3.C new file mode 100644 index 00000000000..731c9aec99f --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile3.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++17 } } +// { dg-options "-Wvolatile" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" } +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" } +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + (vi = 42, 45); + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + (void)(vi = i); + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + i *= vi; + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + volatile T t; + t.a = 3; + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile4.C gcc/testsuite/g++.dg/cpp2a/volatile4.C new file mode 100644 index 00000000000..4d039545ac9 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile4.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++2a } } +// { dg-options "-Wno-deprecated" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int +fn (volatile int i) +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; + ++v; + v--; + --v; + p++; + ++p; + p--; + --p; + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; + &(vi = i); + (vi = 42, 45); + (i = vi = 42, 10); + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); + (void)(vi = i); + (void)(i = vi = 42); + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; + vi -= i; + vi %= i; + vi ^= i; + vi |= i; + vi /= i; + vi = vi += 42; + vi += vi = 42; + i *= vi; + decltype(vi -= 42) x2 = vi; + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; + volatile auto & [vxr, vyr] = a; +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; + u.c += 42; + + volatile T t; + t.a = 3; + j = t.a = 3; + t.a += 3; + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; + t &= 42; +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/expr/bool3.C gcc/testsuite/g++.dg/expr/bool3.C index 373c202b800..f27399cfc8a 100644 --- gcc/testsuite/g++.dg/expr/bool3.C +++ gcc/testsuite/g++.dg/expr/bool3.C @@ -13,8 +13,10 @@ int main() b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } // { dg-error "forbidden" "" { target c++17 } .-1 } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } // { dg-error "forbidden" "" { target c++17 } .-1 } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } i = b; if (i != 1) abort (); diff --git gcc/testsuite/g++.dg/expr/bool4.C gcc/testsuite/g++.dg/expr/bool4.C index dce51ec332e..5891bc311bd 100644 --- gcc/testsuite/g++.dg/expr/bool4.C +++ gcc/testsuite/g++.dg/expr/bool4.C @@ -8,6 +8,6 @@ int main() { my_bool b = false; b--; // { dg-error "" } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-1 } return 0; } - diff --git gcc/testsuite/g++.dg/expr/cond9.C gcc/testsuite/g++.dg/expr/cond9.C index b344c1f683a..f7e092e1445 100644 --- gcc/testsuite/g++.dg/expr/cond9.C +++ gcc/testsuite/g++.dg/expr/cond9.C @@ -4,7 +4,7 @@ struct A { // { dg-message "A" } A(int); }; -void foo(volatile A a) { +void foo(volatile A a) { // { dg-warning "deprecated" "" { target c++2a } } 1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" } 1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" } } diff --git gcc/testsuite/g++.dg/ext/vector25.C gcc/testsuite/g++.dg/ext/vector25.C index 6c1f5d09878..339865d6942 100644 --- gcc/testsuite/g++.dg/ext/vector25.C +++ gcc/testsuite/g++.dg/ext/vector25.C @@ -2,5 +2,5 @@ volatile int i __attribute__((vector_size(8))); void foo() { - i += i; + i += i; // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.dg/gomp/depend-iterator-1.C gcc/testsuite/g++.dg/gomp/depend-iterator-1.C index 6f4aa97ee44..d12670c5159 100644 --- gcc/testsuite/g++.dg/gomp/depend-iterator-1.C +++ gcc/testsuite/g++.dg/gomp/depend-iterator-1.C @@ -1,3 +1,5 @@ +// { dg-additional-options "-Wno-volatile" } + int arr[64], arr2[64]; struct S { int a[4]; } k; short arr4[4]; diff --git gcc/testsuite/g++.dg/inherit/covariant21.C gcc/testsuite/g++.dg/inherit/covariant21.C index 42cdf870081..769cb14ecbc 100644 --- gcc/testsuite/g++.dg/inherit/covariant21.C +++ gcc/testsuite/g++.dg/inherit/covariant21.C @@ -6,12 +6,12 @@ struct C : A, B {}; struct X { - virtual B* foo(volatile int); + virtual B* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } }; struct Y : X { - virtual C* foo(volatile int); + virtual C* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } }; -C* Y::foo(volatile int) { return 0; } +C* Y::foo(volatile int) { return 0; } // { dg-warning "deprecated" "" { target c++2a } } diff --git gcc/testsuite/g++.dg/init/ref18.C gcc/testsuite/g++.dg/init/ref18.C index e704077c26b..81ac76a40d3 100644 --- gcc/testsuite/g++.dg/init/ref18.C +++ gcc/testsuite/g++.dg/init/ref18.C @@ -1,6 +1,6 @@ // PR c++/49395 -volatile int foo(); +volatile int foo(); // { dg-warning "deprecated" "" { target c++2a } } struct A { volatile int i; }; typedef volatile int vi; diff --git gcc/testsuite/g++.dg/ipa/pr63838.C gcc/testsuite/g++.dg/ipa/pr63838.C index d23b3133748..5b6b11d70e5 100644 --- gcc/testsuite/g++.dg/ipa/pr63838.C +++ gcc/testsuite/g++.dg/ipa/pr63838.C @@ -7,12 +7,12 @@ __attribute__((noinline, noclone)) static void bar (int); volatile int v; void (*fn) (); -struct S { S () { v++; } ~S () { v++; } }; +struct S { S () { v++; } ~S () { v++; } }; // { dg-warning "deprecated" "" { target c++2a } } __attribute__((noinline, noclone)) static void foo (int x) { - v++; + v++; // { dg-warning "deprecated" "" { target c++2a } } if (x == 5) bar (x); } @@ -20,7 +20,7 @@ foo (int x) __attribute__((noinline, noclone)) static void bar (int x) { - v++; + v++; // { dg-warning "deprecated" "" { target c++2a } } if (x == 6) foo (x); else if (x == 5) diff --git gcc/testsuite/g++.dg/overload/rvalue2.C gcc/testsuite/g++.dg/overload/rvalue2.C index 8a2290dc293..a829fb5e8cc 100644 --- gcc/testsuite/g++.dg/overload/rvalue2.C +++ gcc/testsuite/g++.dg/overload/rvalue2.C @@ -7,5 +7,5 @@ template <class T> void f(const T&); int main() { volatile int i = 0; - f(i++); + f(i++); // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.dg/parse/semicolon4.C gcc/testsuite/g++.dg/parse/semicolon4.C index 5135ec14b1f..bdd1c845187 100644 --- gcc/testsuite/g++.dg/parse/semicolon4.C +++ gcc/testsuite/g++.dg/parse/semicolon4.C @@ -25,7 +25,7 @@ struct E1 } const; // { dg-error "'const' can only be specified for objects and functions" } void foo ( -struct E2 +struct E2 // { dg-warning "deprecated" "" { target c++2a } } { // { dg-error "types may not be defined in parameter types" } int i; } volatile); diff --git gcc/testsuite/g++.dg/warn/Wreturn-type-4.C gcc/testsuite/g++.dg/warn/Wreturn-type-4.C index 4f02678e7f9..24a6b41cbd8 100644 --- gcc/testsuite/g++.dg/warn/Wreturn-type-4.C +++ gcc/testsuite/g++.dg/warn/Wreturn-type-4.C @@ -3,6 +3,7 @@ /* { dg-options "-Wignored-qualifiers" } */ volatile void bar(); /* { dg-warning "type qualifiers ignored" } */ +// { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } .-1 } struct A { diff --git gcc/testsuite/g++.dg/warn/pr36069.C gcc/testsuite/g++.dg/warn/pr36069.C index efb35c25716..7b166351a4b 100644 --- gcc/testsuite/g++.dg/warn/pr36069.C +++ gcc/testsuite/g++.dg/warn/pr36069.C @@ -6,11 +6,13 @@ struct foo { bool a; volatile bool b,c; foo() { a = b = c = false; } // { dg-bogus "parentheses" } + // { dg-warning "deprecated" "" { target c++2a } .-1 } }; int main() { bool a; volatile bool b,c; a = b = c = false; // { dg-bogus "parentheses" } + // { dg-warning "deprecated" "" { target c++2a } .-1 } foo A; } diff --git gcc/testsuite/g++.old-deja/g++.mike/p9506.C gcc/testsuite/g++.old-deja/g++.mike/p9506.C index db16e3738e2..97594640f96 100644 --- gcc/testsuite/g++.old-deja/g++.mike/p9506.C +++ gcc/testsuite/g++.old-deja/g++.mike/p9506.C @@ -3,5 +3,5 @@ char * volatile p; void foo() { - --p = 0; + --p = 0; // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.old-deja/g++.other/volatile1.C gcc/testsuite/g++.old-deja/g++.other/volatile1.C index 7d818fbe9e1..a93ef58aa9f 100644 --- gcc/testsuite/g++.old-deja/g++.other/volatile1.C +++ gcc/testsuite/g++.old-deja/g++.other/volatile1.C @@ -5,7 +5,7 @@ class f_class // { dg-message "note" "candidates" } { }; -volatile f_class +volatile f_class // { dg-warning "deprecated" "" { target c++2a } } ret_v_f_class() { f_class t;
On 8/26/19 1:46 PM, Marek Polacek wrote: > On Fri, Aug 23, 2019 at 07:39:57PM -0400, Marek Polacek wrote: >> On Fri, Aug 23, 2019 at 02:43:42PM -0700, Jason Merrill wrote: >>> On 8/23/19 9:32 AM, Marek Polacek wrote: >>>> This patch implements another C++20 feature, partially deprecating volatile. >>>> You can read the proposal here: <http://wg21.link/p1152r4>. I encourage >>>> interested people to read the background in <http://wg21.link/p1152r0> which >>>> provides a lot of interesting volatile-related information. >>>> >>>> Note that P1152R4 differs slightly from what's now in the standard: the mention >>>> of "non-class type" was dropped. (Assignment to objects of a class type is >>>> defined by the copy/move assignment operator.) >>>> >>>> The gist is that expressions that involve both load and store of a volatile >>>> lvalue, such as ++ or += are deprecated, as are volatile-qualified parameter >>>> and return types. Chained assignments of the form "a = b = c" are also >>>> deprecated because there's some confusion as to if 'b' is re-read before storing >>>> the value to 'a' (GCC claims not to do it). See Annex D [depr.volatile.type]. >>>> >>>> [expr.ass] further says that "A simple assignment whose left operand is of >>>> a volatile-qualified type is deprecated unless the assignment is either >>>> a discarded-value expression or appears in an unevaluated context." >>>> and therein lies the rub. When parsing/building the MODIFY_EXPR, we don't know >>>> if the assignment's value is going to be discared. We only know that after >>>> mark_discarded_use has run, which for expression-statements takes place in >>>> finish_expr_stmt -> conver_to_void, and that is quite late. >>> >>> It wouldn't work to warn in mark_[lr]value_use? >> >> My worry is that we might be calling those too often and generate redundant >> diagnostics but I'll have to play with that a bit before I can say for sure. > > So indeed we call mark_use multiple times on the same expr, but that is not an > unsurmountable problem, I just need to use TREE_THIS_VOLATILE to prevent that. > FWIW, using TREE_NO_WARNING didn't work for > > &(vi = i); > > because finish_parenthesized_expr sets TREE_NO_WARNING and so we wouldn't warn > at all. But warning in mark_use did simplify things a bit, thanks for the > suggestion. > > One nit is that we emit two warnings for > > vi = vi += 10; > > which could be fixed but I'm not entirely sure it's even worth it. > > Bootstrapped/regtested on x86_64-linux, ok for trunk? > > 2019-08-26 Marek Polacek <polacek@redhat.com> > > Implement P1152R4: Deprecating some uses of volatile. > PR c++/91361 > * c-opts.c (c_common_post_options): Enable -Wvolatile by > default for C++2a, unless -Wno-deprecated. > * c.opt (Wvolatile): New warning. > > * cp-gimplify.c (cp_fold): Set TREE_THIS_VOLATILE. > * decl.c (grokdeclarator): Warn about a volatile-qualified structured > binding and return type. > (grokparms): Warn about a volatile-qualified function parameter. > * expr.c (mark_use) <case MODIFY_EXPR>: Emit a -Wvolatile warning. > * typeck.c (cp_build_unary_op): Emit a -Wvolatile warning for pre and > post ++/-- on a volatile operand. > (genericize_compound_lvalue): Use a better location. Don't lose > TREE_THIS_VOLATILE. > (cp_build_modify_expr): Emit a -Wvolatile warning for a compound > assignment whose LHS is volatile-qualified. Build the assignment with > a more precise location. > > * doc/invoke.texi: Document -Wvolatile. > > * c-c++-common/Wbool-operation-1.c: Use -Wno-volatile in C++. > * c-c++-common/gomp/atomic-1.c: Likewise. > * c-c++-common/gomp/atomic-9.c: Likewise. > * c-c++-common/gomp/depend-iterator-1.c: Likewise. > * c-c++-common/gomp/loop-1.c: Adjust warning location for C++. > * c-c++-common/gomp/order-3.c: Likewise. > * c-c++-common/pr69733.c: Use -Wno-volatile in C++. > * c-c++-common/spec-barrier-2.c: Likewise. > * c-c++-common/tm/pr54893.c: Likewise. > * g++.dg/cpp0x/pr65327.C: Add dg-warning. > * g++.dg/cpp0x/rv-conv2.C: Likewise. > * g++.dg/cpp0x/rv1n.C: Likewise. > * g++.dg/cpp0x/rv1p.C: Likewise. > * g++.dg/cpp0x/rv2n.C: Likewise. > * g++.dg/cpp0x/rv2p.C: Likewise. > * g++.dg/cpp0x/rv3n.C: Likewise. > * g++.dg/cpp0x/rv3p.C: Likewise. > * g++.dg/cpp0x/rv4n.C: Likewise. > * g++.dg/cpp0x/rv4p.C: Likewise. > * g++.dg/cpp0x/rv5n.C: Likewise. > * g++.dg/cpp0x/rv5p.C: Likewise. > * g++.dg/cpp0x/rv6n.C: Likewise. > * g++.dg/cpp0x/rv6p.C: Likewise. > * g++.dg/cpp0x/rv7n.C: Likewise. > * g++.dg/cpp0x/rv7p.C: Likewise. > * g++.dg/cpp0x/rv8p.C: Likewise. > * g++.dg/cpp0x/trailing14.C: Use -Wno-volatile. > * g++.dg/cpp1y/new1.C: Add dg-warning. > * g++.dg/cpp2a/volatile1.C: New test. > * g++.dg/cpp2a/volatile2.C: New test. > * g++.dg/cpp2a/volatile3.C: New test. > * g++.dg/cpp2a/volatile4.C: New test. > * g++.dg/expr/bool3.C: Add dg-warning. > * g++.dg/expr/bool4.C: Likewise. > * g++.dg/expr/cond9.C: Likewise. > * g++.dg/ext/vector25.C: Likewise. > * g++.dg/gomp/depend-iterator-1.C: Use -Wno-volatile. > * g++.dg/inherit/covariant21.C: Add dg-warning. > * g++.dg/init/ref18.C: Likewise. > * g++.dg/ipa/pr63838.C: Likewise. > * g++.dg/overload/rvalue2.C: Likewise. > * g++.dg/parse/semicolon4.C: Likewise. > * g++.dg/warn/Wreturn-type-4.C: Likewise. > * g++.dg/warn/pr36069.C: Likewise. > * g++.old-deja/g++.mike/p9506.C: Likewise. > * g++.old-deja/g++.other/volatile1.C: Likewise. > > diff --git gcc/c-family/c-opts.c gcc/c-family/c-opts.c > index da783e4990c..fa8cd0ccb09 100644 > --- gcc/c-family/c-opts.c > +++ gcc/c-family/c-opts.c > @@ -919,6 +919,10 @@ c_common_post_options (const char **pfilename) > if (!global_options_set.x_warn_comma_subscript) > warn_comma_subscript = (cxx_dialect >= cxx2a && warn_deprecated); > > + /* -Wvolatile is enabled by default in C++20. */ > + if (!global_options_set.x_warn_volatile) > + warn_volatile = (cxx_dialect >= cxx2a && warn_deprecated); > + > /* Declone C++ 'structors if -Os. */ > if (flag_declone_ctor_dtor == -1) > flag_declone_ctor_dtor = optimize_size; > diff --git gcc/c-family/c.opt gcc/c-family/c.opt > index 257cadfa5f1..5adb3c1bcd5 100644 > --- gcc/c-family/c.opt > +++ gcc/c-family/c.opt > @@ -1221,6 +1221,10 @@ Wno-vla-larger-than > C ObjC C++ LTO ObjC++ Alias(Wvla-larger-than=,18446744073709551615EiB,none) Warning > -Wno-vla-larger-than Disable Wvla-larger-than= warning. Equivalent to Wvla-larger-than=<SIZE_MAX> or larger. > > +Wvolatile > +C++ ObjC++ Var(warn_volatile) Warning > +Warn about certain uses of volatile qualifier. Maybe "deprecated uses"? > + > Wvolatile-register-var > C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) > Warn when a register variable is declared volatile. > diff --git gcc/cp/cp-gimplify.c gcc/cp/cp-gimplify.c > index 065dcb7ba06..49fa47ac3af 100644 > --- gcc/cp/cp-gimplify.c > +++ gcc/cp/cp-gimplify.c > @@ -2507,6 +2507,9 @@ cp_fold (tree x) > else > x = org_x; > } > + if (code == MODIFY_EXPR && TREE_CODE (x) == MODIFY_EXPR) > + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); > + > break; > > case VEC_COND_EXPR: > diff --git gcc/cp/decl.c gcc/cp/decl.c > index 9f7923871db..de312c47c21 100644 > --- gcc/cp/decl.c > +++ gcc/cp/decl.c > @@ -11189,6 +11189,10 @@ grokdeclarator (const cp_declarator *declarator, > if (concept_p) > error_at (declspecs->locations[ds_concept], > "structured binding declaration cannot be %qs", "concept"); > + /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ > + if (type_quals & TYPE_QUAL_VOLATILE) > + warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, > + "%<volatile%>-qualified structured binding is deprecated"); > switch (storage_class) > { > case sc_none: > @@ -11579,6 +11583,13 @@ grokdeclarator (const cp_declarator *declarator, > if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) > warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " > "qualifiers ignored on function return type"); > + /* [dcl.fct] "A volatile-qualified return type is > + deprecated." */ > + if (type_quals & TYPE_QUAL_VOLATILE) > + warning_at (typespec_loc, OPT_Wvolatile, > + "%<volatile%>-qualified return type is " > + "deprecated"); > + > /* We now know that the TYPE_QUALS don't apply to the > decl, but to its return type. */ > type_quals = TYPE_UNQUALIFIED; > @@ -13320,6 +13331,13 @@ grokparms (tree parmlist, tree *parms) > cp_warn_deprecated_use (deptype); > } > > + /* [dcl.fct] "A parameter with volatile-qualified type is > + deprecated." */ > + if (CP_TYPE_VOLATILE_P (type)) > + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wvolatile, > + "%<volatile%>-qualified parameter is " > + "deprecated"); > + > /* Top-level qualifiers on the parameters are > ignored for function types. */ > type = cp_build_qualified_type (type, 0); > diff --git gcc/cp/expr.c gcc/cp/expr.c > index 9160043ed11..bb5097c988d 100644 > --- gcc/cp/expr.c > +++ gcc/cp/expr.c > @@ -207,6 +207,27 @@ mark_use (tree expr, bool rvalue_p, bool read_p, > recurse_op[0] = true; > break; > > + case MODIFY_EXPR: > + { > + tree lhs = TREE_OPERAND (expr, 0); > + /* [expr.ass] "A simple assignment whose left operand is of > + a volatile-qualified type is deprecated unless the assignment > + is either a discarded-value expression or appears in an > + unevaluated context." */ > + if (read_p > + && (TREE_THIS_VOLATILE (lhs) > + || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs))) > + && !TREE_THIS_VOLATILE (expr)) > + { > + warning_at (location_of (expr), OPT_Wvolatile, > + "assignment with %<volatile%>-qualified left " > + "operand is deprecated"); This should be more specific; the assignment itself isn't deprecated, but rather using the assignment as an lvalue or rvalue. > + /* Make sure not to warn about this assignment again. */ > + TREE_THIS_VOLATILE (expr) = true; > + } > + break; > + } > + > default: > break; > } > diff --git gcc/cp/typeck.c gcc/cp/typeck.c > index e2a4f285a72..0acdf4e3426 100644 > --- gcc/cp/typeck.c > +++ gcc/cp/typeck.c > @@ -6459,6 +6459,17 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, > complain)) > return error_mark_node; > > + /* [depr.volatile.type] "Postfix ++ and -- expressions and > + prefix ++ and -- expressions of volatile-qualified arithmetic > + and pointer types are deprecated." */ > + if (TREE_THIS_VOLATILE (arg) || CP_TYPE_VOLATILE_P (TREE_TYPE (arg))) > + warning_at (location, OPT_Wvolatile, > + "%qs expression of %<volatile%>-qualified type is " > + "deprecated", > + ((code == PREINCREMENT_EXPR > + || code == POSTINCREMENT_EXPR) > + ? "++" : "--")); > + > /* Forbid using -- or ++ in C++17 on `bool'. */ > if (TREE_CODE (declared_type) == BOOLEAN_TYPE) > { > @@ -8278,6 +8289,15 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype))) > || MAYBE_CLASS_TYPE_P (lhstype))); > > + /* An expression of the form E1 op= E2. [expr.ass] says: > + "Such expressions are deprecated if E1 has volatile-qualified > + type." We warn here rather than in cp_genericize_r because > + for compound assignments we are supposed to warn even if the > + assignment is a discarded-value expression. */ > + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) > + warning_at (loc, OPT_Wvolatile, > + "assignment with %<volatile%>-qualified left operand " > + "is deprecated"); And this should say "compound assignment ..." > /* Preevaluate the RHS to make sure its evaluation is complete > before the lvalue-to-rvalue conversion of the LHS: > > @@ -8450,8 +8470,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > goto ret; > } > > - result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, > - lhstype, lhs, newrhs); > + result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, > + lhstype, lhs, newrhs); > > TREE_SIDE_EFFECTS (result) = 1; > if (!plain_assign) > diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi > index 549e043c67c..0ea2ae284ca 100644 > --- gcc/doc/invoke.texi > +++ gcc/doc/invoke.texi > @@ -243,7 +243,7 @@ in the following sections. > -Wno-non-template-friend -Wold-style-cast @gol > -Woverloaded-virtual -Wno-pmf-conversions @gol > -Wno-class-conversion -Wno-terminate @gol > --Wsign-promo -Wvirtual-inheritance} > +-Wsign-promo -Wvirtual-inheritance -Wvolatile} > > @item Objective-C and Objective-C++ Language Options > @xref{Objective-C and Objective-C++ Dialect Options,,Options Controlling > @@ -3515,6 +3515,18 @@ result in a call to @code{terminate}. > Disable the warning about the case when a conversion function converts an > object to the same type, to a base class of that type, or to void; such > a conversion function will never be called. > + > +@item -Wvolatile @r{(C++ and Objective-C++ only)} > +@opindex Wvolatile > +@opindex Wno-volatile > +Warn about certain uses of volatile qualifier. This includes postfix > +@code{++} and @code{--} expressions, prefix @code{++} and @code{--} > +expressions, certain assignments where the left operand is a > +volatile-qualified non-class type This should also be more specific. , volatile-qualified function return > +type, volatile-qualified parameter type, and a structured binding > +of a volatile-qualified type. This usage was deprecated in C++2a. > + > +Enabled by default with @option{-std=c++2a}. > @end table > > @node Objective-C and Objective-C++ Dialect Options > diff --git gcc/testsuite/c-c++-common/Wbool-operation-1.c gcc/testsuite/c-c++-common/Wbool-operation-1.c > index 04891878155..ce87705692a 100644 > --- gcc/testsuite/c-c++-common/Wbool-operation-1.c > +++ gcc/testsuite/c-c++-common/Wbool-operation-1.c > @@ -1,6 +1,7 @@ > /* PR c/77490 */ > /* { dg-do compile } */ > /* { dg-options "-Wall -Wno-psabi" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > #ifndef __cplusplus > # define bool _Bool > diff --git gcc/testsuite/c-c++-common/gomp/atomic-1.c gcc/testsuite/c-c++-common/gomp/atomic-1.c > index 3e4bc569ba7..1facf4586f5 100644 > --- gcc/testsuite/c-c++-common/gomp/atomic-1.c > +++ gcc/testsuite/c-c++-common/gomp/atomic-1.c > @@ -1,4 +1,5 @@ > /* { dg-do compile } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > int x; > volatile int y; > diff --git gcc/testsuite/c-c++-common/gomp/atomic-9.c gcc/testsuite/c-c++-common/gomp/atomic-9.c > index c07da8fc712..35548395f36 100644 > --- gcc/testsuite/c-c++-common/gomp/atomic-9.c > +++ gcc/testsuite/c-c++-common/gomp/atomic-9.c > @@ -1,5 +1,6 @@ > /* { dg-do compile } */ > /* { dg-options "-fopenmp -fdump-tree-ompexp" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > /* { dg-require-effective-target cas_int } */ > > volatile int *bar(void); > diff --git gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c > index 4fb01c174ec..6fa60215f43 100644 > --- gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c > +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c > @@ -1,3 +1,5 @@ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > + > int arr[64], arr2[64]; > struct S { int a[4]; } k; > short arr4[4]; > diff --git gcc/testsuite/c-c++-common/gomp/loop-1.c gcc/testsuite/c-c++-common/gomp/loop-1.c > index d2f943aea54..4fb995c02a7 100644 > --- gcc/testsuite/c-c++-common/gomp/loop-1.c > +++ gcc/testsuite/c-c++-common/gomp/loop-1.c > @@ -100,8 +100,8 @@ f4 (int *a) > #pragma omp loop order(concurrent) bind(parallel) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ > } > #pragma omp loop order(concurrent) bind(parallel) > for (i = 0; i < 64; i++) > @@ -172,8 +172,8 @@ f5 (int *a) > #pragma omp loop > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ > } > #pragma omp loop > for (i = 0; i < 64; i++) > @@ -245,8 +245,8 @@ f6 (int *a) > #pragma omp loop > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ > } > #pragma omp loop > for (i = 0; i < 64; i++) > diff --git gcc/testsuite/c-c++-common/gomp/order-3.c gcc/testsuite/c-c++-common/gomp/order-3.c > index 2d51bf37749..e33386dd5cc 100644 > --- gcc/testsuite/c-c++-common/gomp/order-3.c > +++ gcc/testsuite/c-c++-common/gomp/order-3.c > @@ -50,8 +50,8 @@ f1 (int *a) > #pragma omp simd order(concurrent) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ > } > #pragma omp simd order(concurrent) > for (i = 0; i < 64; i++) > @@ -112,8 +112,8 @@ f2 (int *a) > #pragma omp for simd order(concurrent) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ > } > #pragma omp for simd order(concurrent) > for (i = 0; i < 64; i++) > @@ -174,8 +174,8 @@ f3 (int *a) > #pragma omp for order(concurrent) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ > } > #pragma omp for order(concurrent) > for (i = 0; i < 64; i++) > diff --git gcc/testsuite/c-c++-common/pr69733.c gcc/testsuite/c-c++-common/pr69733.c > index 57ec1eccb9f..ab70f49009c 100644 > --- gcc/testsuite/c-c++-common/pr69733.c > +++ gcc/testsuite/c-c++-common/pr69733.c > @@ -1,5 +1,6 @@ > /* { dg-do compile } */ > /* { dg-options "-W -fdiagnostics-show-caret" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > typedef const double cd; > double val; > @@ -21,4 +22,3 @@ cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ > cd val2() {return val;} > ^~ > { dg-end-multiline-output "" } */ > - > diff --git gcc/testsuite/c-c++-common/spec-barrier-2.c gcc/testsuite/c-c++-common/spec-barrier-2.c > index b09567e62a9..a27ec54f0d3 100644 > --- gcc/testsuite/c-c++-common/spec-barrier-2.c > +++ gcc/testsuite/c-c++-common/spec-barrier-2.c > @@ -1,4 +1,5 @@ > /* { dg-do run } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > /* Even on targets that don't need the optional failval parameter, > side-effects on the operand should still be calculated. */ > diff --git gcc/testsuite/c-c++-common/tm/pr54893.c gcc/testsuite/c-c++-common/tm/pr54893.c > index 3766078d31e..266cbe9c652 100644 > --- gcc/testsuite/c-c++-common/tm/pr54893.c > +++ gcc/testsuite/c-c++-common/tm/pr54893.c > @@ -1,5 +1,6 @@ > /* { dg-do compile } */ > /* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > /* Test that volatiles are allowed inside relaxed transactions. */ > > diff --git gcc/testsuite/g++.dg/cpp0x/pr65327.C gcc/testsuite/g++.dg/cpp0x/pr65327.C > index 5176b3c3204..6e888ebff2c 100644 > --- gcc/testsuite/g++.dg/cpp0x/pr65327.C > +++ gcc/testsuite/g++.dg/cpp0x/pr65327.C > @@ -11,7 +11,7 @@ foo () > static constexpr volatile int k = 5; > } > > -constexpr volatile int > +constexpr volatile int // { dg-warning "deprecated" "" { target c++2a } } > bar () > { > return i; > diff --git gcc/testsuite/g++.dg/cpp0x/rv-conv2.C gcc/testsuite/g++.dg/cpp0x/rv-conv2.C > index 9b9b154995b..2f2a1fa702a 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv-conv2.C > +++ gcc/testsuite/g++.dg/cpp0x/rv-conv2.C > @@ -1,16 +1,16 @@ > // PR c++/89705 > // { dg-do compile { target c++11 } } > > -struct W { operator const volatile int(); }; > +struct W { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } > const int& rci = W(); > > struct X { operator const int(); }; > int&& rri = X(); > > -struct Y { operator volatile int(); }; > +struct Y { operator volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } > int&& rri2 = Y(); > > -struct Z { operator const volatile int(); }; > +struct Z { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } > volatile int&& rri3 = Z(); > > enum E { A }; > diff --git gcc/testsuite/g++.dg/cpp0x/rv1n.C gcc/testsuite/g++.dg/cpp0x/rv1n.C > index f5e75681758..a762fc85862 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv1n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv1n.C > @@ -26,8 +26,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 1 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv1p.C gcc/testsuite/g++.dg/cpp0x/rv1p.C > index a9097276d5a..e2a983a7708 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv1p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv1p.C > @@ -26,8 +26,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 1 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv2n.C gcc/testsuite/g++.dg/cpp0x/rv2n.C > index 65eda80fba0..2871ccf9ab3 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv2n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv2n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 2 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv2p.C gcc/testsuite/g++.dg/cpp0x/rv2p.C > index 25a42ba2af8..bab0dce3d97 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv2p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv2p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 2 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv3n.C gcc/testsuite/g++.dg/cpp0x/rv3n.C > index 4549438f8ef..35cdba95858 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv3n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv3n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 3 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv3p.C gcc/testsuite/g++.dg/cpp0x/rv3p.C > index 2d7d78df6be..b25aa26c9b0 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv3p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv3p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 3 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv4n.C gcc/testsuite/g++.dg/cpp0x/rv4n.C > index 29deb3fc81b..6941a13de6c 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv4n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv4n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 4 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv4p.C gcc/testsuite/g++.dg/cpp0x/rv4p.C > index 0e4903bc291..cd0d631d780 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv4p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv4p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 4 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv5n.C gcc/testsuite/g++.dg/cpp0x/rv5n.C > index f11d07a3921..086aa460c68 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv5n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv5n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 5 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv5p.C gcc/testsuite/g++.dg/cpp0x/rv5p.C > index 63441a3f0da..34c1017f578 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv5p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv5p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 5 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv6n.C gcc/testsuite/g++.dg/cpp0x/rv6n.C > index 0ebbe33e1d1..b21d22a5b87 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv6n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv6n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 6 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv6p.C gcc/testsuite/g++.dg/cpp0x/rv6p.C > index 26714f0c9aa..fee692bb08f 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv6p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv6p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 6 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv7n.C gcc/testsuite/g++.dg/cpp0x/rv7n.C > index d9e371b8adb..5bc313cc07f 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv7n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv7n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 7 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv7p.C gcc/testsuite/g++.dg/cpp0x/rv7p.C > index 60a35835c7d..b0b8f965498 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv7p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv7p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 7 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv8p.C gcc/testsuite/g++.dg/cpp0x/rv8p.C > index e12da4b8d79..287fb93b432 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv8p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv8p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 8 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/trailing14.C gcc/testsuite/g++.dg/cpp0x/trailing14.C > index 2544d0bab5e..4ebb37406ad 100644 > --- gcc/testsuite/g++.dg/cpp0x/trailing14.C > +++ gcc/testsuite/g++.dg/cpp0x/trailing14.C > @@ -1,6 +1,6 @@ > // PR c++/65775 > // { dg-do compile { target c++11 } } > -// { dg-options "-Wignored-qualifiers" } > +// { dg-options "-Wignored-qualifiers -Wno-volatile" } > > using Qi = int const volatile; > Qi q1(); // { dg-warning "1: type qualifiers ignored" } > diff --git gcc/testsuite/g++.dg/cpp1y/new1.C gcc/testsuite/g++.dg/cpp1y/new1.C > index 5e4f1bf6b0b..b9ad64dfcc0 100644 > --- gcc/testsuite/g++.dg/cpp1y/new1.C > +++ gcc/testsuite/g++.dg/cpp1y/new1.C > @@ -65,7 +65,7 @@ void > test_unused() { > volatile double d = 0.0; > double *p = new double (); > - d += 1.0; > + d += 1.0; // { dg-warning "deprecated" "" { target c++2a } } > delete p; > } > > diff --git gcc/testsuite/g++.dg/cpp2a/volatile1.C gcc/testsuite/g++.dg/cpp2a/volatile1.C > new file mode 100644 > index 00000000000..16c3bb417d3 > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile1.C > @@ -0,0 +1,140 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++17 } } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } } > +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" "" { target c++2a } } > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + (vi = 42, 45); > + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + (void)(vi = i); > + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; I guess we should also test that there's no warning for decltype(i = vi = 42) since this is also an unevaluated context. It's a bit odd the proposal uses "unevaluated context" rather than "unevaluated operand". > + > + // Compound assignments. > + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + i *= vi; > + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } > + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/cpp2a/volatile2.C gcc/testsuite/g++.dg/cpp2a/volatile2.C > new file mode 100644 > index 00000000000..31035e22d8f > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile2.C > @@ -0,0 +1,141 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++2a } } > +// { dg-options "-Wno-volatile" } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int > +fn (volatile int i) > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; > + ++v; > + v--; > + --v; > + p++; > + ++p; > + p--; > + --p; > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; > + &(vi = i); > + (vi = 42, 45); > + (i = vi = 42, 10); > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); > + (void)(vi = i); > + (void)(i = vi = 42); > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + > + // Compound assignments. > + vi += i; > + vi -= i; > + vi %= i; > + vi ^= i; > + vi |= i; > + vi /= i; > + vi = vi += 42; > + vi += vi = 42; > + i *= vi; > + decltype(vi -= 42) x2 = vi; > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; > + volatile auto & [vxr, vyr] = a; > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; > + u.c += 42; > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; > + t.a += 3; > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; > + t &= 42; > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/cpp2a/volatile3.C gcc/testsuite/g++.dg/cpp2a/volatile3.C > new file mode 100644 > index 00000000000..731c9aec99f > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile3.C > @@ -0,0 +1,141 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++17 } } > +// { dg-options "-Wvolatile" } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" } > +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" } > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + (vi = 42, 45); > + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + (void)(vi = i); > + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + > + // Compound assignments. > + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + i *= vi; > + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } > + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/cpp2a/volatile4.C gcc/testsuite/g++.dg/cpp2a/volatile4.C > new file mode 100644 > index 00000000000..4d039545ac9 > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile4.C > @@ -0,0 +1,141 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++2a } } > +// { dg-options "-Wno-deprecated" } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int > +fn (volatile int i) > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; > + ++v; > + v--; > + --v; > + p++; > + ++p; > + p--; > + --p; > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; > + &(vi = i); > + (vi = 42, 45); > + (i = vi = 42, 10); > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); > + (void)(vi = i); > + (void)(i = vi = 42); > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + > + // Compound assignments. > + vi += i; > + vi -= i; > + vi %= i; > + vi ^= i; > + vi |= i; > + vi /= i; > + vi = vi += 42; > + vi += vi = 42; > + i *= vi; > + decltype(vi -= 42) x2 = vi; > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; > + volatile auto & [vxr, vyr] = a; > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; > + u.c += 42; > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; > + t.a += 3; > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; > + t &= 42; > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/expr/bool3.C gcc/testsuite/g++.dg/expr/bool3.C > index 373c202b800..f27399cfc8a 100644 > --- gcc/testsuite/g++.dg/expr/bool3.C > +++ gcc/testsuite/g++.dg/expr/bool3.C > @@ -13,8 +13,10 @@ int main() > > b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } > // { dg-error "forbidden" "" { target c++17 } .-1 } > + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } > b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } > // { dg-error "forbidden" "" { target c++17 } .-1 } > + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } > i = b; > if (i != 1) > abort (); > diff --git gcc/testsuite/g++.dg/expr/bool4.C gcc/testsuite/g++.dg/expr/bool4.C > index dce51ec332e..5891bc311bd 100644 > --- gcc/testsuite/g++.dg/expr/bool4.C > +++ gcc/testsuite/g++.dg/expr/bool4.C > @@ -8,6 +8,6 @@ int main() > { > my_bool b = false; > b--; // { dg-error "" } > + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-1 } > return 0; > } > - > diff --git gcc/testsuite/g++.dg/expr/cond9.C gcc/testsuite/g++.dg/expr/cond9.C > index b344c1f683a..f7e092e1445 100644 > --- gcc/testsuite/g++.dg/expr/cond9.C > +++ gcc/testsuite/g++.dg/expr/cond9.C > @@ -4,7 +4,7 @@ struct A { // { dg-message "A" } > A(int); > }; > > -void foo(volatile A a) { > +void foo(volatile A a) { // { dg-warning "deprecated" "" { target c++2a } } > 1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" } > 1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" } > } > diff --git gcc/testsuite/g++.dg/ext/vector25.C gcc/testsuite/g++.dg/ext/vector25.C > index 6c1f5d09878..339865d6942 100644 > --- gcc/testsuite/g++.dg/ext/vector25.C > +++ gcc/testsuite/g++.dg/ext/vector25.C > @@ -2,5 +2,5 @@ volatile int i __attribute__((vector_size(8))); > > void foo() > { > - i += i; > + i += i; // { dg-warning "deprecated" "" { target c++2a } } > } > diff --git gcc/testsuite/g++.dg/gomp/depend-iterator-1.C gcc/testsuite/g++.dg/gomp/depend-iterator-1.C > index 6f4aa97ee44..d12670c5159 100644 > --- gcc/testsuite/g++.dg/gomp/depend-iterator-1.C > +++ gcc/testsuite/g++.dg/gomp/depend-iterator-1.C > @@ -1,3 +1,5 @@ > +// { dg-additional-options "-Wno-volatile" } > + > int arr[64], arr2[64]; > struct S { int a[4]; } k; > short arr4[4]; > diff --git gcc/testsuite/g++.dg/inherit/covariant21.C gcc/testsuite/g++.dg/inherit/covariant21.C > index 42cdf870081..769cb14ecbc 100644 > --- gcc/testsuite/g++.dg/inherit/covariant21.C > +++ gcc/testsuite/g++.dg/inherit/covariant21.C > @@ -6,12 +6,12 @@ struct C : A, B {}; > > struct X > { > - virtual B* foo(volatile int); > + virtual B* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } > }; > > struct Y : X > { > - virtual C* foo(volatile int); > + virtual C* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } > }; > > -C* Y::foo(volatile int) { return 0; } > +C* Y::foo(volatile int) { return 0; } // { dg-warning "deprecated" "" { target c++2a } } > diff --git gcc/testsuite/g++.dg/init/ref18.C gcc/testsuite/g++.dg/init/ref18.C > index e704077c26b..81ac76a40d3 100644 > --- gcc/testsuite/g++.dg/init/ref18.C > +++ gcc/testsuite/g++.dg/init/ref18.C > @@ -1,6 +1,6 @@ > // PR c++/49395 > > -volatile int foo(); > +volatile int foo(); // { dg-warning "deprecated" "" { target c++2a } } > struct A { volatile int i; }; > typedef volatile int vi; > > diff --git gcc/testsuite/g++.dg/ipa/pr63838.C gcc/testsuite/g++.dg/ipa/pr63838.C > index d23b3133748..5b6b11d70e5 100644 > --- gcc/testsuite/g++.dg/ipa/pr63838.C > +++ gcc/testsuite/g++.dg/ipa/pr63838.C > @@ -7,12 +7,12 @@ > __attribute__((noinline, noclone)) static void bar (int); > volatile int v; > void (*fn) (); > -struct S { S () { v++; } ~S () { v++; } }; > +struct S { S () { v++; } ~S () { v++; } }; // { dg-warning "deprecated" "" { target c++2a } } > > __attribute__((noinline, noclone)) static void > foo (int x) > { > - v++; > + v++; // { dg-warning "deprecated" "" { target c++2a } } > if (x == 5) > bar (x); > } > @@ -20,7 +20,7 @@ foo (int x) > __attribute__((noinline, noclone)) static void > bar (int x) > { > - v++; > + v++; // { dg-warning "deprecated" "" { target c++2a } } > if (x == 6) > foo (x); > else if (x == 5) > diff --git gcc/testsuite/g++.dg/overload/rvalue2.C gcc/testsuite/g++.dg/overload/rvalue2.C > index 8a2290dc293..a829fb5e8cc 100644 > --- gcc/testsuite/g++.dg/overload/rvalue2.C > +++ gcc/testsuite/g++.dg/overload/rvalue2.C > @@ -7,5 +7,5 @@ template <class T> void f(const T&); > int main() > { > volatile int i = 0; > - f(i++); > + f(i++); // { dg-warning "deprecated" "" { target c++2a } } > } > diff --git gcc/testsuite/g++.dg/parse/semicolon4.C gcc/testsuite/g++.dg/parse/semicolon4.C > index 5135ec14b1f..bdd1c845187 100644 > --- gcc/testsuite/g++.dg/parse/semicolon4.C > +++ gcc/testsuite/g++.dg/parse/semicolon4.C > @@ -25,7 +25,7 @@ struct E1 > } const; // { dg-error "'const' can only be specified for objects and functions" } > > void foo ( > -struct E2 > +struct E2 // { dg-warning "deprecated" "" { target c++2a } } > { // { dg-error "types may not be defined in parameter types" } > int i; > } volatile); > diff --git gcc/testsuite/g++.dg/warn/Wreturn-type-4.C gcc/testsuite/g++.dg/warn/Wreturn-type-4.C > index 4f02678e7f9..24a6b41cbd8 100644 > --- gcc/testsuite/g++.dg/warn/Wreturn-type-4.C > +++ gcc/testsuite/g++.dg/warn/Wreturn-type-4.C > @@ -3,6 +3,7 @@ > /* { dg-options "-Wignored-qualifiers" } */ > > volatile void bar(); /* { dg-warning "type qualifiers ignored" } */ > +// { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } .-1 } > > struct A > { > diff --git gcc/testsuite/g++.dg/warn/pr36069.C gcc/testsuite/g++.dg/warn/pr36069.C > index efb35c25716..7b166351a4b 100644 > --- gcc/testsuite/g++.dg/warn/pr36069.C > +++ gcc/testsuite/g++.dg/warn/pr36069.C > @@ -6,11 +6,13 @@ struct foo { > bool a; > volatile bool b,c; > foo() { a = b = c = false; } // { dg-bogus "parentheses" } > + // { dg-warning "deprecated" "" { target c++2a } .-1 } > }; > > int main() { > bool a; > volatile bool b,c; > a = b = c = false; // { dg-bogus "parentheses" } > + // { dg-warning "deprecated" "" { target c++2a } .-1 } > foo A; > } > diff --git gcc/testsuite/g++.old-deja/g++.mike/p9506.C gcc/testsuite/g++.old-deja/g++.mike/p9506.C > index db16e3738e2..97594640f96 100644 > --- gcc/testsuite/g++.old-deja/g++.mike/p9506.C > +++ gcc/testsuite/g++.old-deja/g++.mike/p9506.C > @@ -3,5 +3,5 @@ > > char * volatile p; > void foo() { > - --p = 0; > + --p = 0; // { dg-warning "deprecated" "" { target c++2a } } > } > diff --git gcc/testsuite/g++.old-deja/g++.other/volatile1.C gcc/testsuite/g++.old-deja/g++.other/volatile1.C > index 7d818fbe9e1..a93ef58aa9f 100644 > --- gcc/testsuite/g++.old-deja/g++.other/volatile1.C > +++ gcc/testsuite/g++.old-deja/g++.other/volatile1.C > @@ -5,7 +5,7 @@ > class f_class // { dg-message "note" "candidates" } > { }; > > -volatile f_class > +volatile f_class // { dg-warning "deprecated" "" { target c++2a } } > ret_v_f_class() > { > f_class t; >
On Wed, Aug 28, 2019 at 04:08:39PM -0400, Jason Merrill wrote: > On 8/26/19 1:46 PM, Marek Polacek wrote: > > +Wvolatile > > +C++ ObjC++ Var(warn_volatile) Warning > > +Warn about certain uses of volatile qualifier. > > Maybe "deprecated uses"? Ok, changed. > > --- gcc/cp/expr.c > > +++ gcc/cp/expr.c > > @@ -207,6 +207,27 @@ mark_use (tree expr, bool rvalue_p, bool read_p, > > recurse_op[0] = true; > > break; > > + case MODIFY_EXPR: > > + { > > + tree lhs = TREE_OPERAND (expr, 0); > > + /* [expr.ass] "A simple assignment whose left operand is of > > + a volatile-qualified type is deprecated unless the assignment > > + is either a discarded-value expression or appears in an > > + unevaluated context." */ > > + if (read_p > > + && (TREE_THIS_VOLATILE (lhs) > > + || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs))) > > + && !TREE_THIS_VOLATILE (expr)) > > + { > > + warning_at (location_of (expr), OPT_Wvolatile, > > + "assignment with %<volatile%>-qualified left " > > + "operand is deprecated"); > > This should be more specific; the assignment itself isn't deprecated, but > rather using the assignment as an lvalue or rvalue. This now reads "using value of simple assignment with volatile-qualified left operand is deprecated". > > + /* An expression of the form E1 op= E2. [expr.ass] says: > > + "Such expressions are deprecated if E1 has volatile-qualified > > + type." We warn here rather than in cp_genericize_r because > > + for compound assignments we are supposed to warn even if the > > + assignment is a discarded-value expression. */ > > + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) > > + warning_at (loc, OPT_Wvolatile, > > + "assignment with %<volatile%>-qualified left operand " > > + "is deprecated"); > > And this should say "compound assignment ..." Fixed. > > +@item -Wvolatile @r{(C++ and Objective-C++ only)} > > +@opindex Wvolatile > > +@opindex Wno-volatile > > +Warn about certain uses of volatile qualifier. This includes postfix > > +@code{++} and @code{--} expressions, prefix @code{++} and @code{--} > > +expressions, certain assignments where the left operand is a > > +volatile-qualified non-class type > > This should also be more specific. Improved (hopefully). > > + > > + // Unevaluated operand. > > + decltype(vi = 42) x = vi; > > I guess we should also test that there's no warning for > > decltype(i = vi = 42) > > since this is also an unevaluated context. It's a bit odd the proposal uses > "unevaluated context" rather than "unevaluated operand". Yes we should, and *of course* it was a case where my patch emitted a bogus warning. But it was trivial to fix by checking cp_unevaluated_operand. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-08-28 Marek Polacek <polacek@redhat.com> Implement P1152R4: Deprecating some uses of volatile. PR c++/91361 * c-opts.c (c_common_post_options): Enable -Wvolatile by default for C++2a, unless -Wno-deprecated. * c.opt (Wvolatile): New warning. * cp-gimplify.c (cp_fold): Set TREE_THIS_VOLATILE. * decl.c (grokdeclarator): Warn about a volatile-qualified structured binding and return type. (grokparms): Warn about a volatile-qualified function parameter. * expr.c (mark_use) <case MODIFY_EXPR>: Emit a -Wvolatile warning. * typeck.c (cp_build_unary_op): Emit a -Wvolatile warning for pre and post ++/-- on a volatile operand. (genericize_compound_lvalue): Use a better location. Don't lose TREE_THIS_VOLATILE. (cp_build_modify_expr): Emit a -Wvolatile warning for a compound assignment whose LHS is volatile-qualified. Build the assignment with a more precise location. * doc/invoke.texi: Document -Wvolatile. * c-c++-common/Wbool-operation-1.c: Use -Wno-volatile in C++. * c-c++-common/gomp/atomic-1.c: Likewise. * c-c++-common/gomp/atomic-9.c: Likewise. * c-c++-common/gomp/depend-iterator-1.c: Likewise. * c-c++-common/gomp/loop-1.c: Adjust warning location for C++. * c-c++-common/gomp/order-3.c: Likewise. * c-c++-common/pr69733.c: Use -Wno-volatile in C++. * c-c++-common/spec-barrier-2.c: Likewise. * c-c++-common/tm/pr54893.c: Likewise. * g++.dg/cpp0x/pr65327.C: Add dg-warning. * g++.dg/cpp0x/rv-conv2.C: Likewise. * g++.dg/cpp0x/rv1n.C: Likewise. * g++.dg/cpp0x/rv1p.C: Likewise. * g++.dg/cpp0x/rv2n.C: Likewise. * g++.dg/cpp0x/rv2p.C: Likewise. * g++.dg/cpp0x/rv3n.C: Likewise. * g++.dg/cpp0x/rv3p.C: Likewise. * g++.dg/cpp0x/rv4n.C: Likewise. * g++.dg/cpp0x/rv4p.C: Likewise. * g++.dg/cpp0x/rv5n.C: Likewise. * g++.dg/cpp0x/rv5p.C: Likewise. * g++.dg/cpp0x/rv6n.C: Likewise. * g++.dg/cpp0x/rv6p.C: Likewise. * g++.dg/cpp0x/rv7n.C: Likewise. * g++.dg/cpp0x/rv7p.C: Likewise. * g++.dg/cpp0x/rv8p.C: Likewise. * g++.dg/cpp0x/trailing14.C: Use -Wno-volatile. * g++.dg/cpp1y/new1.C: Add dg-warning. * g++.dg/cpp2a/volatile1.C: New test. * g++.dg/cpp2a/volatile2.C: New test. * g++.dg/cpp2a/volatile3.C: New test. * g++.dg/cpp2a/volatile4.C: New test. * g++.dg/expr/bool3.C: Add dg-warning. * g++.dg/expr/bool4.C: Likewise. * g++.dg/expr/cond9.C: Likewise. * g++.dg/ext/vector25.C: Likewise. * g++.dg/gomp/depend-iterator-1.C: Use -Wno-volatile. * g++.dg/inherit/covariant21.C: Add dg-warning. * g++.dg/init/ref18.C: Likewise. * g++.dg/ipa/pr63838.C: Likewise. * g++.dg/overload/rvalue2.C: Likewise. * g++.dg/parse/semicolon4.C: Likewise. * g++.dg/warn/Wreturn-type-4.C: Likewise. * g++.dg/warn/pr36069.C: Likewise. * g++.old-deja/g++.mike/p9506.C: Likewise. * g++.old-deja/g++.other/volatile1.C: Likewise. diff --git gcc/c-family/c-opts.c gcc/c-family/c-opts.c index da783e4990c..fa8cd0ccb09 100644 --- gcc/c-family/c-opts.c +++ gcc/c-family/c-opts.c @@ -919,6 +919,10 @@ c_common_post_options (const char **pfilename) if (!global_options_set.x_warn_comma_subscript) warn_comma_subscript = (cxx_dialect >= cxx2a && warn_deprecated); + /* -Wvolatile is enabled by default in C++20. */ + if (!global_options_set.x_warn_volatile) + warn_volatile = (cxx_dialect >= cxx2a && warn_deprecated); + /* Declone C++ 'structors if -Os. */ if (flag_declone_ctor_dtor == -1) flag_declone_ctor_dtor = optimize_size; diff --git gcc/c-family/c.opt gcc/c-family/c.opt index 4c468d0f6c2..f8a1a1dbdad 100644 --- gcc/c-family/c.opt +++ gcc/c-family/c.opt @@ -1228,6 +1228,10 @@ Wno-vla-larger-than C ObjC C++ LTO ObjC++ Alias(Wvla-larger-than=,18446744073709551615EiB,none) Warning -Wno-vla-larger-than Disable Wvla-larger-than= warning. Equivalent to Wvla-larger-than=<SIZE_MAX> or larger. +Wvolatile +C++ ObjC++ Var(warn_volatile) Warning +Warn about deprecated uses of volatile qualifier. + Wvolatile-register-var C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn when a register variable is declared volatile. diff --git gcc/cp/cp-gimplify.c gcc/cp/cp-gimplify.c index 065dcb7ba06..49fa47ac3af 100644 --- gcc/cp/cp-gimplify.c +++ gcc/cp/cp-gimplify.c @@ -2507,6 +2507,9 @@ cp_fold (tree x) else x = org_x; } + if (code == MODIFY_EXPR && TREE_CODE (x) == MODIFY_EXPR) + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); + break; case VEC_COND_EXPR: diff --git gcc/cp/decl.c gcc/cp/decl.c index c5cc22a8d6d..2aef330455f 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -11233,6 +11233,10 @@ grokdeclarator (const cp_declarator *declarator, if (concept_p) error_at (declspecs->locations[ds_concept], "structured binding declaration cannot be %qs", "concept"); + /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ + if (type_quals & TYPE_QUAL_VOLATILE) + warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, + "%<volatile%>-qualified structured binding is deprecated"); switch (storage_class) { case sc_none: @@ -11623,6 +11627,13 @@ grokdeclarator (const cp_declarator *declarator, if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " "qualifiers ignored on function return type"); + /* [dcl.fct] "A volatile-qualified return type is + deprecated." */ + if (type_quals & TYPE_QUAL_VOLATILE) + warning_at (typespec_loc, OPT_Wvolatile, + "%<volatile%>-qualified return type is " + "deprecated"); + /* We now know that the TYPE_QUALS don't apply to the decl, but to its return type. */ type_quals = TYPE_UNQUALIFIED; @@ -13378,6 +13389,13 @@ grokparms (tree parmlist, tree *parms) cp_warn_deprecated_use (deptype); } + /* [dcl.fct] "A parameter with volatile-qualified type is + deprecated." */ + if (CP_TYPE_VOLATILE_P (type)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wvolatile, + "%<volatile%>-qualified parameter is " + "deprecated"); + /* Top-level qualifiers on the parameters are ignored for function types. */ type = cp_build_qualified_type (type, 0); diff --git gcc/cp/expr.c gcc/cp/expr.c index 9160043ed11..212a7f93c5a 100644 --- gcc/cp/expr.c +++ gcc/cp/expr.c @@ -207,6 +207,28 @@ mark_use (tree expr, bool rvalue_p, bool read_p, recurse_op[0] = true; break; + case MODIFY_EXPR: + { + tree lhs = TREE_OPERAND (expr, 0); + /* [expr.ass] "A simple assignment whose left operand is of + a volatile-qualified type is deprecated unless the assignment + is either a discarded-value expression or appears in an + unevaluated context." */ + if (read_p + && !cp_unevaluated_operand + && (TREE_THIS_VOLATILE (lhs) + || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs))) + && !TREE_THIS_VOLATILE (expr)) + { + warning_at (location_of (expr), OPT_Wvolatile, + "using value of simple assignment with %<volatile%>-" + "qualified left operand is deprecated"); + /* Make sure not to warn about this assignment again. */ + TREE_THIS_VOLATILE (expr) = true; + } + break; + } + default: break; } diff --git gcc/cp/typeck.c gcc/cp/typeck.c index c09bb309142..d4f2d98143b 100644 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -6459,6 +6459,17 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, complain)) return error_mark_node; + /* [depr.volatile.type] "Postfix ++ and -- expressions and + prefix ++ and -- expressions of volatile-qualified arithmetic + and pointer types are deprecated." */ + if (TREE_THIS_VOLATILE (arg) || CP_TYPE_VOLATILE_P (TREE_TYPE (arg))) + warning_at (location, OPT_Wvolatile, + "%qs expression of %<volatile%>-qualified type is " + "deprecated", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "++" : "--")); + /* Forbid using -- or ++ in C++17 on `bool'. */ if (TREE_CODE (declared_type) == BOOLEAN_TYPE) { @@ -8278,6 +8289,15 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype))) || MAYBE_CLASS_TYPE_P (lhstype))); + /* An expression of the form E1 op= E2. [expr.ass] says: + "Such expressions are deprecated if E1 has volatile-qualified + type." We warn here rather than in cp_genericize_r because + for compound assignments we are supposed to warn even if the + assignment is a discarded-value expression. */ + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) + warning_at (loc, OPT_Wvolatile, + "compound assignment with %<volatile%>-qualified left " + "operand is deprecated"); /* Preevaluate the RHS to make sure its evaluation is complete before the lvalue-to-rvalue conversion of the LHS: @@ -8450,8 +8470,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, goto ret; } - result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, - lhstype, lhs, newrhs); + result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, + lhstype, lhs, newrhs); TREE_SIDE_EFFECTS (result) = 1; if (!plain_assign) diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi index 1391a562c35..aa9886ee09f 100644 --- gcc/doc/invoke.texi +++ gcc/doc/invoke.texi @@ -243,7 +243,7 @@ in the following sections. -Wno-non-template-friend -Wold-style-cast @gol -Woverloaded-virtual -Wno-pmf-conversions @gol -Wno-class-conversion -Wno-terminate @gol --Wsign-promo -Wvirtual-inheritance} +-Wsign-promo -Wvirtual-inheritance -Wvolatile} @item Objective-C and Objective-C++ Language Options @xref{Objective-C and Objective-C++ Dialect Options,,Options Controlling @@ -3516,6 +3516,19 @@ result in a call to @code{terminate}. Disable the warning about the case when a conversion function converts an object to the same type, to a base class of that type, or to void; such a conversion function will never be called. + +@item -Wvolatile @r{(C++ and Objective-C++ only)} +@opindex Wvolatile +@opindex Wno-volatile +Warn about deprecated uses of the volatile qualifier. This includes postfix +and prefix @code{++} and @code{--} expressions of volatile-qualified types, +using simple assignments where the left operand is a volatile-qualified +non-class type for their value, compound assignments where the left operand +is a volatile-qualified non-class type, volatile-qualified function return +type, volatile-qualified parameter type, and structured bindings of a +volatile-qualified type. This usage was deprecated in C++20. + +Enabled by default with @option{-std=c++2a}. @end table @node Objective-C and Objective-C++ Dialect Options diff --git gcc/testsuite/c-c++-common/Wbool-operation-1.c gcc/testsuite/c-c++-common/Wbool-operation-1.c index 04891878155..ce87705692a 100644 --- gcc/testsuite/c-c++-common/Wbool-operation-1.c +++ gcc/testsuite/c-c++-common/Wbool-operation-1.c @@ -1,6 +1,7 @@ /* PR c/77490 */ /* { dg-do compile } */ /* { dg-options "-Wall -Wno-psabi" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ #ifndef __cplusplus # define bool _Bool diff --git gcc/testsuite/c-c++-common/gomp/atomic-1.c gcc/testsuite/c-c++-common/gomp/atomic-1.c index 3e4bc569ba7..1facf4586f5 100644 --- gcc/testsuite/c-c++-common/gomp/atomic-1.c +++ gcc/testsuite/c-c++-common/gomp/atomic-1.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ int x; volatile int y; diff --git gcc/testsuite/c-c++-common/gomp/atomic-9.c gcc/testsuite/c-c++-common/gomp/atomic-9.c index c07da8fc712..35548395f36 100644 --- gcc/testsuite/c-c++-common/gomp/atomic-9.c +++ gcc/testsuite/c-c++-common/gomp/atomic-9.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-fopenmp -fdump-tree-ompexp" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* { dg-require-effective-target cas_int } */ volatile int *bar(void); diff --git gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c index 4fb01c174ec..6fa60215f43 100644 --- gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ + int arr[64], arr2[64]; struct S { int a[4]; } k; short arr4[4]; diff --git gcc/testsuite/c-c++-common/gomp/loop-1.c gcc/testsuite/c-c++-common/gomp/loop-1.c index d2f943aea54..4fb995c02a7 100644 --- gcc/testsuite/c-c++-common/gomp/loop-1.c +++ gcc/testsuite/c-c++-common/gomp/loop-1.c @@ -100,8 +100,8 @@ f4 (int *a) #pragma omp loop order(concurrent) bind(parallel) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop order(concurrent) bind(parallel) for (i = 0; i < 64; i++) @@ -172,8 +172,8 @@ f5 (int *a) #pragma omp loop for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop for (i = 0; i < 64; i++) @@ -245,8 +245,8 @@ f6 (int *a) #pragma omp loop for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop for (i = 0; i < 64; i++) diff --git gcc/testsuite/c-c++-common/gomp/order-3.c gcc/testsuite/c-c++-common/gomp/order-3.c index 2d51bf37749..e33386dd5cc 100644 --- gcc/testsuite/c-c++-common/gomp/order-3.c +++ gcc/testsuite/c-c++-common/gomp/order-3.c @@ -50,8 +50,8 @@ f1 (int *a) #pragma omp simd order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp simd order(concurrent) for (i = 0; i < 64; i++) @@ -112,8 +112,8 @@ f2 (int *a) #pragma omp for simd order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp for simd order(concurrent) for (i = 0; i < 64; i++) @@ -174,8 +174,8 @@ f3 (int *a) #pragma omp for order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp for order(concurrent) for (i = 0; i < 64; i++) diff --git gcc/testsuite/c-c++-common/pr69733.c gcc/testsuite/c-c++-common/pr69733.c index 57ec1eccb9f..ab70f49009c 100644 --- gcc/testsuite/c-c++-common/pr69733.c +++ gcc/testsuite/c-c++-common/pr69733.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-W -fdiagnostics-show-caret" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ typedef const double cd; double val; @@ -21,4 +22,3 @@ cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ cd val2() {return val;} ^~ { dg-end-multiline-output "" } */ - diff --git gcc/testsuite/c-c++-common/spec-barrier-2.c gcc/testsuite/c-c++-common/spec-barrier-2.c index b09567e62a9..a27ec54f0d3 100644 --- gcc/testsuite/c-c++-common/spec-barrier-2.c +++ gcc/testsuite/c-c++-common/spec-barrier-2.c @@ -1,4 +1,5 @@ /* { dg-do run } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* Even on targets that don't need the optional failval parameter, side-effects on the operand should still be calculated. */ diff --git gcc/testsuite/c-c++-common/tm/pr54893.c gcc/testsuite/c-c++-common/tm/pr54893.c index 3766078d31e..266cbe9c652 100644 --- gcc/testsuite/c-c++-common/tm/pr54893.c +++ gcc/testsuite/c-c++-common/tm/pr54893.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* Test that volatiles are allowed inside relaxed transactions. */ diff --git gcc/testsuite/g++.dg/cpp0x/pr65327.C gcc/testsuite/g++.dg/cpp0x/pr65327.C index 5176b3c3204..6e888ebff2c 100644 --- gcc/testsuite/g++.dg/cpp0x/pr65327.C +++ gcc/testsuite/g++.dg/cpp0x/pr65327.C @@ -11,7 +11,7 @@ foo () static constexpr volatile int k = 5; } -constexpr volatile int +constexpr volatile int // { dg-warning "deprecated" "" { target c++2a } } bar () { return i; diff --git gcc/testsuite/g++.dg/cpp0x/rv-conv2.C gcc/testsuite/g++.dg/cpp0x/rv-conv2.C index 9b9b154995b..2f2a1fa702a 100644 --- gcc/testsuite/g++.dg/cpp0x/rv-conv2.C +++ gcc/testsuite/g++.dg/cpp0x/rv-conv2.C @@ -1,16 +1,16 @@ // PR c++/89705 // { dg-do compile { target c++11 } } -struct W { operator const volatile int(); }; +struct W { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } const int& rci = W(); struct X { operator const int(); }; int&& rri = X(); -struct Y { operator volatile int(); }; +struct Y { operator volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } int&& rri2 = Y(); -struct Z { operator const volatile int(); }; +struct Z { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } volatile int&& rri3 = Z(); enum E { A }; diff --git gcc/testsuite/g++.dg/cpp0x/rv1n.C gcc/testsuite/g++.dg/cpp0x/rv1n.C index f5e75681758..a762fc85862 100644 --- gcc/testsuite/g++.dg/cpp0x/rv1n.C +++ gcc/testsuite/g++.dg/cpp0x/rv1n.C @@ -26,8 +26,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 1 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv1p.C gcc/testsuite/g++.dg/cpp0x/rv1p.C index a9097276d5a..e2a983a7708 100644 --- gcc/testsuite/g++.dg/cpp0x/rv1p.C +++ gcc/testsuite/g++.dg/cpp0x/rv1p.C @@ -26,8 +26,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 1 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv2n.C gcc/testsuite/g++.dg/cpp0x/rv2n.C index 65eda80fba0..2871ccf9ab3 100644 --- gcc/testsuite/g++.dg/cpp0x/rv2n.C +++ gcc/testsuite/g++.dg/cpp0x/rv2n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 2 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv2p.C gcc/testsuite/g++.dg/cpp0x/rv2p.C index 25a42ba2af8..bab0dce3d97 100644 --- gcc/testsuite/g++.dg/cpp0x/rv2p.C +++ gcc/testsuite/g++.dg/cpp0x/rv2p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 2 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv3n.C gcc/testsuite/g++.dg/cpp0x/rv3n.C index 4549438f8ef..35cdba95858 100644 --- gcc/testsuite/g++.dg/cpp0x/rv3n.C +++ gcc/testsuite/g++.dg/cpp0x/rv3n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 3 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv3p.C gcc/testsuite/g++.dg/cpp0x/rv3p.C index 2d7d78df6be..b25aa26c9b0 100644 --- gcc/testsuite/g++.dg/cpp0x/rv3p.C +++ gcc/testsuite/g++.dg/cpp0x/rv3p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 3 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv4n.C gcc/testsuite/g++.dg/cpp0x/rv4n.C index 29deb3fc81b..6941a13de6c 100644 --- gcc/testsuite/g++.dg/cpp0x/rv4n.C +++ gcc/testsuite/g++.dg/cpp0x/rv4n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 4 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv4p.C gcc/testsuite/g++.dg/cpp0x/rv4p.C index 0e4903bc291..cd0d631d780 100644 --- gcc/testsuite/g++.dg/cpp0x/rv4p.C +++ gcc/testsuite/g++.dg/cpp0x/rv4p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 4 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv5n.C gcc/testsuite/g++.dg/cpp0x/rv5n.C index f11d07a3921..086aa460c68 100644 --- gcc/testsuite/g++.dg/cpp0x/rv5n.C +++ gcc/testsuite/g++.dg/cpp0x/rv5n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 5 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv5p.C gcc/testsuite/g++.dg/cpp0x/rv5p.C index 63441a3f0da..34c1017f578 100644 --- gcc/testsuite/g++.dg/cpp0x/rv5p.C +++ gcc/testsuite/g++.dg/cpp0x/rv5p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 5 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv6n.C gcc/testsuite/g++.dg/cpp0x/rv6n.C index 0ebbe33e1d1..b21d22a5b87 100644 --- gcc/testsuite/g++.dg/cpp0x/rv6n.C +++ gcc/testsuite/g++.dg/cpp0x/rv6n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 6 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv6p.C gcc/testsuite/g++.dg/cpp0x/rv6p.C index 26714f0c9aa..fee692bb08f 100644 --- gcc/testsuite/g++.dg/cpp0x/rv6p.C +++ gcc/testsuite/g++.dg/cpp0x/rv6p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 6 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv7n.C gcc/testsuite/g++.dg/cpp0x/rv7n.C index d9e371b8adb..5bc313cc07f 100644 --- gcc/testsuite/g++.dg/cpp0x/rv7n.C +++ gcc/testsuite/g++.dg/cpp0x/rv7n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 7 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv7p.C gcc/testsuite/g++.dg/cpp0x/rv7p.C index 60a35835c7d..b0b8f965498 100644 --- gcc/testsuite/g++.dg/cpp0x/rv7p.C +++ gcc/testsuite/g++.dg/cpp0x/rv7p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 7 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv8p.C gcc/testsuite/g++.dg/cpp0x/rv8p.C index e12da4b8d79..287fb93b432 100644 --- gcc/testsuite/g++.dg/cpp0x/rv8p.C +++ gcc/testsuite/g++.dg/cpp0x/rv8p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 8 at a time diff --git gcc/testsuite/g++.dg/cpp0x/trailing14.C gcc/testsuite/g++.dg/cpp0x/trailing14.C index 2544d0bab5e..4ebb37406ad 100644 --- gcc/testsuite/g++.dg/cpp0x/trailing14.C +++ gcc/testsuite/g++.dg/cpp0x/trailing14.C @@ -1,6 +1,6 @@ // PR c++/65775 // { dg-do compile { target c++11 } } -// { dg-options "-Wignored-qualifiers" } +// { dg-options "-Wignored-qualifiers -Wno-volatile" } using Qi = int const volatile; Qi q1(); // { dg-warning "1: type qualifiers ignored" } diff --git gcc/testsuite/g++.dg/cpp1y/new1.C gcc/testsuite/g++.dg/cpp1y/new1.C index 5e4f1bf6b0b..b9ad64dfcc0 100644 --- gcc/testsuite/g++.dg/cpp1y/new1.C +++ gcc/testsuite/g++.dg/cpp1y/new1.C @@ -65,7 +65,7 @@ void test_unused() { volatile double d = 0.0; double *p = new double (); - d += 1.0; + d += 1.0; // { dg-warning "deprecated" "" { target c++2a } } delete p; } diff --git gcc/testsuite/g++.dg/cpp2a/volatile1.C gcc/testsuite/g++.dg/cpp2a/volatile1.C new file mode 100644 index 00000000000..e47591b13bc --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile1.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++17 } } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } } +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" "" { target c++2a } } +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + (vi = 42, 45); + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + (void)(vi = i); + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + // Unevaluated operand. + decltype(vi = 42) x = vi; + decltype(i = vi = 42) x3 = i; + + // Compound assignments. + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + i *= vi; + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + volatile T t; + t.a = 3; + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile2.C gcc/testsuite/g++.dg/cpp2a/volatile2.C new file mode 100644 index 00000000000..1a7889a6a8c --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile2.C @@ -0,0 +1,142 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++2a } } +// { dg-options "-Wno-volatile" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int +fn (volatile int i) +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; + ++v; + v--; + --v; + p++; + ++p; + p--; + --p; + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; + &(vi = i); + (vi = 42, 45); + (i = vi = 42, 10); + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); + (void)(vi = i); + (void)(i = vi = 42); + + // Unevaluated operand. + decltype(vi = 42) x = vi; + decltype(i = vi = 42) x3 = i; + + // Compound assignments. + vi += i; + vi -= i; + vi %= i; + vi ^= i; + vi |= i; + vi /= i; + vi = vi += 42; + vi += vi = 42; + i *= vi; + decltype(vi -= 42) x2 = vi; + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; + volatile auto & [vxr, vyr] = a; +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; + u.c += 42; + + volatile T t; + t.a = 3; + j = t.a = 3; + t.a += 3; + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; + t &= 42; +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile3.C gcc/testsuite/g++.dg/cpp2a/volatile3.C new file mode 100644 index 00000000000..f10a29756a9 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile3.C @@ -0,0 +1,142 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++17 } } +// { dg-options "-Wvolatile" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" } +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" } +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + (vi = 42, 45); + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + (void)(vi = i); + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + // Unevaluated operand. + decltype(vi = 42) x = vi; + decltype(i = vi = 42) x3 = i; + + // Compound assignments. + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + i *= vi; + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + volatile T t; + t.a = 3; + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile4.C gcc/testsuite/g++.dg/cpp2a/volatile4.C new file mode 100644 index 00000000000..2148cdeb3d1 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile4.C @@ -0,0 +1,142 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++2a } } +// { dg-options "-Wno-deprecated" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int +fn (volatile int i) +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; + ++v; + v--; + --v; + p++; + ++p; + p--; + --p; + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; + &(vi = i); + (vi = 42, 45); + (i = vi = 42, 10); + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); + (void)(vi = i); + (void)(i = vi = 42); + + // Unevaluated operand. + decltype(vi = 42) x = vi; + decltype(i = vi = 42) x3 = i; + + // Compound assignments. + vi += i; + vi -= i; + vi %= i; + vi ^= i; + vi |= i; + vi /= i; + vi = vi += 42; + vi += vi = 42; + i *= vi; + decltype(vi -= 42) x2 = vi; + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; + volatile auto & [vxr, vyr] = a; +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; + u.c += 42; + + volatile T t; + t.a = 3; + j = t.a = 3; + t.a += 3; + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; + t &= 42; +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/expr/bool3.C gcc/testsuite/g++.dg/expr/bool3.C index 373c202b800..f27399cfc8a 100644 --- gcc/testsuite/g++.dg/expr/bool3.C +++ gcc/testsuite/g++.dg/expr/bool3.C @@ -13,8 +13,10 @@ int main() b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } // { dg-error "forbidden" "" { target c++17 } .-1 } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } // { dg-error "forbidden" "" { target c++17 } .-1 } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } i = b; if (i != 1) abort (); diff --git gcc/testsuite/g++.dg/expr/bool4.C gcc/testsuite/g++.dg/expr/bool4.C index dce51ec332e..5891bc311bd 100644 --- gcc/testsuite/g++.dg/expr/bool4.C +++ gcc/testsuite/g++.dg/expr/bool4.C @@ -8,6 +8,6 @@ int main() { my_bool b = false; b--; // { dg-error "" } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-1 } return 0; } - diff --git gcc/testsuite/g++.dg/expr/cond9.C gcc/testsuite/g++.dg/expr/cond9.C index b344c1f683a..f7e092e1445 100644 --- gcc/testsuite/g++.dg/expr/cond9.C +++ gcc/testsuite/g++.dg/expr/cond9.C @@ -4,7 +4,7 @@ struct A { // { dg-message "A" } A(int); }; -void foo(volatile A a) { +void foo(volatile A a) { // { dg-warning "deprecated" "" { target c++2a } } 1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" } 1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" } } diff --git gcc/testsuite/g++.dg/ext/vector25.C gcc/testsuite/g++.dg/ext/vector25.C index 6c1f5d09878..339865d6942 100644 --- gcc/testsuite/g++.dg/ext/vector25.C +++ gcc/testsuite/g++.dg/ext/vector25.C @@ -2,5 +2,5 @@ volatile int i __attribute__((vector_size(8))); void foo() { - i += i; + i += i; // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.dg/gomp/depend-iterator-1.C gcc/testsuite/g++.dg/gomp/depend-iterator-1.C index 6f4aa97ee44..d12670c5159 100644 --- gcc/testsuite/g++.dg/gomp/depend-iterator-1.C +++ gcc/testsuite/g++.dg/gomp/depend-iterator-1.C @@ -1,3 +1,5 @@ +// { dg-additional-options "-Wno-volatile" } + int arr[64], arr2[64]; struct S { int a[4]; } k; short arr4[4]; diff --git gcc/testsuite/g++.dg/inherit/covariant21.C gcc/testsuite/g++.dg/inherit/covariant21.C index 42cdf870081..769cb14ecbc 100644 --- gcc/testsuite/g++.dg/inherit/covariant21.C +++ gcc/testsuite/g++.dg/inherit/covariant21.C @@ -6,12 +6,12 @@ struct C : A, B {}; struct X { - virtual B* foo(volatile int); + virtual B* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } }; struct Y : X { - virtual C* foo(volatile int); + virtual C* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } }; -C* Y::foo(volatile int) { return 0; } +C* Y::foo(volatile int) { return 0; } // { dg-warning "deprecated" "" { target c++2a } } diff --git gcc/testsuite/g++.dg/init/ref18.C gcc/testsuite/g++.dg/init/ref18.C index e704077c26b..81ac76a40d3 100644 --- gcc/testsuite/g++.dg/init/ref18.C +++ gcc/testsuite/g++.dg/init/ref18.C @@ -1,6 +1,6 @@ // PR c++/49395 -volatile int foo(); +volatile int foo(); // { dg-warning "deprecated" "" { target c++2a } } struct A { volatile int i; }; typedef volatile int vi; diff --git gcc/testsuite/g++.dg/ipa/pr63838.C gcc/testsuite/g++.dg/ipa/pr63838.C index d23b3133748..5b6b11d70e5 100644 --- gcc/testsuite/g++.dg/ipa/pr63838.C +++ gcc/testsuite/g++.dg/ipa/pr63838.C @@ -7,12 +7,12 @@ __attribute__((noinline, noclone)) static void bar (int); volatile int v; void (*fn) (); -struct S { S () { v++; } ~S () { v++; } }; +struct S { S () { v++; } ~S () { v++; } }; // { dg-warning "deprecated" "" { target c++2a } } __attribute__((noinline, noclone)) static void foo (int x) { - v++; + v++; // { dg-warning "deprecated" "" { target c++2a } } if (x == 5) bar (x); } @@ -20,7 +20,7 @@ foo (int x) __attribute__((noinline, noclone)) static void bar (int x) { - v++; + v++; // { dg-warning "deprecated" "" { target c++2a } } if (x == 6) foo (x); else if (x == 5) diff --git gcc/testsuite/g++.dg/overload/rvalue2.C gcc/testsuite/g++.dg/overload/rvalue2.C index 8a2290dc293..a829fb5e8cc 100644 --- gcc/testsuite/g++.dg/overload/rvalue2.C +++ gcc/testsuite/g++.dg/overload/rvalue2.C @@ -7,5 +7,5 @@ template <class T> void f(const T&); int main() { volatile int i = 0; - f(i++); + f(i++); // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.dg/parse/semicolon4.C gcc/testsuite/g++.dg/parse/semicolon4.C index 5135ec14b1f..bdd1c845187 100644 --- gcc/testsuite/g++.dg/parse/semicolon4.C +++ gcc/testsuite/g++.dg/parse/semicolon4.C @@ -25,7 +25,7 @@ struct E1 } const; // { dg-error "'const' can only be specified for objects and functions" } void foo ( -struct E2 +struct E2 // { dg-warning "deprecated" "" { target c++2a } } { // { dg-error "types may not be defined in parameter types" } int i; } volatile); diff --git gcc/testsuite/g++.dg/warn/Wreturn-type-4.C gcc/testsuite/g++.dg/warn/Wreturn-type-4.C index 4f02678e7f9..24a6b41cbd8 100644 --- gcc/testsuite/g++.dg/warn/Wreturn-type-4.C +++ gcc/testsuite/g++.dg/warn/Wreturn-type-4.C @@ -3,6 +3,7 @@ /* { dg-options "-Wignored-qualifiers" } */ volatile void bar(); /* { dg-warning "type qualifiers ignored" } */ +// { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } .-1 } struct A { diff --git gcc/testsuite/g++.dg/warn/pr36069.C gcc/testsuite/g++.dg/warn/pr36069.C index efb35c25716..7b166351a4b 100644 --- gcc/testsuite/g++.dg/warn/pr36069.C +++ gcc/testsuite/g++.dg/warn/pr36069.C @@ -6,11 +6,13 @@ struct foo { bool a; volatile bool b,c; foo() { a = b = c = false; } // { dg-bogus "parentheses" } + // { dg-warning "deprecated" "" { target c++2a } .-1 } }; int main() { bool a; volatile bool b,c; a = b = c = false; // { dg-bogus "parentheses" } + // { dg-warning "deprecated" "" { target c++2a } .-1 } foo A; } diff --git gcc/testsuite/g++.old-deja/g++.mike/p9506.C gcc/testsuite/g++.old-deja/g++.mike/p9506.C index db16e3738e2..97594640f96 100644 --- gcc/testsuite/g++.old-deja/g++.mike/p9506.C +++ gcc/testsuite/g++.old-deja/g++.mike/p9506.C @@ -3,5 +3,5 @@ char * volatile p; void foo() { - --p = 0; + --p = 0; // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.old-deja/g++.other/volatile1.C gcc/testsuite/g++.old-deja/g++.other/volatile1.C index 7d818fbe9e1..a93ef58aa9f 100644 --- gcc/testsuite/g++.old-deja/g++.other/volatile1.C +++ gcc/testsuite/g++.old-deja/g++.other/volatile1.C @@ -5,7 +5,7 @@ class f_class // { dg-message "note" "candidates" } { }; -volatile f_class +volatile f_class // { dg-warning "deprecated" "" { target c++2a } } ret_v_f_class() { f_class t;
OK. On Wed, Aug 28, 2019 at 7:56 PM Marek Polacek <polacek@redhat.com> wrote: > > On Wed, Aug 28, 2019 at 04:08:39PM -0400, Jason Merrill wrote: > > On 8/26/19 1:46 PM, Marek Polacek wrote: > > > +Wvolatile > > > +C++ ObjC++ Var(warn_volatile) Warning > > > +Warn about certain uses of volatile qualifier. > > > > Maybe "deprecated uses"? > > Ok, changed. > > > > --- gcc/cp/expr.c > > > +++ gcc/cp/expr.c > > > @@ -207,6 +207,27 @@ mark_use (tree expr, bool rvalue_p, bool read_p, > > > recurse_op[0] = true; > > > break; > > > + case MODIFY_EXPR: > > > + { > > > + tree lhs = TREE_OPERAND (expr, 0); > > > + /* [expr.ass] "A simple assignment whose left operand is of > > > + a volatile-qualified type is deprecated unless the assignment > > > + is either a discarded-value expression or appears in an > > > + unevaluated context." */ > > > + if (read_p > > > + && (TREE_THIS_VOLATILE (lhs) > > > + || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs))) > > > + && !TREE_THIS_VOLATILE (expr)) > > > + { > > > + warning_at (location_of (expr), OPT_Wvolatile, > > > + "assignment with %<volatile%>-qualified left " > > > + "operand is deprecated"); > > > > This should be more specific; the assignment itself isn't deprecated, but > > rather using the assignment as an lvalue or rvalue. > > This now reads "using value of simple assignment with volatile-qualified left > operand is deprecated". > > > > + /* An expression of the form E1 op= E2. [expr.ass] says: > > > + "Such expressions are deprecated if E1 has volatile-qualified > > > + type." We warn here rather than in cp_genericize_r because > > > + for compound assignments we are supposed to warn even if the > > > + assignment is a discarded-value expression. */ > > > + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) > > > + warning_at (loc, OPT_Wvolatile, > > > + "assignment with %<volatile%>-qualified left operand " > > > + "is deprecated"); > > > > And this should say "compound assignment ..." > > Fixed. > > > > +@item -Wvolatile @r{(C++ and Objective-C++ only)} > > > +@opindex Wvolatile > > > +@opindex Wno-volatile > > > +Warn about certain uses of volatile qualifier. This includes postfix > > > +@code{++} and @code{--} expressions, prefix @code{++} and @code{--} > > > +expressions, certain assignments where the left operand is a > > > +volatile-qualified non-class type > > > > This should also be more specific. > > Improved (hopefully). > > > > + > > > + // Unevaluated operand. > > > + decltype(vi = 42) x = vi; > > > > I guess we should also test that there's no warning for > > > > decltype(i = vi = 42) > > > > since this is also an unevaluated context. It's a bit odd the proposal uses > > "unevaluated context" rather than "unevaluated operand". > > Yes we should, and *of course* it was a case where my patch emitted a bogus > warning. But it was trivial to fix by checking cp_unevaluated_operand. > > Bootstrapped/regtested on x86_64-linux, ok for trunk? > > 2019-08-28 Marek Polacek <polacek@redhat.com> > > Implement P1152R4: Deprecating some uses of volatile. > PR c++/91361 > * c-opts.c (c_common_post_options): Enable -Wvolatile by > default for C++2a, unless -Wno-deprecated. > * c.opt (Wvolatile): New warning. > > * cp-gimplify.c (cp_fold): Set TREE_THIS_VOLATILE. > * decl.c (grokdeclarator): Warn about a volatile-qualified structured > binding and return type. > (grokparms): Warn about a volatile-qualified function parameter. > * expr.c (mark_use) <case MODIFY_EXPR>: Emit a -Wvolatile warning. > * typeck.c (cp_build_unary_op): Emit a -Wvolatile warning for pre and > post ++/-- on a volatile operand. > (genericize_compound_lvalue): Use a better location. Don't lose > TREE_THIS_VOLATILE. > (cp_build_modify_expr): Emit a -Wvolatile warning for a compound > assignment whose LHS is volatile-qualified. Build the assignment with > a more precise location. > > * doc/invoke.texi: Document -Wvolatile. > > * c-c++-common/Wbool-operation-1.c: Use -Wno-volatile in C++. > * c-c++-common/gomp/atomic-1.c: Likewise. > * c-c++-common/gomp/atomic-9.c: Likewise. > * c-c++-common/gomp/depend-iterator-1.c: Likewise. > * c-c++-common/gomp/loop-1.c: Adjust warning location for C++. > * c-c++-common/gomp/order-3.c: Likewise. > * c-c++-common/pr69733.c: Use -Wno-volatile in C++. > * c-c++-common/spec-barrier-2.c: Likewise. > * c-c++-common/tm/pr54893.c: Likewise. > * g++.dg/cpp0x/pr65327.C: Add dg-warning. > * g++.dg/cpp0x/rv-conv2.C: Likewise. > * g++.dg/cpp0x/rv1n.C: Likewise. > * g++.dg/cpp0x/rv1p.C: Likewise. > * g++.dg/cpp0x/rv2n.C: Likewise. > * g++.dg/cpp0x/rv2p.C: Likewise. > * g++.dg/cpp0x/rv3n.C: Likewise. > * g++.dg/cpp0x/rv3p.C: Likewise. > * g++.dg/cpp0x/rv4n.C: Likewise. > * g++.dg/cpp0x/rv4p.C: Likewise. > * g++.dg/cpp0x/rv5n.C: Likewise. > * g++.dg/cpp0x/rv5p.C: Likewise. > * g++.dg/cpp0x/rv6n.C: Likewise. > * g++.dg/cpp0x/rv6p.C: Likewise. > * g++.dg/cpp0x/rv7n.C: Likewise. > * g++.dg/cpp0x/rv7p.C: Likewise. > * g++.dg/cpp0x/rv8p.C: Likewise. > * g++.dg/cpp0x/trailing14.C: Use -Wno-volatile. > * g++.dg/cpp1y/new1.C: Add dg-warning. > * g++.dg/cpp2a/volatile1.C: New test. > * g++.dg/cpp2a/volatile2.C: New test. > * g++.dg/cpp2a/volatile3.C: New test. > * g++.dg/cpp2a/volatile4.C: New test. > * g++.dg/expr/bool3.C: Add dg-warning. > * g++.dg/expr/bool4.C: Likewise. > * g++.dg/expr/cond9.C: Likewise. > * g++.dg/ext/vector25.C: Likewise. > * g++.dg/gomp/depend-iterator-1.C: Use -Wno-volatile. > * g++.dg/inherit/covariant21.C: Add dg-warning. > * g++.dg/init/ref18.C: Likewise. > * g++.dg/ipa/pr63838.C: Likewise. > * g++.dg/overload/rvalue2.C: Likewise. > * g++.dg/parse/semicolon4.C: Likewise. > * g++.dg/warn/Wreturn-type-4.C: Likewise. > * g++.dg/warn/pr36069.C: Likewise. > * g++.old-deja/g++.mike/p9506.C: Likewise. > * g++.old-deja/g++.other/volatile1.C: Likewise. > > diff --git gcc/c-family/c-opts.c gcc/c-family/c-opts.c > index da783e4990c..fa8cd0ccb09 100644 > --- gcc/c-family/c-opts.c > +++ gcc/c-family/c-opts.c > @@ -919,6 +919,10 @@ c_common_post_options (const char **pfilename) > if (!global_options_set.x_warn_comma_subscript) > warn_comma_subscript = (cxx_dialect >= cxx2a && warn_deprecated); > > + /* -Wvolatile is enabled by default in C++20. */ > + if (!global_options_set.x_warn_volatile) > + warn_volatile = (cxx_dialect >= cxx2a && warn_deprecated); > + > /* Declone C++ 'structors if -Os. */ > if (flag_declone_ctor_dtor == -1) > flag_declone_ctor_dtor = optimize_size; > diff --git gcc/c-family/c.opt gcc/c-family/c.opt > index 4c468d0f6c2..f8a1a1dbdad 100644 > --- gcc/c-family/c.opt > +++ gcc/c-family/c.opt > @@ -1228,6 +1228,10 @@ Wno-vla-larger-than > C ObjC C++ LTO ObjC++ Alias(Wvla-larger-than=,18446744073709551615EiB,none) Warning > -Wno-vla-larger-than Disable Wvla-larger-than= warning. Equivalent to Wvla-larger-than=<SIZE_MAX> or larger. > > +Wvolatile > +C++ ObjC++ Var(warn_volatile) Warning > +Warn about deprecated uses of volatile qualifier. > + > Wvolatile-register-var > C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) > Warn when a register variable is declared volatile. > diff --git gcc/cp/cp-gimplify.c gcc/cp/cp-gimplify.c > index 065dcb7ba06..49fa47ac3af 100644 > --- gcc/cp/cp-gimplify.c > +++ gcc/cp/cp-gimplify.c > @@ -2507,6 +2507,9 @@ cp_fold (tree x) > else > x = org_x; > } > + if (code == MODIFY_EXPR && TREE_CODE (x) == MODIFY_EXPR) > + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); > + > break; > > case VEC_COND_EXPR: > diff --git gcc/cp/decl.c gcc/cp/decl.c > index c5cc22a8d6d..2aef330455f 100644 > --- gcc/cp/decl.c > +++ gcc/cp/decl.c > @@ -11233,6 +11233,10 @@ grokdeclarator (const cp_declarator *declarator, > if (concept_p) > error_at (declspecs->locations[ds_concept], > "structured binding declaration cannot be %qs", "concept"); > + /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ > + if (type_quals & TYPE_QUAL_VOLATILE) > + warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, > + "%<volatile%>-qualified structured binding is deprecated"); > switch (storage_class) > { > case sc_none: > @@ -11623,6 +11627,13 @@ grokdeclarator (const cp_declarator *declarator, > if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) > warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " > "qualifiers ignored on function return type"); > + /* [dcl.fct] "A volatile-qualified return type is > + deprecated." */ > + if (type_quals & TYPE_QUAL_VOLATILE) > + warning_at (typespec_loc, OPT_Wvolatile, > + "%<volatile%>-qualified return type is " > + "deprecated"); > + > /* We now know that the TYPE_QUALS don't apply to the > decl, but to its return type. */ > type_quals = TYPE_UNQUALIFIED; > @@ -13378,6 +13389,13 @@ grokparms (tree parmlist, tree *parms) > cp_warn_deprecated_use (deptype); > } > > + /* [dcl.fct] "A parameter with volatile-qualified type is > + deprecated." */ > + if (CP_TYPE_VOLATILE_P (type)) > + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wvolatile, > + "%<volatile%>-qualified parameter is " > + "deprecated"); > + > /* Top-level qualifiers on the parameters are > ignored for function types. */ > type = cp_build_qualified_type (type, 0); > diff --git gcc/cp/expr.c gcc/cp/expr.c > index 9160043ed11..212a7f93c5a 100644 > --- gcc/cp/expr.c > +++ gcc/cp/expr.c > @@ -207,6 +207,28 @@ mark_use (tree expr, bool rvalue_p, bool read_p, > recurse_op[0] = true; > break; > > + case MODIFY_EXPR: > + { > + tree lhs = TREE_OPERAND (expr, 0); > + /* [expr.ass] "A simple assignment whose left operand is of > + a volatile-qualified type is deprecated unless the assignment > + is either a discarded-value expression or appears in an > + unevaluated context." */ > + if (read_p > + && !cp_unevaluated_operand > + && (TREE_THIS_VOLATILE (lhs) > + || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs))) > + && !TREE_THIS_VOLATILE (expr)) > + { > + warning_at (location_of (expr), OPT_Wvolatile, > + "using value of simple assignment with %<volatile%>-" > + "qualified left operand is deprecated"); > + /* Make sure not to warn about this assignment again. */ > + TREE_THIS_VOLATILE (expr) = true; > + } > + break; > + } > + > default: > break; > } > diff --git gcc/cp/typeck.c gcc/cp/typeck.c > index c09bb309142..d4f2d98143b 100644 > --- gcc/cp/typeck.c > +++ gcc/cp/typeck.c > @@ -6459,6 +6459,17 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, > complain)) > return error_mark_node; > > + /* [depr.volatile.type] "Postfix ++ and -- expressions and > + prefix ++ and -- expressions of volatile-qualified arithmetic > + and pointer types are deprecated." */ > + if (TREE_THIS_VOLATILE (arg) || CP_TYPE_VOLATILE_P (TREE_TYPE (arg))) > + warning_at (location, OPT_Wvolatile, > + "%qs expression of %<volatile%>-qualified type is " > + "deprecated", > + ((code == PREINCREMENT_EXPR > + || code == POSTINCREMENT_EXPR) > + ? "++" : "--")); > + > /* Forbid using -- or ++ in C++17 on `bool'. */ > if (TREE_CODE (declared_type) == BOOLEAN_TYPE) > { > @@ -8278,6 +8289,15 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype))) > || MAYBE_CLASS_TYPE_P (lhstype))); > > + /* An expression of the form E1 op= E2. [expr.ass] says: > + "Such expressions are deprecated if E1 has volatile-qualified > + type." We warn here rather than in cp_genericize_r because > + for compound assignments we are supposed to warn even if the > + assignment is a discarded-value expression. */ > + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) > + warning_at (loc, OPT_Wvolatile, > + "compound assignment with %<volatile%>-qualified left " > + "operand is deprecated"); > /* Preevaluate the RHS to make sure its evaluation is complete > before the lvalue-to-rvalue conversion of the LHS: > > @@ -8450,8 +8470,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > goto ret; > } > > - result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, > - lhstype, lhs, newrhs); > + result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, > + lhstype, lhs, newrhs); > > TREE_SIDE_EFFECTS (result) = 1; > if (!plain_assign) > diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi > index 1391a562c35..aa9886ee09f 100644 > --- gcc/doc/invoke.texi > +++ gcc/doc/invoke.texi > @@ -243,7 +243,7 @@ in the following sections. > -Wno-non-template-friend -Wold-style-cast @gol > -Woverloaded-virtual -Wno-pmf-conversions @gol > -Wno-class-conversion -Wno-terminate @gol > --Wsign-promo -Wvirtual-inheritance} > +-Wsign-promo -Wvirtual-inheritance -Wvolatile} > > @item Objective-C and Objective-C++ Language Options > @xref{Objective-C and Objective-C++ Dialect Options,,Options Controlling > @@ -3516,6 +3516,19 @@ result in a call to @code{terminate}. > Disable the warning about the case when a conversion function converts an > object to the same type, to a base class of that type, or to void; such > a conversion function will never be called. > + > +@item -Wvolatile @r{(C++ and Objective-C++ only)} > +@opindex Wvolatile > +@opindex Wno-volatile > +Warn about deprecated uses of the volatile qualifier. This includes postfix > +and prefix @code{++} and @code{--} expressions of volatile-qualified types, > +using simple assignments where the left operand is a volatile-qualified > +non-class type for their value, compound assignments where the left operand > +is a volatile-qualified non-class type, volatile-qualified function return > +type, volatile-qualified parameter type, and structured bindings of a > +volatile-qualified type. This usage was deprecated in C++20. > + > +Enabled by default with @option{-std=c++2a}. > @end table > > @node Objective-C and Objective-C++ Dialect Options > diff --git gcc/testsuite/c-c++-common/Wbool-operation-1.c gcc/testsuite/c-c++-common/Wbool-operation-1.c > index 04891878155..ce87705692a 100644 > --- gcc/testsuite/c-c++-common/Wbool-operation-1.c > +++ gcc/testsuite/c-c++-common/Wbool-operation-1.c > @@ -1,6 +1,7 @@ > /* PR c/77490 */ > /* { dg-do compile } */ > /* { dg-options "-Wall -Wno-psabi" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > #ifndef __cplusplus > # define bool _Bool > diff --git gcc/testsuite/c-c++-common/gomp/atomic-1.c gcc/testsuite/c-c++-common/gomp/atomic-1.c > index 3e4bc569ba7..1facf4586f5 100644 > --- gcc/testsuite/c-c++-common/gomp/atomic-1.c > +++ gcc/testsuite/c-c++-common/gomp/atomic-1.c > @@ -1,4 +1,5 @@ > /* { dg-do compile } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > int x; > volatile int y; > diff --git gcc/testsuite/c-c++-common/gomp/atomic-9.c gcc/testsuite/c-c++-common/gomp/atomic-9.c > index c07da8fc712..35548395f36 100644 > --- gcc/testsuite/c-c++-common/gomp/atomic-9.c > +++ gcc/testsuite/c-c++-common/gomp/atomic-9.c > @@ -1,5 +1,6 @@ > /* { dg-do compile } */ > /* { dg-options "-fopenmp -fdump-tree-ompexp" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > /* { dg-require-effective-target cas_int } */ > > volatile int *bar(void); > diff --git gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c > index 4fb01c174ec..6fa60215f43 100644 > --- gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c > +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c > @@ -1,3 +1,5 @@ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > + > int arr[64], arr2[64]; > struct S { int a[4]; } k; > short arr4[4]; > diff --git gcc/testsuite/c-c++-common/gomp/loop-1.c gcc/testsuite/c-c++-common/gomp/loop-1.c > index d2f943aea54..4fb995c02a7 100644 > --- gcc/testsuite/c-c++-common/gomp/loop-1.c > +++ gcc/testsuite/c-c++-common/gomp/loop-1.c > @@ -100,8 +100,8 @@ f4 (int *a) > #pragma omp loop order(concurrent) bind(parallel) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ > } > #pragma omp loop order(concurrent) bind(parallel) > for (i = 0; i < 64; i++) > @@ -172,8 +172,8 @@ f5 (int *a) > #pragma omp loop > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ > } > #pragma omp loop > for (i = 0; i < 64; i++) > @@ -245,8 +245,8 @@ f6 (int *a) > #pragma omp loop > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ > } > #pragma omp loop > for (i = 0; i < 64; i++) > diff --git gcc/testsuite/c-c++-common/gomp/order-3.c gcc/testsuite/c-c++-common/gomp/order-3.c > index 2d51bf37749..e33386dd5cc 100644 > --- gcc/testsuite/c-c++-common/gomp/order-3.c > +++ gcc/testsuite/c-c++-common/gomp/order-3.c > @@ -50,8 +50,8 @@ f1 (int *a) > #pragma omp simd order(concurrent) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ > } > #pragma omp simd order(concurrent) > for (i = 0; i < 64; i++) > @@ -112,8 +112,8 @@ f2 (int *a) > #pragma omp for simd order(concurrent) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ > } > #pragma omp for simd order(concurrent) > for (i = 0; i < 64; i++) > @@ -174,8 +174,8 @@ f3 (int *a) > #pragma omp for order(concurrent) > for (i = 0; i < 64; i++) > { > - #pragma omp atomic read > - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ > + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ > + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ > } > #pragma omp for order(concurrent) > for (i = 0; i < 64; i++) > diff --git gcc/testsuite/c-c++-common/pr69733.c gcc/testsuite/c-c++-common/pr69733.c > index 57ec1eccb9f..ab70f49009c 100644 > --- gcc/testsuite/c-c++-common/pr69733.c > +++ gcc/testsuite/c-c++-common/pr69733.c > @@ -1,5 +1,6 @@ > /* { dg-do compile } */ > /* { dg-options "-W -fdiagnostics-show-caret" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > typedef const double cd; > double val; > @@ -21,4 +22,3 @@ cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ > cd val2() {return val;} > ^~ > { dg-end-multiline-output "" } */ > - > diff --git gcc/testsuite/c-c++-common/spec-barrier-2.c gcc/testsuite/c-c++-common/spec-barrier-2.c > index b09567e62a9..a27ec54f0d3 100644 > --- gcc/testsuite/c-c++-common/spec-barrier-2.c > +++ gcc/testsuite/c-c++-common/spec-barrier-2.c > @@ -1,4 +1,5 @@ > /* { dg-do run } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > /* Even on targets that don't need the optional failval parameter, > side-effects on the operand should still be calculated. */ > diff --git gcc/testsuite/c-c++-common/tm/pr54893.c gcc/testsuite/c-c++-common/tm/pr54893.c > index 3766078d31e..266cbe9c652 100644 > --- gcc/testsuite/c-c++-common/tm/pr54893.c > +++ gcc/testsuite/c-c++-common/tm/pr54893.c > @@ -1,5 +1,6 @@ > /* { dg-do compile } */ > /* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */ > +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ > > /* Test that volatiles are allowed inside relaxed transactions. */ > > diff --git gcc/testsuite/g++.dg/cpp0x/pr65327.C gcc/testsuite/g++.dg/cpp0x/pr65327.C > index 5176b3c3204..6e888ebff2c 100644 > --- gcc/testsuite/g++.dg/cpp0x/pr65327.C > +++ gcc/testsuite/g++.dg/cpp0x/pr65327.C > @@ -11,7 +11,7 @@ foo () > static constexpr volatile int k = 5; > } > > -constexpr volatile int > +constexpr volatile int // { dg-warning "deprecated" "" { target c++2a } } > bar () > { > return i; > diff --git gcc/testsuite/g++.dg/cpp0x/rv-conv2.C gcc/testsuite/g++.dg/cpp0x/rv-conv2.C > index 9b9b154995b..2f2a1fa702a 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv-conv2.C > +++ gcc/testsuite/g++.dg/cpp0x/rv-conv2.C > @@ -1,16 +1,16 @@ > // PR c++/89705 > // { dg-do compile { target c++11 } } > > -struct W { operator const volatile int(); }; > +struct W { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } > const int& rci = W(); > > struct X { operator const int(); }; > int&& rri = X(); > > -struct Y { operator volatile int(); }; > +struct Y { operator volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } > int&& rri2 = Y(); > > -struct Z { operator const volatile int(); }; > +struct Z { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } > volatile int&& rri3 = Z(); > > enum E { A }; > diff --git gcc/testsuite/g++.dg/cpp0x/rv1n.C gcc/testsuite/g++.dg/cpp0x/rv1n.C > index f5e75681758..a762fc85862 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv1n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv1n.C > @@ -26,8 +26,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 1 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv1p.C gcc/testsuite/g++.dg/cpp0x/rv1p.C > index a9097276d5a..e2a983a7708 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv1p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv1p.C > @@ -26,8 +26,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 1 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv2n.C gcc/testsuite/g++.dg/cpp0x/rv2n.C > index 65eda80fba0..2871ccf9ab3 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv2n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv2n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 2 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv2p.C gcc/testsuite/g++.dg/cpp0x/rv2p.C > index 25a42ba2af8..bab0dce3d97 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv2p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv2p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 2 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv3n.C gcc/testsuite/g++.dg/cpp0x/rv3n.C > index 4549438f8ef..35cdba95858 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv3n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv3n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 3 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv3p.C gcc/testsuite/g++.dg/cpp0x/rv3p.C > index 2d7d78df6be..b25aa26c9b0 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv3p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv3p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 3 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv4n.C gcc/testsuite/g++.dg/cpp0x/rv4n.C > index 29deb3fc81b..6941a13de6c 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv4n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv4n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 4 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv4p.C gcc/testsuite/g++.dg/cpp0x/rv4p.C > index 0e4903bc291..cd0d631d780 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv4p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv4p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 4 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv5n.C gcc/testsuite/g++.dg/cpp0x/rv5n.C > index f11d07a3921..086aa460c68 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv5n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv5n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 5 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv5p.C gcc/testsuite/g++.dg/cpp0x/rv5p.C > index 63441a3f0da..34c1017f578 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv5p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv5p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 5 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv6n.C gcc/testsuite/g++.dg/cpp0x/rv6n.C > index 0ebbe33e1d1..b21d22a5b87 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv6n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv6n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 6 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv6p.C gcc/testsuite/g++.dg/cpp0x/rv6p.C > index 26714f0c9aa..fee692bb08f 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv6p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv6p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 6 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv7n.C gcc/testsuite/g++.dg/cpp0x/rv7n.C > index d9e371b8adb..5bc313cc07f 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv7n.C > +++ gcc/testsuite/g++.dg/cpp0x/rv7n.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 7 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv7p.C gcc/testsuite/g++.dg/cpp0x/rv7p.C > index 60a35835c7d..b0b8f965498 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv7p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv7p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 7 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/rv8p.C gcc/testsuite/g++.dg/cpp0x/rv8p.C > index e12da4b8d79..287fb93b432 100644 > --- gcc/testsuite/g++.dg/cpp0x/rv8p.C > +++ gcc/testsuite/g++.dg/cpp0x/rv8p.C > @@ -25,8 +25,8 @@ struct A > > A source(); > const A c_source(); > - volatile A v_source(); > -const volatile A cv_source(); > + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } > +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } > > // 8 at a time > > diff --git gcc/testsuite/g++.dg/cpp0x/trailing14.C gcc/testsuite/g++.dg/cpp0x/trailing14.C > index 2544d0bab5e..4ebb37406ad 100644 > --- gcc/testsuite/g++.dg/cpp0x/trailing14.C > +++ gcc/testsuite/g++.dg/cpp0x/trailing14.C > @@ -1,6 +1,6 @@ > // PR c++/65775 > // { dg-do compile { target c++11 } } > -// { dg-options "-Wignored-qualifiers" } > +// { dg-options "-Wignored-qualifiers -Wno-volatile" } > > using Qi = int const volatile; > Qi q1(); // { dg-warning "1: type qualifiers ignored" } > diff --git gcc/testsuite/g++.dg/cpp1y/new1.C gcc/testsuite/g++.dg/cpp1y/new1.C > index 5e4f1bf6b0b..b9ad64dfcc0 100644 > --- gcc/testsuite/g++.dg/cpp1y/new1.C > +++ gcc/testsuite/g++.dg/cpp1y/new1.C > @@ -65,7 +65,7 @@ void > test_unused() { > volatile double d = 0.0; > double *p = new double (); > - d += 1.0; > + d += 1.0; // { dg-warning "deprecated" "" { target c++2a } } > delete p; > } > > diff --git gcc/testsuite/g++.dg/cpp2a/volatile1.C gcc/testsuite/g++.dg/cpp2a/volatile1.C > new file mode 100644 > index 00000000000..e47591b13bc > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile1.C > @@ -0,0 +1,141 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++17 } } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } } > +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" "" { target c++2a } } > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + (vi = 42, 45); > + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + (void)(vi = i); > + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + decltype(i = vi = 42) x3 = i; > + > + // Compound assignments. > + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + i *= vi; > + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } > + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/cpp2a/volatile2.C gcc/testsuite/g++.dg/cpp2a/volatile2.C > new file mode 100644 > index 00000000000..1a7889a6a8c > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile2.C > @@ -0,0 +1,142 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++2a } } > +// { dg-options "-Wno-volatile" } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int > +fn (volatile int i) > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; > + ++v; > + v--; > + --v; > + p++; > + ++p; > + p--; > + --p; > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; > + &(vi = i); > + (vi = 42, 45); > + (i = vi = 42, 10); > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); > + (void)(vi = i); > + (void)(i = vi = 42); > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + decltype(i = vi = 42) x3 = i; > + > + // Compound assignments. > + vi += i; > + vi -= i; > + vi %= i; > + vi ^= i; > + vi |= i; > + vi /= i; > + vi = vi += 42; > + vi += vi = 42; > + i *= vi; > + decltype(vi -= 42) x2 = vi; > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; > + volatile auto & [vxr, vyr] = a; > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; > + u.c += 42; > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; > + t.a += 3; > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; > + t &= 42; > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/cpp2a/volatile3.C gcc/testsuite/g++.dg/cpp2a/volatile3.C > new file mode 100644 > index 00000000000..f10a29756a9 > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile3.C > @@ -0,0 +1,142 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++17 } } > +// { dg-options "-Wvolatile" } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" } > +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" } > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + (vi = 42, 45); > + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + (void)(vi = i); > + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + decltype(i = vi = 42) x3 = i; > + > + // Compound assignments. > + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + i *= vi; > + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } > + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/cpp2a/volatile4.C gcc/testsuite/g++.dg/cpp2a/volatile4.C > new file mode 100644 > index 00000000000..2148cdeb3d1 > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp2a/volatile4.C > @@ -0,0 +1,142 @@ > +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. > +// { dg-do compile { target c++2a } } > +// { dg-options "-Wno-deprecated" } > + > +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) > + > +struct S { > + volatile int a : 4; > + int b : 2; > +}; > + > +struct T { > + int a : 4; > + int b : 2; > +}; > + > +union U { > + char c; > + int i; > +}; > + > +struct W { > + W(); > + W(volatile W&); > + W& operator=(volatile W&) volatile; > +}; > + > +volatile int > +fn (volatile int i) > +{ > + volatile int v = 10; > + int *volatile p = nullptr; > + > + // Pre/post ++/--. > + v++; > + ++v; > + v--; > + --v; > + p++; > + ++p; > + p--; > + --p; > + return v + i + *p; > +} > + > +void > +fn2 () > +{ > + volatile int vi = 42; > + int i = 24; > + > + // Discarded-value expression ([expr.context]). > + // The lvalue-to-rvalue conversion is applied here: > + vi; > + // ...but not here. Otherwise we'd write to VI and then immediately read it. > + vi = 42; > + vi = i; > + vi = i = 42; > + i = vi = 42; > + &(vi = i); > + (vi = 42, 45); > + (i = vi = 42, 10); > + i = vi; // LHS not volatile. > + i = (vi = i, 42); > + static_cast<void>(vi = i); > + static_cast<void>(i = vi = 42); > + (void)(vi = i); > + (void)(i = vi = 42); > + > + // Unevaluated operand. > + decltype(vi = 42) x = vi; > + decltype(i = vi = 42) x3 = i; > + > + // Compound assignments. > + vi += i; > + vi -= i; > + vi %= i; > + vi ^= i; > + vi |= i; > + vi /= i; > + vi = vi += 42; > + vi += vi = 42; > + i *= vi; > + decltype(vi -= 42) x2 = vi; > + > + // Structured bindings. > + int a[] = { 10, 5 }; > + const auto & [cxr, cyr] = a; > + const volatile auto & [cvxr, cvyr] = a; > + volatile auto & [vxr, vyr] = a; > +} > + > +void > +fn3 () > +{ > + volatile int i, j, k = 0; > + i = j = k; > + > + ACCESS_ONCE(j); > + > + S s; > + s.b = 1; > + > + volatile U u; > + u.c = 42; > + i = u.c = 42; > + u.c += 42; > + > + volatile T t; > + t.a = 3; > + j = t.a = 3; > + t.a += 3; > + > + volatile int *src = &i; > + *src; // No assignment, don't warn. > +} > + > +void > +fn4 () > +{ > + volatile W vw; > + W w; > + // Assignment to objects of a class is defined by the copy/move assignment > + // operator. > + vw = w; > + w = vw; > +} > + > +template<typename T> > +void raccoon () > +{ > + volatile T t, u; > + t = 42; > + u = t = 42; > + t &= 42; > +} > + > +void > +fn5 () > +{ > + raccoon<int>(); > +} > diff --git gcc/testsuite/g++.dg/expr/bool3.C gcc/testsuite/g++.dg/expr/bool3.C > index 373c202b800..f27399cfc8a 100644 > --- gcc/testsuite/g++.dg/expr/bool3.C > +++ gcc/testsuite/g++.dg/expr/bool3.C > @@ -13,8 +13,10 @@ int main() > > b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } > // { dg-error "forbidden" "" { target c++17 } .-1 } > + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } > b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } > // { dg-error "forbidden" "" { target c++17 } .-1 } > + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } > i = b; > if (i != 1) > abort (); > diff --git gcc/testsuite/g++.dg/expr/bool4.C gcc/testsuite/g++.dg/expr/bool4.C > index dce51ec332e..5891bc311bd 100644 > --- gcc/testsuite/g++.dg/expr/bool4.C > +++ gcc/testsuite/g++.dg/expr/bool4.C > @@ -8,6 +8,6 @@ int main() > { > my_bool b = false; > b--; // { dg-error "" } > + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-1 } > return 0; > } > - > diff --git gcc/testsuite/g++.dg/expr/cond9.C gcc/testsuite/g++.dg/expr/cond9.C > index b344c1f683a..f7e092e1445 100644 > --- gcc/testsuite/g++.dg/expr/cond9.C > +++ gcc/testsuite/g++.dg/expr/cond9.C > @@ -4,7 +4,7 @@ struct A { // { dg-message "A" } > A(int); > }; > > -void foo(volatile A a) { > +void foo(volatile A a) { // { dg-warning "deprecated" "" { target c++2a } } > 1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" } > 1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" } > } > diff --git gcc/testsuite/g++.dg/ext/vector25.C gcc/testsuite/g++.dg/ext/vector25.C > index 6c1f5d09878..339865d6942 100644 > --- gcc/testsuite/g++.dg/ext/vector25.C > +++ gcc/testsuite/g++.dg/ext/vector25.C > @@ -2,5 +2,5 @@ volatile int i __attribute__((vector_size(8))); > > void foo() > { > - i += i; > + i += i; // { dg-warning "deprecated" "" { target c++2a } } > } > diff --git gcc/testsuite/g++.dg/gomp/depend-iterator-1.C gcc/testsuite/g++.dg/gomp/depend-iterator-1.C > index 6f4aa97ee44..d12670c5159 100644 > --- gcc/testsuite/g++.dg/gomp/depend-iterator-1.C > +++ gcc/testsuite/g++.dg/gomp/depend-iterator-1.C > @@ -1,3 +1,5 @@ > +// { dg-additional-options "-Wno-volatile" } > + > int arr[64], arr2[64]; > struct S { int a[4]; } k; > short arr4[4]; > diff --git gcc/testsuite/g++.dg/inherit/covariant21.C gcc/testsuite/g++.dg/inherit/covariant21.C > index 42cdf870081..769cb14ecbc 100644 > --- gcc/testsuite/g++.dg/inherit/covariant21.C > +++ gcc/testsuite/g++.dg/inherit/covariant21.C > @@ -6,12 +6,12 @@ struct C : A, B {}; > > struct X > { > - virtual B* foo(volatile int); > + virtual B* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } > }; > > struct Y : X > { > - virtual C* foo(volatile int); > + virtual C* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } > }; > > -C* Y::foo(volatile int) { return 0; } > +C* Y::foo(volatile int) { return 0; } // { dg-warning "deprecated" "" { target c++2a } } > diff --git gcc/testsuite/g++.dg/init/ref18.C gcc/testsuite/g++.dg/init/ref18.C > index e704077c26b..81ac76a40d3 100644 > --- gcc/testsuite/g++.dg/init/ref18.C > +++ gcc/testsuite/g++.dg/init/ref18.C > @@ -1,6 +1,6 @@ > // PR c++/49395 > > -volatile int foo(); > +volatile int foo(); // { dg-warning "deprecated" "" { target c++2a } } > struct A { volatile int i; }; > typedef volatile int vi; > > diff --git gcc/testsuite/g++.dg/ipa/pr63838.C gcc/testsuite/g++.dg/ipa/pr63838.C > index d23b3133748..5b6b11d70e5 100644 > --- gcc/testsuite/g++.dg/ipa/pr63838.C > +++ gcc/testsuite/g++.dg/ipa/pr63838.C > @@ -7,12 +7,12 @@ > __attribute__((noinline, noclone)) static void bar (int); > volatile int v; > void (*fn) (); > -struct S { S () { v++; } ~S () { v++; } }; > +struct S { S () { v++; } ~S () { v++; } }; // { dg-warning "deprecated" "" { target c++2a } } > > __attribute__((noinline, noclone)) static void > foo (int x) > { > - v++; > + v++; // { dg-warning "deprecated" "" { target c++2a } } > if (x == 5) > bar (x); > } > @@ -20,7 +20,7 @@ foo (int x) > __attribute__((noinline, noclone)) static void > bar (int x) > { > - v++; > + v++; // { dg-warning "deprecated" "" { target c++2a } } > if (x == 6) > foo (x); > else if (x == 5) > diff --git gcc/testsuite/g++.dg/overload/rvalue2.C gcc/testsuite/g++.dg/overload/rvalue2.C > index 8a2290dc293..a829fb5e8cc 100644 > --- gcc/testsuite/g++.dg/overload/rvalue2.C > +++ gcc/testsuite/g++.dg/overload/rvalue2.C > @@ -7,5 +7,5 @@ template <class T> void f(const T&); > int main() > { > volatile int i = 0; > - f(i++); > + f(i++); // { dg-warning "deprecated" "" { target c++2a } } > } > diff --git gcc/testsuite/g++.dg/parse/semicolon4.C gcc/testsuite/g++.dg/parse/semicolon4.C > index 5135ec14b1f..bdd1c845187 100644 > --- gcc/testsuite/g++.dg/parse/semicolon4.C > +++ gcc/testsuite/g++.dg/parse/semicolon4.C > @@ -25,7 +25,7 @@ struct E1 > } const; // { dg-error "'const' can only be specified for objects and functions" } > > void foo ( > -struct E2 > +struct E2 // { dg-warning "deprecated" "" { target c++2a } } > { // { dg-error "types may not be defined in parameter types" } > int i; > } volatile); > diff --git gcc/testsuite/g++.dg/warn/Wreturn-type-4.C gcc/testsuite/g++.dg/warn/Wreturn-type-4.C > index 4f02678e7f9..24a6b41cbd8 100644 > --- gcc/testsuite/g++.dg/warn/Wreturn-type-4.C > +++ gcc/testsuite/g++.dg/warn/Wreturn-type-4.C > @@ -3,6 +3,7 @@ > /* { dg-options "-Wignored-qualifiers" } */ > > volatile void bar(); /* { dg-warning "type qualifiers ignored" } */ > +// { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } .-1 } > > struct A > { > diff --git gcc/testsuite/g++.dg/warn/pr36069.C gcc/testsuite/g++.dg/warn/pr36069.C > index efb35c25716..7b166351a4b 100644 > --- gcc/testsuite/g++.dg/warn/pr36069.C > +++ gcc/testsuite/g++.dg/warn/pr36069.C > @@ -6,11 +6,13 @@ struct foo { > bool a; > volatile bool b,c; > foo() { a = b = c = false; } // { dg-bogus "parentheses" } > + // { dg-warning "deprecated" "" { target c++2a } .-1 } > }; > > int main() { > bool a; > volatile bool b,c; > a = b = c = false; // { dg-bogus "parentheses" } > + // { dg-warning "deprecated" "" { target c++2a } .-1 } > foo A; > } > diff --git gcc/testsuite/g++.old-deja/g++.mike/p9506.C gcc/testsuite/g++.old-deja/g++.mike/p9506.C > index db16e3738e2..97594640f96 100644 > --- gcc/testsuite/g++.old-deja/g++.mike/p9506.C > +++ gcc/testsuite/g++.old-deja/g++.mike/p9506.C > @@ -3,5 +3,5 @@ > > char * volatile p; > void foo() { > - --p = 0; > + --p = 0; // { dg-warning "deprecated" "" { target c++2a } } > } > diff --git gcc/testsuite/g++.old-deja/g++.other/volatile1.C gcc/testsuite/g++.old-deja/g++.other/volatile1.C > index 7d818fbe9e1..a93ef58aa9f 100644 > --- gcc/testsuite/g++.old-deja/g++.other/volatile1.C > +++ gcc/testsuite/g++.old-deja/g++.other/volatile1.C > @@ -5,7 +5,7 @@ > class f_class // { dg-message "note" "candidates" } > { }; > > -volatile f_class > +volatile f_class // { dg-warning "deprecated" "" { target c++2a } } > ret_v_f_class() > { > f_class t;
On 8/28/19 5:56 PM, Marek Polacek wrote: > --- gcc/doc/invoke.texi > +++ gcc/doc/invoke.texi > @@ -3516,6 +3516,19 @@ result in a call to @code{terminate}. > Disable the warning about the case when a conversion function converts an > object to the same type, to a base class of that type, or to void; such > a conversion function will never be called. > + > +@item -Wvolatile @r{(C++ and Objective-C++ only)} > +@opindex Wvolatile > +@opindex Wno-volatile > +Warn about deprecated uses of the volatile qualifier. This includes postfix > +and prefix @code{++} and @code{--} expressions of volatile-qualified types, > +using simple assignments where the left operand is a volatile-qualified > +non-class type for their value, compound assignments where the left operand > +is a volatile-qualified non-class type, volatile-qualified function return > +type, volatile-qualified parameter type, and structured bindings of a > +volatile-qualified type. This usage was deprecated in C++20. Just a minor thing: Since the text uses volatile as a keyword (as opposed to an adjective) it should be @code{volatile}, analogously how it's quoted in warnings. Martin
On Thu, Aug 29, 2019 at 03:14:36PM -0600, Martin Sebor wrote: > On 8/28/19 5:56 PM, Marek Polacek wrote: > > --- gcc/doc/invoke.texi > > +++ gcc/doc/invoke.texi > > @@ -3516,6 +3516,19 @@ result in a call to @code{terminate}. > > Disable the warning about the case when a conversion function converts an > > object to the same type, to a base class of that type, or to void; such > > a conversion function will never be called. > > + > > +@item -Wvolatile @r{(C++ and Objective-C++ only)} > > +@opindex Wvolatile > > +@opindex Wno-volatile > > +Warn about deprecated uses of the volatile qualifier. This includes postfix > > +and prefix @code{++} and @code{--} expressions of volatile-qualified types, > > +using simple assignments where the left operand is a volatile-qualified > > +non-class type for their value, compound assignments where the left operand > > +is a volatile-qualified non-class type, volatile-qualified function return > > +type, volatile-qualified parameter type, and structured bindings of a > > +volatile-qualified type. This usage was deprecated in C++20. > > Just a minor thing: Since the text uses volatile as a keyword > (as opposed to an adjective) it should be @code{volatile}, > analogously how it's quoted in warnings. Oh right, thanks. Fixed with: 2019-08-30 Marek Polacek <polacek@redhat.com> * doc/invoke.texi (-Wvolatile): Use @code for volatile. diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi index aa9886ee09f..44a8801e558 100644 --- gcc/doc/invoke.texi +++ gcc/doc/invoke.texi @@ -3520,13 +3520,14 @@ a conversion function will never be called. @item -Wvolatile @r{(C++ and Objective-C++ only)} @opindex Wvolatile @opindex Wno-volatile -Warn about deprecated uses of the volatile qualifier. This includes postfix -and prefix @code{++} and @code{--} expressions of volatile-qualified types, -using simple assignments where the left operand is a volatile-qualified -non-class type for their value, compound assignments where the left operand -is a volatile-qualified non-class type, volatile-qualified function return -type, volatile-qualified parameter type, and structured bindings of a -volatile-qualified type. This usage was deprecated in C++20. +Warn about deprecated uses of the @code{volatile} qualifier. This includes +postfix and prefix @code{++} and @code{--} expressions of +@code{volatile}-qualified types, using simple assignments where the left +operand is a @code{volatile}-qualified non-class type for their value, +compound assignments where the left operand is a @code{volatile}-qualified +non-class type, @code{volatile}-qualified function return type, +@code{volatile}-qualified parameter type, and structured bindings of a +@code{volatile}-qualified type. This usage was deprecated in C++20. Enabled by default with @option{-std=c++2a}. @end table
diff --git gcc/c-family/c-opts.c gcc/c-family/c-opts.c index da783e4990c..fa8cd0ccb09 100644 --- gcc/c-family/c-opts.c +++ gcc/c-family/c-opts.c @@ -919,6 +919,10 @@ c_common_post_options (const char **pfilename) if (!global_options_set.x_warn_comma_subscript) warn_comma_subscript = (cxx_dialect >= cxx2a && warn_deprecated); + /* -Wvolatile is enabled by default in C++20. */ + if (!global_options_set.x_warn_volatile) + warn_volatile = (cxx_dialect >= cxx2a && warn_deprecated); + /* Declone C++ 'structors if -Os. */ if (flag_declone_ctor_dtor == -1) flag_declone_ctor_dtor = optimize_size; diff --git gcc/c-family/c.opt gcc/c-family/c.opt index 257cadfa5f1..5adb3c1bcd5 100644 --- gcc/c-family/c.opt +++ gcc/c-family/c.opt @@ -1221,6 +1221,10 @@ Wno-vla-larger-than C ObjC C++ LTO ObjC++ Alias(Wvla-larger-than=,18446744073709551615EiB,none) Warning -Wno-vla-larger-than Disable Wvla-larger-than= warning. Equivalent to Wvla-larger-than=<SIZE_MAX> or larger. +Wvolatile +C++ ObjC++ Var(warn_volatile) Warning +Warn about certain uses of volatile qualifier. + Wvolatile-register-var C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn when a register variable is declared volatile. diff --git gcc/cp/cp-gimplify.c gcc/cp/cp-gimplify.c index 065dcb7ba06..03ae6b0e92b 100644 --- gcc/cp/cp-gimplify.c +++ gcc/cp/cp-gimplify.c @@ -1632,6 +1632,13 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) TARGET_EXPR_NO_ELIDE (stmt) = 1; break; + case MODIFY_EXPR: + if (TREE_THIS_VOLATILE (stmt)) + warning_at (location_of (stmt), OPT_Wvolatile, + "assignment with %<volatile%>-qualified left operand " + "is deprecated"); + break; + default: if (IS_TYPE_OR_DECL_P (stmt)) *walk_subtrees = 0; @@ -2507,6 +2514,9 @@ cp_fold (tree x) else x = org_x; } + if (code == MODIFY_EXPR && TREE_CODE (x) == MODIFY_EXPR) + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); + break; case VEC_COND_EXPR: diff --git gcc/cp/decl.c gcc/cp/decl.c index 88aa69ce5de..8da2f3abf83 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -11188,6 +11188,10 @@ grokdeclarator (const cp_declarator *declarator, if (concept_p) error_at (declspecs->locations[ds_concept], "structured binding declaration cannot be %qs", "concept"); + /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ + if (type_quals & TYPE_QUAL_VOLATILE) + warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, + "%<volatile%>-qualified structured binding is deprecated"); switch (storage_class) { case sc_none: @@ -11576,6 +11580,13 @@ grokdeclarator (const cp_declarator *declarator, if (SCALAR_TYPE_P (type) || VOID_TYPE_P (type)) warning_at (typespec_loc, OPT_Wignored_qualifiers, "type " "qualifiers ignored on function return type"); + /* [dcl.fct] "A volatile-qualified return type is + deprecated." */ + if (type_quals & TYPE_QUAL_VOLATILE) + warning_at (typespec_loc, OPT_Wvolatile, + "%<volatile%>-qualified return type is " + "deprecated"); + /* We now know that the TYPE_QUALS don't apply to the decl, but to its return type. */ type_quals = TYPE_UNQUALIFIED; @@ -13314,6 +13325,13 @@ grokparms (tree parmlist, tree *parms) cp_warn_deprecated_use (deptype); } + /* [dcl.fct] "A parameter with volatile-qualified type is + deprecated." */ + if (CP_TYPE_VOLATILE_P (type)) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wvolatile, + "%<volatile%>-qualified parameter is " + "deprecated"); + /* Top-level qualifiers on the parameters are ignored for function types. */ type = cp_build_qualified_type (type, 0); diff --git gcc/cp/expr.c gcc/cp/expr.c index 9160043ed11..939143ddbcc 100644 --- gcc/cp/expr.c +++ gcc/cp/expr.c @@ -292,6 +292,11 @@ mark_discarded_use (tree expr) case INDIRECT_REF: case MEMBER_REF: break; + case MODIFY_EXPR: + /* [expr.ass] says that if the assignment with a volatile-qualified + LHS is a discarded-value expression then it is not deprecated. */ + TREE_THIS_VOLATILE (expr) = false; + return expr; default: if (DECL_P (expr)) break; diff --git gcc/cp/typeck.c gcc/cp/typeck.c index e2a4f285a72..1b456fca652 100644 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -6459,6 +6459,17 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert, complain)) return error_mark_node; + /* [depr.volatile.type] "Postfix ++ and -- expressions and + prefix ++ and -- expressions of volatile-qualified arithmetic + and pointer types are deprecated." */ + if (TREE_THIS_VOLATILE (arg) || CP_TYPE_VOLATILE_P (TREE_TYPE (arg))) + warning_at (location, OPT_Wvolatile, + "%qs expression of %<volatile%>-qualified type is " + "deprecated", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "++" : "--")); + /* Forbid using -- or ++ in C++17 on `bool'. */ if (TREE_CODE (declared_type) == BOOLEAN_TYPE) { @@ -6538,9 +6549,14 @@ tree genericize_compound_lvalue (tree lvalue) { if (TREE_SIDE_EFFECTS (TREE_OPERAND (lvalue, 0))) - lvalue = build2 (TREE_CODE (lvalue), TREE_TYPE (lvalue), - cp_stabilize_reference (TREE_OPERAND (lvalue, 0)), - TREE_OPERAND (lvalue, 1)); + { + const bool was_volatile = TREE_THIS_VOLATILE (lvalue); + lvalue = build2_loc (EXPR_LOCATION (lvalue), TREE_CODE (lvalue), + TREE_TYPE (lvalue), + cp_stabilize_reference (TREE_OPERAND (lvalue, 0)), + TREE_OPERAND (lvalue, 1)); + TREE_THIS_VOLATILE (lvalue) = was_volatile; + } return build2 (COMPOUND_EXPR, TREE_TYPE (TREE_OPERAND (lvalue, 0)), lvalue, TREE_OPERAND (lvalue, 0)); } @@ -8075,6 +8091,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, tree olhstype = lhstype; bool plain_assign = (modifycode == NOP_EXPR); bool compound_side_effects_p = false; + bool lhs_volatile_p = false; tree preeval = NULL_TREE; /* Avoid duplicate error messages from operands that had errors. */ @@ -8266,6 +8283,14 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, goto ret; } lhstype = olhstype; + + /* [expr.ass] "A simple assignment whose left operand is of + a volatile-qualified type is deprecated unless the assignment + is either a discarded-value expression or appears in an + unevaluated context." */ + if ((TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) + && !cp_unevaluated_operand) + lhs_volatile_p = true; } else { @@ -8278,6 +8303,15 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype))) || MAYBE_CLASS_TYPE_P (lhstype))); + /* An expression of the form E1 op= E2. [expr.ass] says: + "Such expressions are deprecated if E1 has volatile-qualified + type." We warn here rather than in cp_genericize_r because + for compound assignments we are supposed to warn even if the + assignment is a discarded-value expression. */ + if (TREE_THIS_VOLATILE (lhs) || CP_TYPE_VOLATILE_P (lhstype)) + warning_at (loc, OPT_Wvolatile, + "assignment with %<volatile%>-qualified left operand " + "is deprecated"); /* Preevaluate the RHS to make sure its evaluation is complete before the lvalue-to-rvalue conversion of the LHS: @@ -8450,10 +8484,11 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, goto ret; } - result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, - lhstype, lhs, newrhs); + result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, + lhstype, lhs, newrhs); TREE_SIDE_EFFECTS (result) = 1; + TREE_THIS_VOLATILE (result) = (lhs_volatile_p && modifycode == NOP_EXPR); if (!plain_assign) TREE_NO_WARNING (result) = 1; diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi index 7a356840d78..7ca86ce8cda 100644 --- gcc/doc/invoke.texi +++ gcc/doc/invoke.texi @@ -243,7 +243,7 @@ in the following sections. -Wno-non-template-friend -Wold-style-cast @gol -Woverloaded-virtual -Wno-pmf-conversions @gol -Wno-class-conversion -Wno-terminate @gol --Wsign-promo -Wvirtual-inheritance} +-Wsign-promo -Wvirtual-inheritance -Wvolatile} @item Objective-C and Objective-C++ Language Options @xref{Objective-C and Objective-C++ Dialect Options,,Options Controlling @@ -3515,6 +3515,18 @@ result in a call to @code{terminate}. Disable the warning about the case when a conversion function converts an object to the same type, to a base class of that type, or to void; such a conversion function will never be called. + +@item -Wvolatile @r{(C++ and Objective-C++ only)} +@opindex Wvolatile +@opindex Wno-volatile +Warn about certain uses of volatile qualifier. This includes postfix +@code{++} and @code{--} expressions, prefix @code{++} and @code{--} +expressions, certain assignments where the left operand is a +volatile-qualified non-class type, volatile-qualified function return +type, volatile-qualified parameter type, and a structured binding +of a volatile-qualified type. This usage was deprecated in C++2a. + +Enabled by default with @option{-std=c++2a}. @end table @node Objective-C and Objective-C++ Dialect Options diff --git gcc/testsuite/c-c++-common/Wbool-operation-1.c gcc/testsuite/c-c++-common/Wbool-operation-1.c index 04891878155..ce87705692a 100644 --- gcc/testsuite/c-c++-common/Wbool-operation-1.c +++ gcc/testsuite/c-c++-common/Wbool-operation-1.c @@ -1,6 +1,7 @@ /* PR c/77490 */ /* { dg-do compile } */ /* { dg-options "-Wall -Wno-psabi" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ #ifndef __cplusplus # define bool _Bool diff --git gcc/testsuite/c-c++-common/gomp/atomic-1.c gcc/testsuite/c-c++-common/gomp/atomic-1.c index 3e4bc569ba7..1facf4586f5 100644 --- gcc/testsuite/c-c++-common/gomp/atomic-1.c +++ gcc/testsuite/c-c++-common/gomp/atomic-1.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ int x; volatile int y; diff --git gcc/testsuite/c-c++-common/gomp/atomic-9.c gcc/testsuite/c-c++-common/gomp/atomic-9.c index c07da8fc712..35548395f36 100644 --- gcc/testsuite/c-c++-common/gomp/atomic-9.c +++ gcc/testsuite/c-c++-common/gomp/atomic-9.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-fopenmp -fdump-tree-ompexp" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* { dg-require-effective-target cas_int } */ volatile int *bar(void); diff --git gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c index 4fb01c174ec..6fa60215f43 100644 --- gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ + int arr[64], arr2[64]; struct S { int a[4]; } k; short arr4[4]; diff --git gcc/testsuite/c-c++-common/gomp/loop-1.c gcc/testsuite/c-c++-common/gomp/loop-1.c index d2f943aea54..4fb995c02a7 100644 --- gcc/testsuite/c-c++-common/gomp/loop-1.c +++ gcc/testsuite/c-c++-common/gomp/loop-1.c @@ -100,8 +100,8 @@ f4 (int *a) #pragma omp loop order(concurrent) bind(parallel) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop order(concurrent) bind(parallel) for (i = 0; i < 64; i++) @@ -172,8 +172,8 @@ f5 (int *a) #pragma omp loop for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop for (i = 0; i < 64; i++) @@ -245,8 +245,8 @@ f6 (int *a) #pragma omp loop for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" "" { target c } } */ } #pragma omp loop for (i = 0; i < 64; i++) diff --git gcc/testsuite/c-c++-common/gomp/order-3.c gcc/testsuite/c-c++-common/gomp/order-3.c index 2d51bf37749..e33386dd5cc 100644 --- gcc/testsuite/c-c++-common/gomp/order-3.c +++ gcc/testsuite/c-c++-common/gomp/order-3.c @@ -50,8 +50,8 @@ f1 (int *a) #pragma omp simd order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp simd order(concurrent) for (i = 0; i < 64; i++) @@ -112,8 +112,8 @@ f2 (int *a) #pragma omp for simd order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp for simd order(concurrent) for (i = 0; i < 64; i++) @@ -174,8 +174,8 @@ f3 (int *a) #pragma omp for order(concurrent) for (i = 0; i < 64; i++) { - #pragma omp atomic read - a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ } #pragma omp for order(concurrent) for (i = 0; i < 64; i++) diff --git gcc/testsuite/c-c++-common/pr69733.c gcc/testsuite/c-c++-common/pr69733.c index 57ec1eccb9f..ab70f49009c 100644 --- gcc/testsuite/c-c++-common/pr69733.c +++ gcc/testsuite/c-c++-common/pr69733.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-W -fdiagnostics-show-caret" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ typedef const double cd; double val; @@ -21,4 +22,3 @@ cd val2() {return val;} /* { dg-warning "qualifiers ignored" } */ cd val2() {return val;} ^~ { dg-end-multiline-output "" } */ - diff --git gcc/testsuite/c-c++-common/spec-barrier-2.c gcc/testsuite/c-c++-common/spec-barrier-2.c index b09567e62a9..a27ec54f0d3 100644 --- gcc/testsuite/c-c++-common/spec-barrier-2.c +++ gcc/testsuite/c-c++-common/spec-barrier-2.c @@ -1,4 +1,5 @@ /* { dg-do run } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* Even on targets that don't need the optional failval parameter, side-effects on the operand should still be calculated. */ diff --git gcc/testsuite/c-c++-common/tm/pr54893.c gcc/testsuite/c-c++-common/tm/pr54893.c index 3766078d31e..266cbe9c652 100644 --- gcc/testsuite/c-c++-common/tm/pr54893.c +++ gcc/testsuite/c-c++-common/tm/pr54893.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-fgnu-tm -fdump-ipa-tmipa" } */ +/* { dg-additional-options "-Wno-volatile" { target c++ } } */ /* Test that volatiles are allowed inside relaxed transactions. */ diff --git gcc/testsuite/g++.dg/cpp0x/pr65327.C gcc/testsuite/g++.dg/cpp0x/pr65327.C index 5176b3c3204..6e888ebff2c 100644 --- gcc/testsuite/g++.dg/cpp0x/pr65327.C +++ gcc/testsuite/g++.dg/cpp0x/pr65327.C @@ -11,7 +11,7 @@ foo () static constexpr volatile int k = 5; } -constexpr volatile int +constexpr volatile int // { dg-warning "deprecated" "" { target c++2a } } bar () { return i; diff --git gcc/testsuite/g++.dg/cpp0x/rv-conv2.C gcc/testsuite/g++.dg/cpp0x/rv-conv2.C index 9b9b154995b..2f2a1fa702a 100644 --- gcc/testsuite/g++.dg/cpp0x/rv-conv2.C +++ gcc/testsuite/g++.dg/cpp0x/rv-conv2.C @@ -1,16 +1,16 @@ // PR c++/89705 // { dg-do compile { target c++11 } } -struct W { operator const volatile int(); }; +struct W { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } const int& rci = W(); struct X { operator const int(); }; int&& rri = X(); -struct Y { operator volatile int(); }; +struct Y { operator volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } int&& rri2 = Y(); -struct Z { operator const volatile int(); }; +struct Z { operator const volatile int(); }; // { dg-warning "deprecated" "" { target c++2a } } volatile int&& rri3 = Z(); enum E { A }; diff --git gcc/testsuite/g++.dg/cpp0x/rv1n.C gcc/testsuite/g++.dg/cpp0x/rv1n.C index f5e75681758..a762fc85862 100644 --- gcc/testsuite/g++.dg/cpp0x/rv1n.C +++ gcc/testsuite/g++.dg/cpp0x/rv1n.C @@ -26,8 +26,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 1 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv1p.C gcc/testsuite/g++.dg/cpp0x/rv1p.C index a9097276d5a..e2a983a7708 100644 --- gcc/testsuite/g++.dg/cpp0x/rv1p.C +++ gcc/testsuite/g++.dg/cpp0x/rv1p.C @@ -26,8 +26,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 1 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv2n.C gcc/testsuite/g++.dg/cpp0x/rv2n.C index 65eda80fba0..2871ccf9ab3 100644 --- gcc/testsuite/g++.dg/cpp0x/rv2n.C +++ gcc/testsuite/g++.dg/cpp0x/rv2n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 2 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv2p.C gcc/testsuite/g++.dg/cpp0x/rv2p.C index 25a42ba2af8..bab0dce3d97 100644 --- gcc/testsuite/g++.dg/cpp0x/rv2p.C +++ gcc/testsuite/g++.dg/cpp0x/rv2p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 2 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv3n.C gcc/testsuite/g++.dg/cpp0x/rv3n.C index 4549438f8ef..35cdba95858 100644 --- gcc/testsuite/g++.dg/cpp0x/rv3n.C +++ gcc/testsuite/g++.dg/cpp0x/rv3n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 3 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv3p.C gcc/testsuite/g++.dg/cpp0x/rv3p.C index 2d7d78df6be..b25aa26c9b0 100644 --- gcc/testsuite/g++.dg/cpp0x/rv3p.C +++ gcc/testsuite/g++.dg/cpp0x/rv3p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 3 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv4n.C gcc/testsuite/g++.dg/cpp0x/rv4n.C index 29deb3fc81b..6941a13de6c 100644 --- gcc/testsuite/g++.dg/cpp0x/rv4n.C +++ gcc/testsuite/g++.dg/cpp0x/rv4n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 4 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv4p.C gcc/testsuite/g++.dg/cpp0x/rv4p.C index 0e4903bc291..cd0d631d780 100644 --- gcc/testsuite/g++.dg/cpp0x/rv4p.C +++ gcc/testsuite/g++.dg/cpp0x/rv4p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 4 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv5n.C gcc/testsuite/g++.dg/cpp0x/rv5n.C index f11d07a3921..086aa460c68 100644 --- gcc/testsuite/g++.dg/cpp0x/rv5n.C +++ gcc/testsuite/g++.dg/cpp0x/rv5n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 5 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv5p.C gcc/testsuite/g++.dg/cpp0x/rv5p.C index 63441a3f0da..34c1017f578 100644 --- gcc/testsuite/g++.dg/cpp0x/rv5p.C +++ gcc/testsuite/g++.dg/cpp0x/rv5p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 5 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv6n.C gcc/testsuite/g++.dg/cpp0x/rv6n.C index 0ebbe33e1d1..b21d22a5b87 100644 --- gcc/testsuite/g++.dg/cpp0x/rv6n.C +++ gcc/testsuite/g++.dg/cpp0x/rv6n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 6 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv6p.C gcc/testsuite/g++.dg/cpp0x/rv6p.C index 26714f0c9aa..fee692bb08f 100644 --- gcc/testsuite/g++.dg/cpp0x/rv6p.C +++ gcc/testsuite/g++.dg/cpp0x/rv6p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 6 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv7n.C gcc/testsuite/g++.dg/cpp0x/rv7n.C index d9e371b8adb..5bc313cc07f 100644 --- gcc/testsuite/g++.dg/cpp0x/rv7n.C +++ gcc/testsuite/g++.dg/cpp0x/rv7n.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 7 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv7p.C gcc/testsuite/g++.dg/cpp0x/rv7p.C index 60a35835c7d..b0b8f965498 100644 --- gcc/testsuite/g++.dg/cpp0x/rv7p.C +++ gcc/testsuite/g++.dg/cpp0x/rv7p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 7 at a time diff --git gcc/testsuite/g++.dg/cpp0x/rv8p.C gcc/testsuite/g++.dg/cpp0x/rv8p.C index e12da4b8d79..287fb93b432 100644 --- gcc/testsuite/g++.dg/cpp0x/rv8p.C +++ gcc/testsuite/g++.dg/cpp0x/rv8p.C @@ -25,8 +25,8 @@ struct A A source(); const A c_source(); - volatile A v_source(); -const volatile A cv_source(); + volatile A v_source(); // { dg-warning "deprecated" "" { target c++2a } } +const volatile A cv_source(); // { dg-warning "deprecated" "" { target c++2a } } // 8 at a time diff --git gcc/testsuite/g++.dg/cpp0x/trailing14.C gcc/testsuite/g++.dg/cpp0x/trailing14.C index 2544d0bab5e..4ebb37406ad 100644 --- gcc/testsuite/g++.dg/cpp0x/trailing14.C +++ gcc/testsuite/g++.dg/cpp0x/trailing14.C @@ -1,6 +1,6 @@ // PR c++/65775 // { dg-do compile { target c++11 } } -// { dg-options "-Wignored-qualifiers" } +// { dg-options "-Wignored-qualifiers -Wno-volatile" } using Qi = int const volatile; Qi q1(); // { dg-warning "1: type qualifiers ignored" } diff --git gcc/testsuite/g++.dg/cpp1y/new1.C gcc/testsuite/g++.dg/cpp1y/new1.C index 5e4f1bf6b0b..b9ad64dfcc0 100644 --- gcc/testsuite/g++.dg/cpp1y/new1.C +++ gcc/testsuite/g++.dg/cpp1y/new1.C @@ -65,7 +65,7 @@ void test_unused() { volatile double d = 0.0; double *p = new double (); - d += 1.0; + d += 1.0; // { dg-warning "deprecated" "" { target c++2a } } delete p; } diff --git gcc/testsuite/g++.dg/cpp2a/volatile1.C gcc/testsuite/g++.dg/cpp2a/volatile1.C new file mode 100644 index 00000000000..16c3bb417d3 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile1.C @@ -0,0 +1,140 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++17 } } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } } +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" "" { target c++2a } } +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" "" { target c++2a } } + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + (vi = 42, 45); + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + (void)(vi = i); + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + i *= vi; + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" "" { target c++2a } } +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + volatile T t; + t.a = 3; + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" "" { target c++2a } } +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile2.C gcc/testsuite/g++.dg/cpp2a/volatile2.C new file mode 100644 index 00000000000..31035e22d8f --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile2.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++2a } } +// { dg-options "-Wno-volatile" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int +fn (volatile int i) +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; + ++v; + v--; + --v; + p++; + ++p; + p--; + --p; + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; + &(vi = i); + (vi = 42, 45); + (i = vi = 42, 10); + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); + (void)(vi = i); + (void)(i = vi = 42); + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; + vi -= i; + vi %= i; + vi ^= i; + vi |= i; + vi /= i; + vi = vi += 42; + vi += vi = 42; + i *= vi; + decltype(vi -= 42) x2 = vi; + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; + volatile auto & [vxr, vyr] = a; +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; + u.c += 42; + + volatile T t; + t.a = 3; + j = t.a = 3; + t.a += 3; + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; + t &= 42; +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile3.C gcc/testsuite/g++.dg/cpp2a/volatile3.C new file mode 100644 index 00000000000..731c9aec99f --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile3.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++17 } } +// { dg-options "-Wvolatile" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int // { dg-warning ".volatile.-qualified return type is deprecated" } +fn (volatile int i) // { dg-warning ".volatile.-qualified parameter is deprecated" } +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + ++v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + v--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + --v; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + p++; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + ++p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + p--; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + --p; // { dg-warning "expression of .volatile.-qualified type is deprecated" } + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + &(vi = i); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + (vi = 42, 45); + (i = vi = 42, 10); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + (void)(vi = i); + (void)(i = vi = 42); // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi -= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi %= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi ^= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi |= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi /= i; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi = vi += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + vi += vi = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + i *= vi; + decltype(vi -= 42) x2 = vi; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } + volatile auto & [vxr, vyr] = a; // { dg-warning ".volatile.-qualified structured binding is deprecated" } +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + u.c += 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + volatile T t; + t.a = 3; + j = t.a = 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + t.a += 3; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } + t &= 42; // { dg-warning "assignment with .volatile.-qualified left operand is deprecated" } +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/cpp2a/volatile4.C gcc/testsuite/g++.dg/cpp2a/volatile4.C new file mode 100644 index 00000000000..4d039545ac9 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/volatile4.C @@ -0,0 +1,141 @@ +// PR c++/91361 - P1152R4: Deprecating some uses of volatile. +// { dg-do compile { target c++2a } } +// { dg-options "-Wno-deprecated" } + +#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x)) + +struct S { + volatile int a : 4; + int b : 2; +}; + +struct T { + int a : 4; + int b : 2; +}; + +union U { + char c; + int i; +}; + +struct W { + W(); + W(volatile W&); + W& operator=(volatile W&) volatile; +}; + +volatile int +fn (volatile int i) +{ + volatile int v = 10; + int *volatile p = nullptr; + + // Pre/post ++/--. + v++; + ++v; + v--; + --v; + p++; + ++p; + p--; + --p; + return v + i + *p; +} + +void +fn2 () +{ + volatile int vi = 42; + int i = 24; + + // Discarded-value expression ([expr.context]). + // The lvalue-to-rvalue conversion is applied here: + vi; + // ...but not here. Otherwise we'd write to VI and then immediately read it. + vi = 42; + vi = i; + vi = i = 42; + i = vi = 42; + &(vi = i); + (vi = 42, 45); + (i = vi = 42, 10); + i = vi; // LHS not volatile. + i = (vi = i, 42); + static_cast<void>(vi = i); + static_cast<void>(i = vi = 42); + (void)(vi = i); + (void)(i = vi = 42); + + // Unevaluated operand. + decltype(vi = 42) x = vi; + + // Compound assignments. + vi += i; + vi -= i; + vi %= i; + vi ^= i; + vi |= i; + vi /= i; + vi = vi += 42; + vi += vi = 42; + i *= vi; + decltype(vi -= 42) x2 = vi; + + // Structured bindings. + int a[] = { 10, 5 }; + const auto & [cxr, cyr] = a; + const volatile auto & [cvxr, cvyr] = a; + volatile auto & [vxr, vyr] = a; +} + +void +fn3 () +{ + volatile int i, j, k = 0; + i = j = k; + + ACCESS_ONCE(j); + + S s; + s.b = 1; + + volatile U u; + u.c = 42; + i = u.c = 42; + u.c += 42; + + volatile T t; + t.a = 3; + j = t.a = 3; + t.a += 3; + + volatile int *src = &i; + *src; // No assignment, don't warn. +} + +void +fn4 () +{ + volatile W vw; + W w; + // Assignment to objects of a class is defined by the copy/move assignment + // operator. + vw = w; + w = vw; +} + +template<typename T> +void raccoon () +{ + volatile T t, u; + t = 42; + u = t = 42; + t &= 42; +} + +void +fn5 () +{ + raccoon<int>(); +} diff --git gcc/testsuite/g++.dg/expr/bool3.C gcc/testsuite/g++.dg/expr/bool3.C index 373c202b800..f27399cfc8a 100644 --- gcc/testsuite/g++.dg/expr/bool3.C +++ gcc/testsuite/g++.dg/expr/bool3.C @@ -13,8 +13,10 @@ int main() b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } // { dg-error "forbidden" "" { target c++17 } .-1 } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } b++; // { dg-warning "deprecated" "" { target { ! c++17 } } } // { dg-error "forbidden" "" { target c++17 } .-1 } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-2 } i = b; if (i != 1) abort (); diff --git gcc/testsuite/g++.dg/expr/bool4.C gcc/testsuite/g++.dg/expr/bool4.C index dce51ec332e..5891bc311bd 100644 --- gcc/testsuite/g++.dg/expr/bool4.C +++ gcc/testsuite/g++.dg/expr/bool4.C @@ -8,6 +8,6 @@ int main() { my_bool b = false; b--; // { dg-error "" } + // { dg-warning ".volatile.-qualified type is deprecated" "" { target c++2a } .-1 } return 0; } - diff --git gcc/testsuite/g++.dg/expr/cond9.C gcc/testsuite/g++.dg/expr/cond9.C index b344c1f683a..f7e092e1445 100644 --- gcc/testsuite/g++.dg/expr/cond9.C +++ gcc/testsuite/g++.dg/expr/cond9.C @@ -4,7 +4,7 @@ struct A { // { dg-message "A" } A(int); }; -void foo(volatile A a) { +void foo(volatile A a) { // { dg-warning "deprecated" "" { target c++2a } } 1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" } 1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" } } diff --git gcc/testsuite/g++.dg/ext/vector25.C gcc/testsuite/g++.dg/ext/vector25.C index 6c1f5d09878..339865d6942 100644 --- gcc/testsuite/g++.dg/ext/vector25.C +++ gcc/testsuite/g++.dg/ext/vector25.C @@ -2,5 +2,5 @@ volatile int i __attribute__((vector_size(8))); void foo() { - i += i; + i += i; // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.dg/gomp/depend-iterator-1.C gcc/testsuite/g++.dg/gomp/depend-iterator-1.C index 6f4aa97ee44..d12670c5159 100644 --- gcc/testsuite/g++.dg/gomp/depend-iterator-1.C +++ gcc/testsuite/g++.dg/gomp/depend-iterator-1.C @@ -1,3 +1,5 @@ +// { dg-additional-options "-Wno-volatile" } + int arr[64], arr2[64]; struct S { int a[4]; } k; short arr4[4]; diff --git gcc/testsuite/g++.dg/inherit/covariant21.C gcc/testsuite/g++.dg/inherit/covariant21.C index 42cdf870081..769cb14ecbc 100644 --- gcc/testsuite/g++.dg/inherit/covariant21.C +++ gcc/testsuite/g++.dg/inherit/covariant21.C @@ -6,12 +6,12 @@ struct C : A, B {}; struct X { - virtual B* foo(volatile int); + virtual B* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } }; struct Y : X { - virtual C* foo(volatile int); + virtual C* foo(volatile int); // { dg-warning "deprecated" "" { target c++2a } } }; -C* Y::foo(volatile int) { return 0; } +C* Y::foo(volatile int) { return 0; } // { dg-warning "deprecated" "" { target c++2a } } diff --git gcc/testsuite/g++.dg/init/ref18.C gcc/testsuite/g++.dg/init/ref18.C index e704077c26b..81ac76a40d3 100644 --- gcc/testsuite/g++.dg/init/ref18.C +++ gcc/testsuite/g++.dg/init/ref18.C @@ -1,6 +1,6 @@ // PR c++/49395 -volatile int foo(); +volatile int foo(); // { dg-warning "deprecated" "" { target c++2a } } struct A { volatile int i; }; typedef volatile int vi; diff --git gcc/testsuite/g++.dg/ipa/pr63838.C gcc/testsuite/g++.dg/ipa/pr63838.C index d23b3133748..5b6b11d70e5 100644 --- gcc/testsuite/g++.dg/ipa/pr63838.C +++ gcc/testsuite/g++.dg/ipa/pr63838.C @@ -7,12 +7,12 @@ __attribute__((noinline, noclone)) static void bar (int); volatile int v; void (*fn) (); -struct S { S () { v++; } ~S () { v++; } }; +struct S { S () { v++; } ~S () { v++; } }; // { dg-warning "deprecated" "" { target c++2a } } __attribute__((noinline, noclone)) static void foo (int x) { - v++; + v++; // { dg-warning "deprecated" "" { target c++2a } } if (x == 5) bar (x); } @@ -20,7 +20,7 @@ foo (int x) __attribute__((noinline, noclone)) static void bar (int x) { - v++; + v++; // { dg-warning "deprecated" "" { target c++2a } } if (x == 6) foo (x); else if (x == 5) diff --git gcc/testsuite/g++.dg/overload/rvalue2.C gcc/testsuite/g++.dg/overload/rvalue2.C index 8a2290dc293..a829fb5e8cc 100644 --- gcc/testsuite/g++.dg/overload/rvalue2.C +++ gcc/testsuite/g++.dg/overload/rvalue2.C @@ -7,5 +7,5 @@ template <class T> void f(const T&); int main() { volatile int i = 0; - f(i++); + f(i++); // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.dg/parse/semicolon4.C gcc/testsuite/g++.dg/parse/semicolon4.C index 5135ec14b1f..bdd1c845187 100644 --- gcc/testsuite/g++.dg/parse/semicolon4.C +++ gcc/testsuite/g++.dg/parse/semicolon4.C @@ -25,7 +25,7 @@ struct E1 } const; // { dg-error "'const' can only be specified for objects and functions" } void foo ( -struct E2 +struct E2 // { dg-warning "deprecated" "" { target c++2a } } { // { dg-error "types may not be defined in parameter types" } int i; } volatile); diff --git gcc/testsuite/g++.dg/warn/Wreturn-type-4.C gcc/testsuite/g++.dg/warn/Wreturn-type-4.C index 4f02678e7f9..24a6b41cbd8 100644 --- gcc/testsuite/g++.dg/warn/Wreturn-type-4.C +++ gcc/testsuite/g++.dg/warn/Wreturn-type-4.C @@ -3,6 +3,7 @@ /* { dg-options "-Wignored-qualifiers" } */ volatile void bar(); /* { dg-warning "type qualifiers ignored" } */ +// { dg-warning ".volatile.-qualified return type is deprecated" "" { target c++2a } .-1 } struct A { diff --git gcc/testsuite/g++.dg/warn/pr36069.C gcc/testsuite/g++.dg/warn/pr36069.C index efb35c25716..7b166351a4b 100644 --- gcc/testsuite/g++.dg/warn/pr36069.C +++ gcc/testsuite/g++.dg/warn/pr36069.C @@ -6,11 +6,13 @@ struct foo { bool a; volatile bool b,c; foo() { a = b = c = false; } // { dg-bogus "parentheses" } + // { dg-warning "deprecated" "" { target c++2a } .-1 } }; int main() { bool a; volatile bool b,c; a = b = c = false; // { dg-bogus "parentheses" } + // { dg-warning "deprecated" "" { target c++2a } .-1 } foo A; } diff --git gcc/testsuite/g++.old-deja/g++.mike/p9506.C gcc/testsuite/g++.old-deja/g++.mike/p9506.C index db16e3738e2..97594640f96 100644 --- gcc/testsuite/g++.old-deja/g++.mike/p9506.C +++ gcc/testsuite/g++.old-deja/g++.mike/p9506.C @@ -3,5 +3,5 @@ char * volatile p; void foo() { - --p = 0; + --p = 0; // { dg-warning "deprecated" "" { target c++2a } } } diff --git gcc/testsuite/g++.old-deja/g++.other/volatile1.C gcc/testsuite/g++.old-deja/g++.other/volatile1.C index 7d818fbe9e1..a93ef58aa9f 100644 --- gcc/testsuite/g++.old-deja/g++.other/volatile1.C +++ gcc/testsuite/g++.old-deja/g++.other/volatile1.C @@ -5,7 +5,7 @@ class f_class // { dg-message "note" "candidates" } { }; -volatile f_class +volatile f_class // { dg-warning "deprecated" "" { target c++2a } } ret_v_f_class() { f_class t;