summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorTaiju Tsuiki <tzik@google.com>2018-06-19 04:39:07 +0000
committerTaiju Tsuiki <tzik@google.com>2018-06-19 04:39:07 +0000
commitb000a8860e9ec26f4a2834dbeaba44cd27025306 (patch)
treeacb0e6018e9e3cfc7fc0c3efaf2eace9de21fb69 /clang/lib
parentc2965214efbd35ed54e08cce042e8eed778646aa (diff)
downloadbcm5719-llvm-b000a8860e9ec26f4a2834dbeaba44cd27025306.tar.gz
bcm5719-llvm-b000a8860e9ec26f4a2834dbeaba44cd27025306.zip
Update NRVO logic to support early return (Attempt 2)
Summary: This is the second attempt of r333500 (Update NRVO logic to support early return). The previous one was reverted for a miscompilation for an incorrect NRVO set up on templates such as: ``` struct Foo {}; template <typename T> T bar() { T t; if (false) return T(); return t; } ``` Where, `t` is marked as non-NRVO variable before its instantiation. However, while its instantiation, it's left an NRVO candidate, turned into an NRVO variable later. Reviewers: rsmith Reviewed By: rsmith Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D47586 llvm-svn: 335019
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/Scope.cpp24
-rw-r--r--clang/lib/Sema/SemaDecl.cpp33
-rw-r--r--clang/lib/Sema/SemaExpr.cpp10
-rw-r--r--clang/lib/Sema/SemaStmt.cpp9
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp5
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp2
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp4
7 files changed, 34 insertions, 53 deletions
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index eae5a328bfa..5a46ba26d29 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -92,7 +92,6 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
- NRVO.setPointerAndInt(nullptr, 0);
}
bool Scope::containedInPrototypeScope() const {
@@ -119,19 +118,15 @@ void Scope::AddFlags(unsigned FlagsToSet) {
Flags |= FlagsToSet;
}
-void Scope::mergeNRVOIntoParent() {
- if (VarDecl *Candidate = NRVO.getPointer()) {
- if (isDeclScope(Candidate))
- Candidate->setNRVOVariable(true);
+void Scope::setNRVOCandidate(VarDecl *Candidate) {
+ for (Decl *D : DeclsInScope) {
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (VD && VD != Candidate && VD->isNRVOCandidate())
+ VD->setNRVOVariable(false);
}
- if (getEntity())
- return;
-
- if (NRVO.getInt())
- getParent()->setNoNRVO();
- else if (NRVO.getPointer())
- getParent()->addNRVOCandidate(NRVO.getPointer());
+ if (Scope *parent = getParent())
+ parent->setNRVOCandidate(Candidate);
}
LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
@@ -191,9 +186,4 @@ void Scope::dumpImpl(raw_ostream &OS) const {
OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
if (const DeclContext *DC = getEntity())
OS << "Entity : (clang::DeclContext*)" << DC << '\n';
-
- if (NRVO.getInt())
- OS << "NRVO not allowed\n";
- else if (NRVO.getPointer())
- OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f6faf38c95e..4c98ffed71b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1798,8 +1798,6 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
- S->mergeNRVOIntoParent();
-
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
"Scope shouldn't contain decls!");
@@ -12563,21 +12561,24 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
/// optimization.
///
/// Each of the variables that is subject to the named return value
-/// optimization will be marked as NRVO variables in the AST, and any
+/// optimization will be marked as NRVO variable candidates in the AST, and any
/// return statement that has a marked NRVO variable as its NRVO candidate can
/// use the named return value optimization.
///
-/// This function applies a very simplistic algorithm for NRVO: if every return
-/// statement in the scope of a variable has the same NRVO candidate, that
-/// candidate is an NRVO variable.
+/// This function applies a very simplistic algorithm for NRVO: if every
+/// reachable return statement in the scope of a variable has the same NRVO
+/// candidate, that candidate is an NRVO variable.
void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
- ReturnStmt **Returns = Scope->Returns.data();
+ for (ReturnStmt *Return : Scope->Returns) {
+ const VarDecl *Candidate = Return->getNRVOCandidate();
+ if (!Candidate)
+ continue;
- for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) {
- if (const VarDecl *NRVOCandidate = Returns[I]->getNRVOCandidate()) {
- if (!NRVOCandidate->isNRVOVariable())
- Returns[I]->setNRVOCandidate(nullptr);
- }
+ if (Candidate->isNRVOCandidate())
+ const_cast<VarDecl*>(Candidate)->setNRVOVariable(true);
+
+ if (!Candidate->isNRVOVariable())
+ Return->setNRVOCandidate(nullptr);
}
}
@@ -12712,12 +12713,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Destructor->getParent());
- // Try to apply the named return value optimization. We have to check
- // if we can do this here because lambdas keep return statements around
- // to deduce an implicit return type.
- if (FD->getReturnType()->isRecordType() &&
- (!getLangOpts().CPlusPlus || !FD->isDependentContext()))
- computeNRVO(Body, getCurFunction());
+ // Try to apply the named return value optimization.
+ computeNRVO(Body, getCurFunction());
}
// GNU warning -Wmissing-prototypes:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index aeedd6b1691..220d6906954 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13385,13 +13385,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (Body && getCurFunction()->HasPotentialAvailabilityViolations)
DiagnoseUnguardedAvailabilityViolations(BSI->TheDecl);
- // Try to apply the named return value optimization. We have to check again
- // if we can do this, though, because blocks keep return statements around
- // to deduce an implicit return type.
- if (getLangOpts().CPlusPlus && RetTy->isRecordType() &&
- !BSI->TheDecl->isDependentContext())
- computeNRVO(Body, BSI);
-
+ // Try to apply the named return value optimization.
+ computeNRVO(Body, BSI);
+
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index ccf25ee9ebe..04f51145104 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -3455,12 +3455,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
ExpressionEvaluationContext::DiscardedStatement)
return R;
- if (VarDecl *VD =
- const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
- CurScope->addNRVOCandidate(VD);
- } else {
- CurScope->setNoNRVO();
- }
+ VarDecl *VD =
+ const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate());
+ CurScope->setNRVOCandidate(VD);
CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 68857d972b5..7e38dcc7959 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -740,12 +740,13 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
StartingScope, InstantiatingVarTemplate);
+ bool NRVO = false;
if (D->isNRVOVariable()) {
QualType ReturnType = cast<FunctionDecl>(DC)->getReturnType();
if (SemaRef.isCopyElisionCandidate(ReturnType, Var, Sema::CES_Strict))
- Var->setNRVOVariable(true);
+ NRVO = true;
}
-
+ Var->setNRVOVariable(NRVO);
Var->setImplicit(D->isImplicit());
return Var;
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index a1ce26d27ca..699a98ce4f5 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1326,7 +1326,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->NonParmVarDeclBits.IsThisDeclarationADemotedDefinition =
Record.readInt();
VD->NonParmVarDeclBits.ExceptionVar = Record.readInt();
- VD->NonParmVarDeclBits.NRVOVariable = Record.readInt();
+ VD->NonParmVarDeclBits.NRVOMode = Record.readInt();
VD->NonParmVarDeclBits.CXXForRangeDecl = Record.readInt();
VD->NonParmVarDeclBits.ObjCForDecl = Record.readInt();
VD->NonParmVarDeclBits.ARCPseudoStrong = Record.readInt();
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index cf35a2bc1fc..c1f983e5ce8 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -918,7 +918,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
if (!isa<ParmVarDecl>(D)) {
Record.push_back(D->isThisDeclarationADemotedDefinition());
Record.push_back(D->isExceptionVariable());
- Record.push_back(D->isNRVOVariable());
+ Record.push_back(D->getNRVOMode());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isObjCForDecl());
Record.push_back(D->isARCPseudoStrong());
@@ -2031,7 +2031,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // InitStyle
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsThisDeclarationADemotedDefinition
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // NRVOMode
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isObjCForDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
OpenPOWER on IntegriCloud