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) {
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>()) {
--- /dev/null
+// 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;
+}