diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-05-22 05:17:18 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-05-22 05:17:18 +0000 |
commit | 2d6b0e94db30c0e2754d270753c6f75478e451bf (patch) | |
tree | 789d9601397ddcd59cd006e9e0c5cabfa5c2edc9 | |
parent | 5e30b8bf56c41fcfec63ae82ddd461c99f3c4221 (diff) |
Improve our handling of reference binding for subobjects of
temporaries. There are actually several interrelated fixes here:
- When converting an object to a base class, it's only an lvalue
cast when the original object was an lvalue and we aren't casting
pointer-to-derived to pointer-to-base. Previously, we were
misclassifying derived-to-base casts of class rvalues as lvalues,
causing various oddities (including problems with reference binding
not extending the lifetimes of some temporaries).
- Teach the code for emitting a reference binding how to look
through no-op casts and parentheses directly, since
Expr::IgnoreParenNoOpCasts is just plain wrong for this. Also, make
sure that we properly look through multiple levels of indirection
from the temporary object, but destroy the actual temporary object;
this fixes the reference-binding issue mentioned above.
- Teach Objective-C message sends to bind the result as a temporary
when needed. This is actually John's change, but it triggered the
reference-binding problem above, so it's included here. Now John
can actually test his return-slot improvements.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104434 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 26 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 34 | ||||
-rw-r--r-- | test/CodeGenCXX/references.cpp | 6 |
5 files changed, 57 insertions, 26 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 74e64e59a5..17d85dc9d9 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -211,9 +211,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, llvm::SmallVector<SubobjectAdjustment, 2> Adjustments; do { - if (const CastExpr *CE - = dyn_cast<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) { - if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { + if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + continue; + } + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if ((CE->getCastKind() == CastExpr::CK_DerivedToBase || + CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase) && + E->getType()->isRecordType()) { E = CE->getSubExpr(); CXXRecordDecl *Derived = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); @@ -221,9 +227,12 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, Derived)); continue; } - } else if (const MemberExpr *ME - = dyn_cast<MemberExpr>( - E->IgnoreParenNoopCasts(getContext()))) { + + if (CE->getCastKind() == CastExpr::CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { if (ME->getBase()->isLvalue(getContext()) != Expr::LV_Valid && ME->getBase()->getType()->isRecordType()) { if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { @@ -234,7 +243,10 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } } } - } while (false); + + // Nothing changed. + break; + } while (true); Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, IsInitializer); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index aa32bb8d8d..7b0c316c9d 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -216,6 +216,14 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } + case CastExpr::CK_DerivedToBase: + case CastExpr::CK_BaseToDerived: + case CastExpr::CK_UncheckedDerivedToBase: { + assert(0 && "cannot perform hierarchy conversion in EmitAggExpr: " + "should have been unpacked before we got here"); + break; + } + // FIXME: Remove the CK_Unknown check here. case CastExpr::CK_Unknown: case CastExpr::CK_NoOp: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8c854ab77a..d722f75222 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1404,6 +1404,9 @@ Sema::PerformObjectMemberConversion(Expr *&From, SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); + bool isLvalue + = (From->isLvalue(Context) == Expr::LV_Valid) && !PointerConversions; + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1441,7 +1444,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (PointerConversions) QType = Context.getPointerType(QType); ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); FromType = QType; FromRecordType = QRecordType; @@ -1478,7 +1481,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (PointerConversions) UType = Context.getPointerType(UType); ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); FromType = UType; FromRecordType = URecordType; } @@ -1495,7 +1498,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, return true; ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/!PointerConversions, BasePath); + isLvalue, BasePath); return false; } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index dd402b074d..695a1beca1 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -764,15 +764,17 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, } // Construct the appropriate ObjCMessageExpr. + Expr *Result; if (SuperLoc.isValid()) - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, Method, Args, - NumArgs, RBracLoc)); - - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - ReceiverTypeInfo, Sel, Method, Args, - NumArgs, RBracLoc)); + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/false, + ReceiverType, Sel, Method, Args, + NumArgs, RBracLoc); + else + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + ReceiverTypeInfo, Sel, Method, Args, + NumArgs, RBracLoc); + return MaybeBindToTemporary(Result); } // ActOnClassMessage - used for both unary and keyword messages. @@ -1007,14 +1009,16 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, return ExprError(); // Construct the appropriate ObjCMessageExpr instance. + Expr *Result; if (SuperLoc.isValid()) - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, Method, - Args, NumArgs, RBracLoc)); - - return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, - Sel, Method, Args, NumArgs, RBracLoc)); + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/true, + ReceiverType, Sel, Method, + Args, NumArgs, RBracLoc); + else + Result = ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, + Sel, Method, Args, NumArgs, RBracLoc); + return MaybeBindToTemporary(Result); } // ActOnInstanceMessage - used for both unary and keyword messages. diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp index ed162492b3..6fc610298b 100644 --- a/test/CodeGenCXX/references.cpp +++ b/test/CodeGenCXX/references.cpp @@ -215,7 +215,11 @@ namespace N2 { // CHECK: define void @_ZN2N21gEi // CHECK: call void @_ZN2N24getZEv - // FIXME: Not treated as an lvalue! + // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: store i32 19 + // CHECK: call void @_ZN2N21ZD1Ev + // CHECK: ret void void g(int i) { const X &xr = getZ().has.x; i = 19; |