mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 16:06:05 +00:00
[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:
parent
772527c57b
commit
b9fa99649b
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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) &&
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user