7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,13 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,

SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
StartingScope, InstantiatingVarTemplate);

if (D->isNRVOVariable()) {
QualType ReturnType = cast<FunctionDecl>(DC)->getReturnType();
if (SemaRef.isCopyElisionCandidate(ReturnType, Var, false))
Var->setNRVOVariable(true);
}

return Var;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ class TreeTransform {
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, Expr *Result) {
return getSema().ActOnReturnStmt(ReturnLoc, Result);
return getSema().BuildReturnStmt(ReturnLoc, Result);
}

/// \brief Build a new declaration statement.
Expand Down
43 changes: 41 additions & 2 deletions clang/test/CodeGenCXX/nrvo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ class X {
~X();
};

template<typename T> struct Y {
Y();
static Y f() {
Y y;
return y;
}
};

// CHECK-LABEL: define void @_Z5test0v
// CHECK-EH-LABEL: define void @_Z5test0v
X test0() {
Expand Down Expand Up @@ -108,12 +116,18 @@ X test2(bool B) {

}

// CHECK-LABEL: define void @_Z5test3b
X test3(bool B) {
// FIXME: We don't manage to apply NRVO here, although we could.
{
// FIXME: llvm should apply tail here.
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NOT: call {{.*}} @_ZN1XC1ERKS_
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK: call {{.*}} @_ZN1XC1ERKS_
if (B) {
X y;
return y;
}
// FIXME: we should NRVO this variable too.
X x;
return x;
}
Expand Down Expand Up @@ -161,4 +175,29 @@ X test6() {
// CHECK-NEXT: ret void
}

X test7(bool b) {
if (b) {
X x;
return x;
}
return X();
}

X test8(bool b) {
if (b) {
X x;
return x;
} else {
X y;
return y;
}
}

Y<int> test9() {
Y<int>::f();
}

// CHECK-LABEL: define linkonce_odr void @_ZN1YIiE1fEv
// CHECK: tail call {{.*}} @_ZN1YIiEC1Ev

// CHECK-EH: attributes [[NR_NUW]] = { noreturn nounwind }