Sema: Don't emit a missing prototype warning for deleted functions.

This is a bit more involved than I anticipated, so here's a breakdown
of the changes:
  1. Call ActOnFinishFunctionBody _after_ we parsed =default and
     =delete specifiers. Saying that we finished the body before parsing
     =default is just wrong. Changing this allows us to use isDefaulted
     and isDeleted on a decl in ActOnFinishFunctionBody.
  2. Check for -Wmissing-prototypes after we parsed the function body.
  3. Disable -Wmissing-prototypes when the Decl isDeleted.

llvm-svn: 232040
This commit is contained in:
Benjamin Kramer 2015-03-12 14:28:47 +00:00
parent e4812148e1
commit 8610cae98a
3 changed files with 35 additions and 28 deletions

View File

@ -1048,7 +1048,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
Actions.ActOnFinishFunctionBody(Res, nullptr, false);
bool Delete = false;
SourceLocation KWLoc;
@ -1076,6 +1075,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
SkipUntil(tok::semi);
}
Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
return Res;
}

View File

@ -10188,6 +10188,10 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (FD->hasAttr<OpenCLKernelAttr>())
return false;
// Don't warn on explicitly deleted functions.
if (FD->isDeleted())
return false;
bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
@ -10330,30 +10334,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
diag::err_func_def_incomplete_result))
FD->setInvalidDecl();
// GNU warning -Wmissing-prototypes:
// Warn if a global function is defined without a previous
// prototype declaration. This warning is issued even if the
// definition itself provides a prototype. The aim is to detect
// global functions that fail to be declared in header files.
const FunctionDecl *PossibleZeroParamPrototype = nullptr;
if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
if (PossibleZeroParamPrototype) {
// We found a declaration that is not a prototype,
// but that could be a zero-parameter prototype
if (TypeSourceInfo *TI =
PossibleZeroParamPrototype->getTypeSourceInfo()) {
TypeLoc TL = TI->getTypeLoc();
if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
Diag(PossibleZeroParamPrototype->getLocation(),
diag::note_declaration_not_a_prototype)
<< PossibleZeroParamPrototype
<< FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
}
}
}
if (FnBodyScope)
PushDeclContext(FnBodyScope, FD);
@ -10555,7 +10535,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (!FD->isInvalidDecl()) {
// Don't diagnose unused parameters of defaulted or deleted functions.
if (Body)
if (!FD->isDeleted() && !FD->isDefaulted())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
FD->getReturnType(), FD);
@ -10574,6 +10554,30 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
computeNRVO(Body, getCurFunction());
}
// GNU warning -Wmissing-prototypes:
// Warn if a global function is defined without a previous
// prototype declaration. This warning is issued even if the
// definition itself provides a prototype. The aim is to detect
// global functions that fail to be declared in header files.
const FunctionDecl *PossibleZeroParamPrototype = nullptr;
if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
if (PossibleZeroParamPrototype) {
// We found a declaration that is not a prototype,
// but that could be a zero-parameter prototype
if (TypeSourceInfo *TI =
PossibleZeroParamPrototype->getTypeSourceInfo()) {
TypeLoc TL = TI->getTypeLoc();
if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
Diag(PossibleZeroParamPrototype->getLocation(),
diag::note_declaration_not_a_prototype)
<< PossibleZeroParamPrototype
<< FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
}
}
}
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
const CXXMethodDecl *KeyFunction;
if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) &&
@ -10659,7 +10663,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
"handled in the block above.");
// Verify and clean out per-function state.
if (Body) {
if (Body && (!FD || !FD->isDefaulted())) {
// C++ constructors that have function-try-blocks can't have return
// statements in the handlers of that block. (C++ [except.handle]p14)
// Verify this.

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-prototypes %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-prototypes -std=c++11 %s
void f() { } // expected-warning {{no previous prototype for function 'f'}}
@ -30,3 +30,5 @@ class I {
friend void I_friend() {}
};
// Don't warn on explicitly deleted functions.
void j() = delete;