[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, ParsingDeclSpec &DS,
AccessSpecifier AS); AccessSpecifier AS);
void SkipFunctionBody();
Decl *ParseFunctionDefinition(ParsingDeclarator &D, Decl *ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
LateParsedAttrList *LateParsedAttrs = nullptr); LateParsedAttrList *LateParsedAttrs = nullptr);

View File

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

View File

@ -2614,6 +2614,7 @@ void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
} }
else if (Tok.is(tok::colon)) { else if (Tok.is(tok::colon)) {
ConsumeToken(); ConsumeToken();
// FIXME: This is wrong, due to C++11 braced initialization.
while (Tok.isNot(tok::l_brace)) { while (Tok.isNot(tok::l_brace)) {
ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false); ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false);
ConsumeAndStoreUntil(tok::r_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 // Tell the actions module that we have entered a function definition with the
// specified Declarator for the function. // specified Declarator for the function.
Decl *Res = TemplateInfo.TemplateParams? Sema::SkipBodyInfo SkipBody;
Actions.ActOnStartOfFunctionTemplateDef(getCurScope(), Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D,
*TemplateInfo.TemplateParams, D) TemplateInfo.TemplateParams
: Actions.ActOnStartOfFunctionDef(getCurScope(), D); ? *TemplateInfo.TemplateParams
: MultiTemplateParamsArg(),
&SkipBody);
if (SkipBody.ShouldSkip) {
SkipFunctionBody();
return Res;
}
// Break out of the ParsingDeclarator context before we parse the body. // Break out of the ParsingDeclarator context before we parse the body.
D.complete(Res); D.complete(Res);
@ -1137,6 +1144,28 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return ParseFunctionStatementBody(Res, BodyScope); 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 /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
/// types for a function with a K&R-style identifier list for arguments. /// types for a function with a K&R-style identifier list for arguments.
void Parser::ParseKNRParamDeclarations(Declarator &D) { 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]; const Attr *NewAttribute = NewAttributes[I];
if (isa<AliasAttr>(NewAttribute)) { if (isa<AliasAttr>(NewAttribute)) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) {
S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def)); Sema::SkipBodyInfo SkipBody;
else { 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); VarDecl *VD = cast<VarDecl>(New);
unsigned Diag = cast<VarDecl>(Def)->isThisDeclarationADefinition() == unsigned Diag = cast<VarDecl>(Def)->isThisDeclarationADefinition() ==
VarDecl::TentativeDefinition 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(getCurFunctionDecl() == nullptr && "Function parsing confused");
assert(D.isFunctionDeclarator() && "Not a function declarator!"); assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent(); Scope *ParentScope = FnBodyScope->getParent();
D.setFunctionDefinitionKind(FDK_Definition); D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg()); Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists);
return ActOnStartOfFunctionDef(FnBodyScope, DP); return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
} }
void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) { void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) {
@ -10469,7 +10480,8 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
void void
Sema::CheckForFunctionRedefinition(FunctionDecl *FD, 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 // Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function. // was an extern inline function.
const FunctionDecl *Definition = EffectiveDefinition; const FunctionDecl *Definition = EffectiveDefinition;
@ -10481,17 +10493,20 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
return; return;
// If we don't have a visible definition of the function, and it's inline or // 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. // a template, skip the new definition.
// if (SkipBody && !hasVisibleDefinition(Definition) &&
// 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) &&
(Definition->getFormalLinkage() == InternalLinkage || (Definition->getFormalLinkage() == InternalLinkage ||
Definition->isInlined() || Definition->isInlined() ||
Definition->getDescribedFunctionTemplate() || 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; return;
}
if (getLangOpts().GNUMode && Definition->isInlineSpecified() && if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern) 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. // Clear the last template instantiation error context.
LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation();
@ -10564,6 +10580,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
FD = FunTmpl->getTemplatedDecl(); FD = FunTmpl->getTemplatedDecl();
else else
FD = cast<FunctionDecl>(D); 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 // If we are instantiating a generic lambda call operator, push
// a LambdaScopeInfo onto the function stack. But use the information // a LambdaScopeInfo onto the function stack. But use the information
// that's already been calculated (ActOnLambdaExpr) to prime the current // 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 // Enter a new function scope
PushFunctionScope(); PushFunctionScope();
// See if this is a redefinition.
if (!FD->isLateTemplateParsed())
CheckForFunctionRedefinition(FD);
// Builtin functions cannot be defined. // Builtin functions cannot be defined.
if (unsigned BuiltinID = FD->getBuiltinID()) { if (unsigned BuiltinID = FD->getBuiltinID()) {
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) && if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) &&

View File

@ -6472,24 +6472,6 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
return NewDecl; 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 /// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized. /// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) { 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 // 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 // this now (delayed) so that we can be sure that the declaration chains
// have been fully wired up. // have been fully wired up (hasBody relies on this).
// FIXME: There seems to be no point in delaying this, it does not depend // FIXME: We shouldn't require complete redeclaration chains here.
// on the redecl chains having been wired up.
for (PendingBodiesMap::iterator PB = PendingBodies.begin(), for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
PBEnd = PendingBodies.end(); PBEnd = PendingBodies.end();
PB != PBEnd; ++PB) { PB != PBEnd; ++PB) {