[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. llvm-svn: 374133
This commit is contained in:
parent
ad6690afa3
commit
84ef9c6493
|
@ -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">;
|
||||
|
||||
|
|
|
@ -6650,6 +6650,23 @@ def ext_increment_bool : ExtWarn<
|
|||
DefaultError, InGroup<IncrementBool>;
|
||||
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<DeprecatedVolatile>;
|
||||
def warn_deprecated_compound_assign_volatile : Warning<
|
||||
"compound assignment to object of volatile-qualified type %0 is deprecated">,
|
||||
InGroup<DeprecatedVolatile>;
|
||||
def warn_deprecated_volatile_return : Warning<
|
||||
"volatile-qualified return type %0 is deprecated">,
|
||||
InGroup<DeprecatedVolatile>;
|
||||
def warn_deprecated_volatile_param : Warning<
|
||||
"volatile-qualified parameter type %0 is deprecated">,
|
||||
InGroup<DeprecatedVolatile>;
|
||||
def warn_deprecated_volatile_structured_binding : Warning<
|
||||
"volatile qualifier in structured binding declaration is deprecated">,
|
||||
InGroup<DeprecatedVolatile>;
|
||||
|
||||
def err_catch_incomplete_ptr : Error<
|
||||
"cannot catch pointer to incomplete type %0">;
|
||||
def err_catch_incomplete_ref : Error<
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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<typename T> T f(T v); // cxx20-warning 2{{deprecated}}
|
||||
int use_f = f<volatile int>(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();
|
||||
|
|
|
@ -1103,7 +1103,7 @@ as the draft C++2a standard evolves.
|
|||
<tr>
|
||||
<td>Deprecate some problematic uses of <tt>volatile</tt></td>
|
||||
<td><a href="http://wg21.link/p1152r4">P1152R4</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="partial" align="center">Partial</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>[[nodiscard("with reason")]]</tt></td>
|
||||
|
|
Loading…
Reference in New Issue