From f798f65ccc1ba56a1d34c9228af6e01c09c7a7e8 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Thu, 24 May 2012 22:04:19 +0000 Subject: [PATCH] Implement the C++11 discarded value expression rules for volatile lvalues. . llvm-svn: 157420 --- clang/lib/Sema/SemaExprCXX.cpp | 72 ++++++++++++++++++++++++++++++++++++++++-- clang/test/CXX/expr/p10-0x.cpp | 46 +++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 clang/test/CXX/expr/p10-0x.cpp diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index efc13a9..d98cb87 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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(E)) + return true; + + // — subscripting (5.2.1), + if (isa(E)) + return true; + + // — class member access (5.2.5), + if (isa(E)) + return true; + + // — indirection (5.3.1), + if (UnaryOperator *UO = dyn_cast(E)) + if (UO->getOpcode() == UO_Deref) + return true; + + if (BinaryOperator *BO = dyn_cast(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(E)) + return IsSpecialDiscardedValue(CO->getTrueExpr()) && + IsSpecialDiscardedValue(CO->getFalseExpr()); + // The related edge case of "*x ?: *x". + if (BinaryConditionalOperator *BCO = + dyn_cast(E)) { + if (OpaqueValueExpr *OVE = dyn_cast(BCO->getTrueExpr())) + return IsSpecialDiscardedValue(OVE->getSourceExpr()) && + IsSpecialDiscardedValue(BCO->getFalseExpr()); + } + + // Objective-C++ extensions to the rule. + if (isa(E) || isa(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()) { diff --git a/clang/test/CXX/expr/p10-0x.cpp b/clang/test/CXX/expr/p10-0x.cpp new file mode 100644 index 0000000..564df884 --- /dev/null +++ b/clang/test/CXX/expr/p10-0x.cpp @@ -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; +} -- 2.7.4