[modules] When we see a definition of a function for which we already have a

non-visible definition, skip the new definition to avoid ending up with a
function with multiple definitions.

llvm-svn: 245664
This commit is contained in:
Richard Smith 2015-08-21 03:04:33 +00:00
parent 772527c57b
commit b9fa99649b
7 changed files with 92 additions and 59 deletions

View File

@ -1236,6 +1236,7 @@ private:
ParsingDeclSpec &DS,
AccessSpecifier AS);
void SkipFunctionBody();
Decl *ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
LateParsedAttrList *LateParsedAttrs = nullptr);

View File

@ -1440,6 +1440,12 @@ public:
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
struct SkipBodyInfo {
SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {}
bool ShouldSkip;
NamedDecl *Previous;
};
/// List of decls defined in a function prototype. This contains EnumConstants
/// that incorrectly end up in translation unit scope because there is no
/// function to pin them on. ActOnFunctionDeclarator reads this list and patches
@ -1705,11 +1711,14 @@ public:
void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
void CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition =
nullptr);
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
void CheckForFunctionRedefinition(
FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr,
SkipBodyInfo *SkipBody = nullptr);
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
SkipBodyInfo *SkipBody = nullptr);
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D,
SkipBodyInfo *SkipBody = nullptr);
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
bool isObjCMethodDecl(Decl *D) {
return D && isa<ObjCMethodDecl>(D);
@ -1851,12 +1860,6 @@ public:
TUK_Friend // Friend declaration: 'friend struct foo;'
};
struct SkipBodyInfo {
SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {}
bool ShouldSkip;
NamedDecl *Previous;
};
Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
@ -5630,10 +5633,6 @@ public:
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
Decl *ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
bool
CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
TemplateSpecializationKind NewTSK,

View File

@ -2614,6 +2614,7 @@ void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
}
else if (Tok.is(tok::colon)) {
ConsumeToken();
// FIXME: This is wrong, due to C++11 braced initialization.
while (Tok.isNot(tok::l_brace)) {
ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);

View File

@ -1067,10 +1067,17 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Tell the actions module that we have entered a function definition with the
// specified Declarator for the function.
Decl *Res = TemplateInfo.TemplateParams?
Actions.ActOnStartOfFunctionTemplateDef(getCurScope(),
*TemplateInfo.TemplateParams, D)
: Actions.ActOnStartOfFunctionDef(getCurScope(), D);
Sema::SkipBodyInfo SkipBody;
Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D,
TemplateInfo.TemplateParams
? *TemplateInfo.TemplateParams
: MultiTemplateParamsArg(),
&SkipBody);
if (SkipBody.ShouldSkip) {
SkipFunctionBody();
return Res;
}
// Break out of the ParsingDeclarator context before we parse the body.
D.complete(Res);
@ -1137,6 +1144,28 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return ParseFunctionStatementBody(Res, BodyScope);
}
void Parser::SkipFunctionBody() {
if (Tok.is(tok::equal)) {
SkipUntil(tok::semi);
return;
}
bool IsFunctionTryBlock = Tok.is(tok::kw_try);
if (IsFunctionTryBlock)
ConsumeToken();
CachedTokens Skipped;
if (ConsumeAndStoreFunctionPrologue(Skipped))
SkipMalformedDecl();
else {
SkipUntil(tok::r_brace);
while (IsFunctionTryBlock && Tok.is(tok::kw_catch)) {
SkipUntil(tok::l_brace);
SkipUntil(tok::r_brace);
}
}
}
/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
/// types for a function with a K&R-style identifier list for arguments.
void Parser::ParseKNRParamDeclarations(Declarator &D) {

View File

@ -2272,9 +2272,17 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
const Attr *NewAttribute = NewAttributes[I];
if (isa<AliasAttr>(NewAttribute)) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New))
S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def));
else {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) {
Sema::SkipBodyInfo SkipBody;
S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def), &SkipBody);
// If we're skipping this definition, drop the "alias" attribute.
if (SkipBody.ShouldSkip) {
NewAttributes.erase(NewAttributes.begin() + I);
--E;
continue;
}
} else {
VarDecl *VD = cast<VarDecl>(New);
unsigned Diag = cast<VarDecl>(Def)->isThisDeclarationADefinition() ==
VarDecl::TentativeDefinition
@ -10398,14 +10406,17 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
}
}
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
Decl *
Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
SkipBodyInfo *SkipBody) {
assert(getCurFunctionDecl() == nullptr && "Function parsing confused");
assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg());
return ActOnStartOfFunctionDef(FnBodyScope, DP);
Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists);
return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
}
void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) {
@ -10469,7 +10480,8 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
void
Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition) {
const FunctionDecl *EffectiveDefinition,
SkipBodyInfo *SkipBody) {
// Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
const FunctionDecl *Definition = EffectiveDefinition;
@ -10481,17 +10493,20 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
return;
// If we don't have a visible definition of the function, and it's inline or
// a template, it's OK to form another definition of it.
//
// FIXME: Should we skip the body of the function and use the old definition
// in this case? That may be necessary for functions that return local types
// through a deduced return type, or instantiate templates with local types.
if (!hasVisibleDefinition(Definition) &&
// a template, skip the new definition.
if (SkipBody && !hasVisibleDefinition(Definition) &&
(Definition->getFormalLinkage() == InternalLinkage ||
Definition->isInlined() ||
Definition->getDescribedFunctionTemplate() ||
Definition->getNumTemplateParameterLists()))
Definition->getNumTemplateParameterLists())) {
SkipBody->ShouldSkip = true;
if (auto *TD = Definition->getDescribedFunctionTemplate())
makeMergedDefinitionVisible(TD, FD->getLocation());
else
makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition),
FD->getLocation());
return;
}
if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern)
@ -10552,7 +10567,8 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
}
}
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
SkipBodyInfo *SkipBody) {
// Clear the last template instantiation error context.
LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation();
@ -10564,6 +10580,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
FD = FunTmpl->getTemplatedDecl();
else
FD = cast<FunctionDecl>(D);
// See if this is a redefinition.
if (!FD->isLateTemplateParsed()) {
CheckForFunctionRedefinition(FD, nullptr, SkipBody);
// If we're skipping the body, we're done. Don't enter the scope.
if (SkipBody && SkipBody->ShouldSkip)
return D;
}
// If we are instantiating a generic lambda call operator, push
// a LambdaScopeInfo onto the function stack. But use the information
// that's already been calculated (ActOnLambdaExpr) to prime the current
@ -10583,10 +10609,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// Enter a new function scope
PushFunctionScope();
// See if this is a redefinition.
if (!FD->isLateTemplateParsed())
CheckForFunctionRedefinition(FD);
// Builtin functions cannot be defined.
if (unsigned BuiltinID = FD->getBuiltinID()) {
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) &&

View File

@ -6472,24 +6472,6 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
return NewDecl;
}
Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
assert(getCurFunctionDecl() == nullptr && "Function parsing confused");
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
if (FTI.hasPrototype) {
// FIXME: Diagnose arguments without names in C.
}
Scope *ParentScope = FnBodyScope->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
TemplateParameterLists);
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {

View File

@ -8238,9 +8238,8 @@ void ASTReader::finishPendingActions() {
// Load the bodies of any functions or methods we've encountered. We do
// this now (delayed) so that we can be sure that the declaration chains
// have been fully wired up.
// FIXME: There seems to be no point in delaying this, it does not depend
// on the redecl chains having been wired up.
// have been fully wired up (hasBody relies on this).
// FIXME: We shouldn't require complete redeclaration chains here.
for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
PBEnd = PendingBodies.end();
PB != PBEnd; ++PB) {