Implement the C++11 discarded value expression rules for volatile lvalues. <rdar://problem/10790820>.

llvm-svn: 157420
This commit is contained in:
Eli Friedman 2012-05-24 22:04:19 +00:00
parent c05323dd5c
commit f798f65ccc
2 changed files with 116 additions and 2 deletions

View File

@ -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>()) {

View File

@ -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;
}