aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/CGDecl.cpp58
-rw-r--r--lib/CodeGen/CGStmt.cpp7
-rw-r--r--lib/Sema/SemaStmt.cpp3
3 files changed, 44 insertions, 24 deletions
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 48198ff576..c93d9ba33d 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -398,16 +398,19 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
CharUnits Align = CharUnits::Zero();
bool IsSimpleConstantInitializer = false;
+ bool NRVO = false;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
-
+ NRVO = getContext().getLangOptions().ElideConstructors &&
+ D.isNRVOVariable();
// If this value is an array or struct, is POD, and if the initializer is
- // a staticly determinable constant, try to optimize it.
+ // a staticly determinable constant, try to optimize it (unless the NRVO
+ // is already optimizing this).
if (D.getInit() && !isByRef &&
(Ty->isArrayType() || Ty->isRecordType()) &&
Ty->isPODType() &&
- D.getInit()->isConstantInitializer(getContext())) {
+ D.getInit()->isConstantInitializer(getContext()) && !NRVO) {
// If this variable is marked 'const', emit the value as a global.
if (CGM.getCodeGenOpts().MergeAllConstants &&
Ty.isConstant(getContext())) {
@@ -418,19 +421,29 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
IsSimpleConstantInitializer = true;
}
- // A normal fixed sized variable becomes an alloca in the entry block.
+ // A normal fixed sized variable becomes an alloca in the entry block,
+ // unless it's an NRVO variable.
const llvm::Type *LTy = ConvertTypeForMem(Ty);
- if (isByRef)
- LTy = BuildByRefType(&D);
- llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- Alloc->setName(D.getNameAsString());
-
- Align = getContext().getDeclAlign(&D);
- if (isByRef)
- Align = std::max(Align,
- CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
- Alloc->setAlignment(Align.getQuantity());
- DeclPtr = Alloc;
+
+ if (NRVO) {
+ // The named return value optimization: allocate this variable in the
+ // return slot, so that we can elide the copy when returning this
+ // variable (C++0x [class.copy]p34).
+ DeclPtr = ReturnValue;
+ } else {
+ if (isByRef)
+ LTy = BuildByRefType(&D);
+
+ llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
+ Alloc->setName(D.getNameAsString());
+
+ Align = getContext().getDeclAlign(&D);
+ if (isByRef)
+ Align = std::max(Align,
+ CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
+ Alloc->setAlignment(Align.getQuantity());
+ DeclPtr = Alloc;
+ }
} else {
// Targets that don't support recursion emit locals as globals.
const char *Class =
@@ -645,13 +658,14 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
DtorTy = getContext().getBaseElementType(Array);
if (const RecordType *RT = DtorTy->getAs<RecordType>())
- if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- llvm::Value *Loc = DeclPtr;
- if (isByRef)
- Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
- D.getNameAsString());
-
- if (!ClassDecl->hasTrivialDestructor()) {
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!ClassDecl->hasTrivialDestructor() && !NRVO) {
+ // Note: We suppress the destructor call when this is an NRVO variable.
+ llvm::Value *Loc = DeclPtr;
+ if (isByRef)
+ Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
+ D.getNameAsString());
+
const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext());
assert(D && "EmitLocalBlockVarDecl - destructor is nul");
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 772f640ed0..f51a899e7f 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -607,7 +607,12 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
- if (!ReturnValue) {
+ if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() &&
+ !Target.useGlobalsForAutomaticVariables()) {
+ // Apply the named return value optimization for this return statement,
+ // which means doing nothing: the appropriate result has already been
+ // constructed into the NRVO variable.
+ } else if (!ReturnValue) {
// Make sure not to return anything, but evaluate the expression
// for side effects.
if (RV)
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index f8fe4fe21c..d904907e97 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1090,7 +1090,8 @@ static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType,
return 0;
if (VD->getKind() == Decl::Var && VD->hasLocalStorage() &&
- !VD->getType()->isReferenceType() && !VD->getType().isVolatileQualified())
+ !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() &&
+ !VD->getType().isVolatileQualified())
return VD;
return 0;