diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2012-05-24 22:04:19 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2012-05-24 22:04:19 +0000 |
commit | e26073c85259be1c2f397797cc59286ac85fb3b8 (patch) | |
tree | 7de6736376ad9e5c7e88e4aa5663a0e2b1aa3461 /lib/Sema/SemaExprCXX.cpp | |
parent | c2c1e4f5ad659b9ffd75097b050a5a0e2b90d019 (diff) |
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
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index efc13a9284..d98cb87dfb 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/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<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>()) { |