From 254170520fef51111331fb5a22c75ebfef881483 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 9 Oct 2019 00:49:40 +0000 Subject: [PATCH] [c++20] Implement most of P1152R4. Diagnose some now-deprecated uses of volatile types: * as function parameter types and return types * as the type of a structured binding declaration * as the type of the lvalue operand of an increment / decrement / compound assignment operator This does not implement a check for the deprecation of simple assignments whose results are used; that check requires somewhat more complexity and will be addressed separately. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@374133 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 17 ++++++ lib/Sema/SemaDeclCXX.cpp | 7 +++ lib/Sema/SemaExpr.cpp | 21 +++++++ lib/Sema/SemaType.cpp | 22 +++++++ test/SemaCXX/deprecated.cpp | 69 +++++++++++++++++++++- www/cxx_status.html | 2 +- 7 files changed, 138 insertions(+), 2 deletions(-) diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 48874f98e5..396f297881 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -140,6 +140,7 @@ def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">; def DeprecatedRegister : DiagGroup<"deprecated-register">; def DeprecatedThisCapture : DiagGroup<"deprecated-this-capture">; +def DeprecatedVolatile : DiagGroup<"deprecated-volatile">; def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings", [CXX11CompatDeprecatedWritableStr]>; // FIXME: Why is DeprecatedImplementations not in this group? @@ -150,6 +151,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes, DeprecatedIncrementBool, DeprecatedRegister, DeprecatedThisCapture, + DeprecatedVolatile, DeprecatedWritableStr]>, DiagCategory<"Deprecations">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d0d1a7d4ea..9d1475d201 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6650,6 +6650,23 @@ def ext_increment_bool : ExtWarn< DefaultError, InGroup; def err_increment_decrement_enum : Error< "cannot %select{decrement|increment}0 expression of enum type %1">; + +def warn_deprecated_increment_decrement_volatile : Warning< + "%select{decrement|increment}0 of object of volatile-qualified type %1 " + "is deprecated">, InGroup; +def warn_deprecated_compound_assign_volatile : Warning< + "compound assignment to object of volatile-qualified type %0 is deprecated">, + InGroup; +def warn_deprecated_volatile_return : Warning< + "volatile-qualified return type %0 is deprecated">, + InGroup; +def warn_deprecated_volatile_param : Warning< + "volatile-qualified parameter type %0 is deprecated">, + InGroup; +def warn_deprecated_volatile_structured_binding : Warning< + "volatile qualifier in structured binding declaration is deprecated">, + InGroup; + def err_catch_incomplete_ptr : Error< "cannot catch pointer to incomplete type %0">; def err_catch_incomplete_ref : Error< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9863398159..ff90b9548e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -775,6 +775,13 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, return nullptr; } + // C++2a [dcl.struct.bind]p1: + // A cv that includes volatile is deprecated + if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) && + getLangOpts().CPlusPlus2a) + Diag(DS.getVolatileSpecLoc(), + diag::warn_deprecated_volatile_structured_binding); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d158eaabde..b691668da8 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -11938,6 +11938,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, CheckForNullPointerDereference(*this, LHSExpr); + if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) { + if (CompoundType.isNull()) { + // C++2a [expr.ass]p5: + // A simple-assignment whose left operand is of a volatile-qualified + // type is deprecated unless the assignment is either a discarded-value + // expression or an unevaluated operand + // FIXME: Implement checks for this. + } else { + // C++2a [expr.ass]p6: + // [Compound-assignment] expressions are deprecated if E1 has + // volatile-qualified type + Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType; + } + } + // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. @@ -12126,6 +12141,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // Now make sure the operand is a modifiable lvalue. if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); + if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) { + // C++2a [expr.pre.inc]p1, [expr.post.inc]p1: + // An operand with volatile-qualified type is deprecated + S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile) + << IsInc << ResType; + } // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 87a672c537..fccdb2bc2e 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2475,6 +2475,11 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); + // C++2a [dcl.fct]p12: + // A volatile-qualified return type is deprecated + if (T.isVolatileQualified() && getLangOpts().CPlusPlus2a) + Diag(Loc, diag::warn_deprecated_volatile_return) << T; + return false; } @@ -2555,6 +2560,11 @@ QualType Sema::BuildFunctionType(QualType T, Invalid = true; } + // C++2a [dcl.fct]p4: + // A parameter with volatile-qualified type is deprecated + if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus2a) + Diag(Loc, diag::warn_deprecated_volatile_param) << ParamType; + ParamTypes[Idx] = ParamType; } @@ -4685,6 +4695,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(DeclType.Loc, diag::err_func_returning_qualified_void) << T; } else diagnoseRedundantReturnTypeQualifiers(S, T, D, chunkIndex); + + // C++2a [dcl.fct]p12: + // A volatile-qualified return type is deprecated + if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a) + S.Diag(DeclType.Loc, diag::warn_deprecated_volatile_return) << T; } // Objective-C ARC ownership qualifiers are ignored on the function @@ -5168,6 +5183,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, T->isObjectType()) T.addConst(); + // C++2a [dcl.fct]p4: + // A parameter with volatile-qualified type is deprecated + if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a && + (D.getContext() == DeclaratorContext::PrototypeContext || + D.getContext() == DeclaratorContext::LambdaExprParameterContext)) + S.Diag(D.getIdentifierLoc(), diag::warn_deprecated_volatile_param) << T; + // If there was an ellipsis in the declarator, the declaration declares a // parameter pack whose type may be a pack expansion type. if (D.hasEllipsis()) { diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp index b5760c37cf..36c73b0a27 100644 --- a/test/SemaCXX/deprecated.cpp +++ b/test/SemaCXX/deprecated.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -std=c++11 %s -Wdeprecated -verify -triple x86_64-linux-gnu // RUN: %clang_cc1 -std=c++14 %s -Wdeprecated -verify -triple x86_64-linux-gnu // RUN: %clang_cc1 -std=c++17 %s -Wdeprecated -verify -triple x86_64-linux-gnu -// RUN: %clang_cc1 -std=c++2a %s -Wdeprecated -verify -triple x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++2a %s -Wdeprecated -verify=expected,cxx20 -triple x86_64-linux-gnu // RUN: %clang_cc1 -std=c++14 %s -Wdeprecated -verify -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS @@ -125,5 +125,72 @@ void array_index_comma() { X()[(X(), X())]; } +namespace DeprecatedVolatile { + volatile int n = 1; + void use(int); + void f() { + // simple assignments are deprecated only if their value is used + n = 5; // ok +#if __cplusplus >= 201103L + decltype(n = 5) m = n; // ok expected-warning {{side effects}} + m = sizeof(n = 5); // ok expected-warning {{side effects}} +#endif + (n = 5, 0); // ok + use(n = 5); // FIXME: deprecated + (n = 5); // FIXME: deprecated + int q = n = 5; // FIXME: deprecated + q = n = 5; // FIXME: deprecated +#if __cplusplus >= 201103L + decltype(q = n = 5) m2 = q; // FIXME: deprecated expected-warning {{side effects}} +#endif + q = sizeof(q = n = 5); // FIXME: deprecated expected-warning {{side effects}} + + // inc / dec / compound assignments are always deprecated + ++n; // cxx20-warning {{increment of object of volatile-qualified type 'volatile int' is deprecated}} + --n; // cxx20-warning {{decrement of object of volatile-qualified type 'volatile int' is deprecated}} + n++; // cxx20-warning {{increment of object of volatile-qualified type 'volatile int' is deprecated}} + n--; // cxx20-warning {{decrement of object of volatile-qualified type 'volatile int' is deprecated}} + n += 5; // cxx20-warning {{compound assignment to object of volatile-qualified type 'volatile int' is deprecated}} + n *= 3; // cxx20-warning {{compound assignment to object of volatile-qualified type 'volatile int' is deprecated}} + n /= 2; // cxx20-warning {{compound assignment to object of volatile-qualified type 'volatile int' is deprecated}} + n %= 42; // cxx20-warning {{compound assignment to object of volatile-qualified type 'volatile int' is deprecated}} + +#if __cplusplus >= 201703L + struct X { int a, b; }; + volatile auto [x, y] = X{1, 2}; // cxx20-warning {{volatile qualifier in structured binding declaration is deprecated}} + + struct Y { volatile int a, b; }; + auto [x2, y2] = Y{1, 2}; // ok +#endif + } + volatile int g( // cxx20-warning {{volatile-qualified return type 'volatile int' is deprecated}} + volatile int n, // cxx20-warning {{volatile-qualified parameter type 'volatile int' is deprecated}} + volatile int (*p)( // cxx20-warning {{volatile-qualified return type 'volatile int' is deprecated}} + volatile int m) // cxx20-warning {{volatile-qualified parameter type 'volatile int' is deprecated}} + ); +#if __cplusplus >= 201103L + auto lambda = []( // cxx20-warning{{volatile-qualified return type 'volatile int' is deprecated}} + volatile int n) // cxx20-warning{{volatile-qualified parameter type 'volatile int' is deprecated}} + -> volatile int { return n; }; +#endif + + template T f(T v); // cxx20-warning 2{{deprecated}} + int use_f = f(0); // FIXME: Missing "in instantiation of" note. + + // OK, only the built-in operators are deprecated. + struct UDT { + UDT(volatile const UDT&); + UDT &operator=(const UDT&); + UDT &operator=(const UDT&) volatile; + UDT operator+=(const UDT&) volatile; + }; + void h(UDT a) { + volatile UDT b = a; + volatile UDT c = b; + a = c = a; + b += a; + } +} + # 1 "/usr/include/system-header.h" 1 3 void system_header_function(void) throw(); diff --git a/www/cxx_status.html b/www/cxx_status.html index e53dbc5206..0c6f3dec04 100755 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -1103,7 +1103,7 @@ as the draft C++2a standard evolves. Deprecate some problematic uses of volatile P1152R4 - No + Partial [[nodiscard("with reason")]] -- 2.40.0