зеркало из 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);
|
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
|
/// Perform the conversions required for an expression used in a
|
||||||
/// context that ignores the result.
|
/// context that ignores the result.
|
||||||
ExprResult Sema::IgnoredValueConversions(Expr *E) {
|
ExprResult Sema::IgnoredValueConversions(Expr *E) {
|
||||||
|
@ -5291,8 +5346,21 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
|
||||||
return Owned(E);
|
return Owned(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, this rule does not apply in C++, at least not for the moment.
|
if (getLangOpts().CPlusPlus) {
|
||||||
if (getLangOpts().CPlusPlus) return Owned(E);
|
// 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.
|
// GCC seems to also exclude expressions of incomplete enum type.
|
||||||
if (const EnumType *T = E->getType()->getAs<EnumType>()) {
|
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;
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче