Modify some deleted function methods to better reflect reality:
- New isDefined() function checks for deletedness
- isThisDeclarationADefinition checks for deletedness
- New doesThisDeclarationHaveABody() does what
isThisDeclarationADefinition() used to do
- The IsDeleted bit is not propagated across redeclarations
- isDeleted() now checks the canoncial declaration
- New isDeletedAsWritten() does what it says on the tin.
- isUserProvided() now correct (thanks Richard!)
This fixes the bug that we weren't catching
void foo() = delete;
void foo() {}
as being a redefinition.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131013 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a5ff664..07823e0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -6100,7 +6100,7 @@
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Forward declarations aren't required.
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->doesThisDeclarationHaveABody())
return false;
// Constructors and destructors are required.
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e336dd7..b57c6ab 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1422,6 +1422,17 @@
return false;
}
+bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if (I->IsDeleted || I->Body || I->IsLateTemplateParsed) {
+ Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
+ return true;
+ }
+ }
+
+ return false;
+}
+
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
if (I->Body) {
@@ -1690,7 +1701,7 @@
/// an externally visible symbol, but "extern inline" will not create an
/// externally visible symbol.
bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
- assert(isThisDeclarationADefinition() && "Must have the function definition");
+ assert(doesThisDeclarationHaveABody() && "Must have the function definition");
assert(isInlined() && "Function must be inline");
ASTContext &Context = getASTContext();
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 2fd88d7..49f2723 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -400,7 +400,7 @@
if (D->getNumParams()) POut << ", ";
POut << "...";
}
- } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) {
+ } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) {
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
if (i)
Proto += ", ";
@@ -518,9 +518,9 @@
if (D->isPure())
Out << " = 0";
- else if (D->isDeleted())
+ else if (D->isDeletedAsWritten())
Out << " = delete";
- else if (D->isThisDeclarationADefinition()) {
+ else if (D->doesThisDeclarationHaveABody()) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
// parameters.
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 8bb39ba..9bb3807 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -482,7 +482,7 @@
setFlag("trivial", D->isTrivial());
setFlag("returnzero", D->hasImplicitReturnZero());
setFlag("prototype", D->hasWrittenPrototype());
- setFlag("deleted", D->isDeleted());
+ setFlag("deleted", D->isDeletedAsWritten());
if (D->getStorageClass() != SC_None)
set("storage",
VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
@@ -493,7 +493,7 @@
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
- if (D->isThisDeclarationADefinition())
+ if (D->doesThisDeclarationHaveABody())
dispatch(D->getBody());
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 96aa725..2ccd6a7 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -727,7 +727,7 @@
}
// Forward declarations are emitted lazily on first use.
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->doesThisDeclarationHaveABody())
return;
} else {
const VarDecl *VD = cast<VarDecl>(Global);
@@ -897,7 +897,7 @@
assert(FD->isUsed() && "Sema didn't mark implicit function as used!");
DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
break;
- } else if (FD->isThisDeclarationADefinition()) {
+ } else if (FD->doesThisDeclarationHaveABody()) {
DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
break;
}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 8945028..4a2c4ab 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -79,7 +79,7 @@
MEnd = D->decls_end();
M != MEnd; ++M)
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*M))
- if (Method->isThisDeclarationADefinition() &&
+ if (Method->doesThisDeclarationHaveABody() &&
(Method->hasAttr<UsedAttr>() ||
Method->hasAttr<ConstructorAttr>()))
Builder->EmitTopLevelDecl(Method);
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index ecd6ef4..28d312a 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -173,7 +173,7 @@
break;
case Decl::Function: {
const FunctionDecl* FD = cast<FunctionDecl>(DC);
- if (FD->isThisDeclarationADefinition())
+ if (FD->doesThisDeclarationHaveABody())
Out << "[function] ";
else
Out << "<function> ";
diff --git a/lib/Index/CallGraph.cpp b/lib/Index/CallGraph.cpp
index bf3f5a8..94790b8 100644
--- a/lib/Index/CallGraph.cpp
+++ b/lib/Index/CallGraph.cpp
@@ -74,7 +74,7 @@
I != E; ++I) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
- if (FD->isThisDeclarationADefinition()) {
+ if (FD->doesThisDeclarationHaveABody()) {
// Set caller's ASTContext.
Entity Ent = Entity::get(FD, Prog);
CallGraphNode *Node = getOrInsertFunction(Ent);
diff --git a/lib/Index/Indexer.cpp b/lib/Index/Indexer.cpp
index 7f21c4f..ebba43c 100644
--- a/lib/Index/Indexer.cpp
+++ b/lib/Index/Indexer.cpp
@@ -39,7 +39,7 @@
Decl *D = Ent.getDecl(TU->getASTContext());
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isThisDeclarationADefinition())
+ if (FD->doesThisDeclarationHaveABody())
DefMap[Ent] = std::make_pair(FD, TU);
}
};
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0bf984d..46b38e1 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -938,7 +938,7 @@
static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) {
// FIXME: Should check for private access too but access is set after we get
// the decl here.
- if (D->isThisDeclarationADefinition())
+ if (D->doesThisDeclarationHaveABody())
return false;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
@@ -973,10 +973,9 @@
return false;
}
- if (FD->isThisDeclarationADefinition() &&
+ if (FD->doesThisDeclarationHaveABody() &&
Context.DeclMustBeEmitted(FD))
return false;
-
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl() ||
VD->getType().isConstant(Context) ||
@@ -1907,10 +1906,6 @@
if (Old->isPure())
New->setPure();
- // Merge the "deleted" flag.
- if (Old->isDeleted())
- New->setDeleted();
-
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
@@ -4723,7 +4718,7 @@
if (Redeclaration && Previous.isSingleResult()) {
const FunctionDecl *Def;
FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl());
- if (PrevFD && PrevFD->hasBody(Def) && D.hasAttributes()) {
+ if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) {
Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
Diag(Def->getLocation(), diag::note_previous_definition);
}
@@ -6118,7 +6113,7 @@
// Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
const FunctionDecl *Definition;
- if (FD->hasBody(Definition) &&
+ if (FD->isDefined(Definition) &&
!canRedefineFunction(Definition, getLangOptions())) {
if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern)
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ca5fdd1..41b09df 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2805,7 +2805,7 @@
CXXMethodDecl *MD) {
// No need to do the check on definitions, which require that
// the return/param types be complete.
- if (MD->isThisDeclarationADefinition())
+ if (MD->doesThisDeclarationHaveABody())
return;
// For safety's sake, just ignore it if we don't have type source
@@ -7646,7 +7646,7 @@
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
}
- Fn->setDeleted();
+ Fn->setDeletedAsWritten();
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 3e1e735..03c2bef 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2013,7 +2013,7 @@
SuppressNew)
continue;
- if (Function->hasBody())
+ if (Function->isDefined())
continue;
if (TSK == TSK_ExplicitInstantiationDefinition) {
@@ -2023,7 +2023,7 @@
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
- if (!Pattern->hasBody())
+ if (!Pattern->isDefined())
continue;
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f6cbe26..1f0bd4c 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1216,7 +1216,7 @@
D->isThisDeclarationADefinition()) {
// Check for a function body.
const FunctionDecl *Definition = 0;
- if (Function->hasBody(Definition) &&
+ if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
@@ -1248,7 +1248,7 @@
default:
if (const FunctionDecl *RPattern
= R->getTemplateInstantiationPattern())
- if (RPattern->hasBody(RPattern)) {
+ if (RPattern->isDefined(RPattern)) {
SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
@@ -2124,8 +2124,8 @@
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
- if (Tmpl->isDeleted())
- New->setDeleted();
+ if (Tmpl->isDeletedAsWritten())
+ New->setDeletedAsWritten();
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
@@ -2300,7 +2300,7 @@
FunctionDecl *Function,
bool Recursive,
bool DefinitionRequired) {
- if (Function->isInvalidDecl() || Function->hasBody())
+ if (Function->isInvalidDecl() || Function->isDefined())
return;
// Never instantiate an explicit specialization.
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 2b82f90..44b8c6a 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1385,7 +1385,7 @@
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- return Func->isThisDeclarationADefinition();
+ return Func->doesThisDeclarationHaveABody();
return isa<ObjCProtocolDecl>(D) || isa<ObjCImplementationDecl>(D);
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index dbcbadb..8c1774a 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -128,8 +128,8 @@
// have been written. We want it last because we will not read it back when
// retrieving it from the AST, we'll just lazily set the offset.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- Record.push_back(FD->isThisDeclarationADefinition());
- if (FD->isThisDeclarationADefinition())
+ Record.push_back(FD->doesThisDeclarationHaveABody());
+ if (FD->doesThisDeclarationHaveABody())
Writer.AddStmt(FD->getBody());
}
}
@@ -322,7 +322,7 @@
Record.push_back(D->isPure());
Record.push_back(D->hasInheritedPrototype());
Record.push_back(D->hasWrittenPrototype());
- Record.push_back(D->isDeleted());
+ Record.push_back(D->isDeletedAsWritten());
Record.push_back(D->isTrivial());
Record.push_back(D->hasImplicitReturnZero());
Writer.AddSourceLocation(D->getLocEnd(), Record);
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 63a5917..a51d8e0 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -97,7 +97,7 @@
void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
AnalysisManager &mgr,
BugReporter &BR) const {
- if (!D->isThisDeclarationADefinition())
+ if (!D->doesThisDeclarationHaveABody())
return;
if (!D->getResultType()->isVoidType())
return;
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
index 54cbca0..ef7bc20 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
@@ -132,7 +132,7 @@
assert(CD);
#if 0
- if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+ if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
// FIXME: invalidate the object.
return;
#endif
@@ -246,7 +246,7 @@
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+ if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
return;
// Create the context for 'this' region.
const StackFrameContext *SFC = AMgr.getStackFrame(DD,