зеркало из https://github.com/microsoft/clang-1.git
Implement the C++11 discarded value expression rules for volatile lvalues. <rdar://problem/10790820>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@157420 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
c2c1e4f5ad
Коммит
e26073c852
|
@ -5267,6 +5267,61 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
|
|||
return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen);
|
||||
}
|
||||
|
||||
static bool IsSpecialDiscardedValue(Expr *E) {
|
||||
// In C++11, discarded-value expressions of a certain form are special,
|
||||
// according to [expr]p10:
|
||||
// The lvalue-to-rvalue conversion (4.1) is applied only if the
|
||||
// expression is an lvalue of volatile-qualified type and it has
|
||||
// one of the following forms:
|
||||
E = E->IgnoreParens();
|
||||
|
||||
// — id-expression (5.1.1),
|
||||
if (isa<DeclRefExpr>(E))
|
||||
return true;
|
||||
|
||||
// — subscripting (5.2.1),
|
||||
if (isa<ArraySubscriptExpr>(E))
|
||||
return true;
|
||||
|
||||
// — class member access (5.2.5),
|
||||
if (isa<MemberExpr>(E))
|
||||
return true;
|
||||
|
||||
// — indirection (5.3.1),
|
||||
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
|
||||
if (UO->getOpcode() == UO_Deref)
|
||||
return true;
|
||||
|
||||
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
|
||||
// — pointer-to-member operation (5.5),
|
||||
if (BO->isPtrMemOp())
|
||||
return true;
|
||||
|
||||
// — comma expression (5.18) where the right operand is one of the above.
|
||||
if (BO->getOpcode() == BO_Comma)
|
||||
return IsSpecialDiscardedValue(BO->getRHS());
|
||||
}
|
||||
|
||||
// — conditional expression (5.16) where both the second and the third
|
||||
// operands are one of the above, or
|
||||
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
|
||||
return IsSpecialDiscardedValue(CO->getTrueExpr()) &&
|
||||
IsSpecialDiscardedValue(CO->getFalseExpr());
|
||||
// The related edge case of "*x ?: *x".
|
||||
if (BinaryConditionalOperator *BCO =
|
||||
dyn_cast<BinaryConditionalOperator>(E)) {
|
||||
if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(BCO->getTrueExpr()))
|
||||
return IsSpecialDiscardedValue(OVE->getSourceExpr()) &&
|
||||
IsSpecialDiscardedValue(BCO->getFalseExpr());
|
||||
}
|
||||
|
||||
// Objective-C++ extensions to the rule.
|
||||
if (isa<PseudoObjectExpr>(E) || isa<ObjCIvarRefExpr>(E))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Perform the conversions required for an expression used in a
|
||||
/// context that ignores the result.
|
||||
ExprResult Sema::IgnoredValueConversions(Expr *E) {
|
||||
|
@ -5291,8 +5346,21 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
|
|||
return Owned(E);
|
||||
}
|
||||
|
||||
// Otherwise, this rule does not apply in C++, at least not for the moment.
|
||||
if (getLangOpts().CPlusPlus) return Owned(E);
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
// The C++11 standard defines the notion of a discarded-value expression;
|
||||
// normally, we don't need to do anything to handle it, but if it is a
|
||||
// volatile lvalue with a special form, we perform an lvalue-to-rvalue
|
||||
// conversion.
|
||||
if (getLangOpts().CPlusPlus0x && E->isGLValue() &&
|
||||
E->getType().isVolatileQualified() &&
|
||||
IsSpecialDiscardedValue(E)) {
|
||||
ExprResult Res = DefaultLvalueConversion(E);
|
||||
if (Res.isInvalid())
|
||||
return Owned(E);
|
||||
E = Res.take();
|
||||
}
|
||||
return Owned(E);
|
||||
}
|
||||
|
||||
// GCC seems to also exclude expressions of incomplete enum type.
|
||||
if (const EnumType *T = E->getType()->getAs<EnumType>()) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -triple x86_64-pc-linux-gnu %s -o - -std=c++11 | FileCheck %s
|
||||
|
||||
volatile int g1;
|
||||
struct S {
|
||||
volatile int a;
|
||||
} g2;
|
||||
|
||||
volatile int& refcall();
|
||||
|
||||
// CHECK: define void @_Z2f1PViPV1S
|
||||
void f1(volatile int *x, volatile S* s) {
|
||||
// We should perform the load in these cases.
|
||||
// CHECK: load volatile i32*
|
||||
(*x);
|
||||
// CHECK: load volatile i32*
|
||||
__extension__ g1;
|
||||
// CHECK: load volatile i32*
|
||||
s->a;
|
||||
// CHECK: load volatile i32*
|
||||
g2.a;
|
||||
// CHECK: load volatile i32*
|
||||
s->*(&S::a);
|
||||
// CHECK: load volatile i32*
|
||||
// CHECK: load volatile i32*
|
||||
x[0], 1 ? x[0] : *x;
|
||||
|
||||
// CHECK: load volatile i32*
|
||||
// CHECK: load volatile i32*
|
||||
// CHECK: load volatile i32*
|
||||
*x ?: *x;
|
||||
|
||||
// CHECK: load volatile i32*
|
||||
({ *x; });
|
||||
|
||||
// CHECK-NOT: load volatile
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
// CHECK: define void @_Z2f2PVi
|
||||
// CHECK-NOT: load volatile
|
||||
// CHECK: ret
|
||||
void f2(volatile int *x) {
|
||||
// We shouldn't perform the load in these cases.
|
||||
refcall();
|
||||
1 ? refcall() : *x;
|
||||
}
|
Загрузка…
Ссылка в новой задаче