summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/Expr.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-04-02 18:24:57 +0000
committerDouglas Gregor <dgregor@apple.com>2010-04-02 18:24:57 +0000
commit45cf7e3d2a524e751c2d5c35f2761a8cfbc47fdd (patch)
tree758fe66ff8493c68ce04d93ab2ca1c9709f311b2 /clang/lib/AST/Expr.cpp
parent4b82a8876434e76921f15f4b395440179515b7b5 (diff)
downloadbcm5719-llvm-45cf7e3d2a524e751c2d5c35f2761a8cfbc47fdd.tar.gz
bcm5719-llvm-45cf7e3d2a524e751c2d5c35f2761a8cfbc47fdd.zip
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to build a copy and when it can be elided. The correct implementation is actually simpler than the approximation. When we only enumerate constructors as part of initialization (e.g., for direct initialization or when we're copying from a class type or one of its derived classes), we don't create a copy. When we enumerate all conversion functions, we do create a copy. Before, we created some extra copies and missed some others. The new test copy-initialization.cpp shows a case where we missed creating a (required, non-elidable) copy as part of a user-defined conversion, which resulted in a miscompile. This commit also fixes PR6757, where the missing copy made us reject well-formed code in the ternary operator. This commit also cleans up our handling of copy elision in the case where we create an extra copy of a temporary object, which became necessary now that we produce the right copies. The code that seeks to find the temporary object being copied has moved into Expr::getTemporaryObject(); it used to have two different not-quite-the-same implementations, one in Sema and one in CodeGen. Note that we still do not attempt to perform the named return value optimization, so we miss copy elisions for return values and throw expressions. llvm-svn: 100196
Diffstat (limited to 'clang/lib/AST/Expr.cpp')
-rw-r--r--clang/lib/AST/Expr.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 6764612c80b..ae4bc8c8012 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1476,6 +1476,71 @@ bool Expr::isDefaultArgument() const {
return isa<CXXDefaultArgExpr>(E);
}
+/// \brief Skip over any no-op casts and any temporary-binding
+/// expressions.
+static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) {
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
+ else
+ break;
+ }
+
+ while (const CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = BE->getSubExpr();
+
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr();
+ else
+ break;
+ }
+
+ return E;
+}
+
+const Expr *Expr::getTemporaryObject() const {
+ const Expr *E = skipTemporaryBindingsAndNoOpCasts(this);
+
+ // A cast can produce a temporary object. The object's construction
+ // is represented as a CXXConstructExpr.
+ if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) {
+ // Only user-defined and constructor conversions can produce
+ // temporary objects.
+ if (Cast->getCastKind() != CastExpr::CK_ConstructorConversion &&
+ Cast->getCastKind() != CastExpr::CK_UserDefinedConversion)
+ return 0;
+
+ // Strip off temporary bindings and no-op casts.
+ const Expr *Sub = skipTemporaryBindingsAndNoOpCasts(Cast->getSubExpr());
+
+ // If this is a constructor conversion, see if we have an object
+ // construction.
+ if (Cast->getCastKind() == CastExpr::CK_ConstructorConversion)
+ return dyn_cast<CXXConstructExpr>(Sub);
+
+ // If this is a user-defined conversion, see if we have a call to
+ // a function that itself returns a temporary object.
+ if (Cast->getCastKind() == CastExpr::CK_UserDefinedConversion)
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Sub))
+ if (CE->getCallReturnType()->isRecordType())
+ return CE;
+
+ return 0;
+ }
+
+ // A call returning a class type returns a temporary.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ if (CE->getCallReturnType()->isRecordType())
+ return CE;
+
+ return 0;
+ }
+
+ // Explicit temporary object constructors create temporaries.
+ return dyn_cast<CXXTemporaryObjectExpr>(E);
+}
+
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
OpenPOWER on IntegriCloud