From a6f97071338e525d18e607ca286e338639dd2a5e Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Thu, 17 Jan 2013 00:26:13 +0000 Subject: [PATCH] Implement a fixit for -Wmain-return-type git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172684 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 1 + lib/Sema/SemaDecl.cpp | 30 ++++++++++++- test/Sema/gnu89.c | 2 +- test/Sema/warn-main-return-type.c | 49 ++++++++++++++++++++++ 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 test/Sema/warn-main-return-type.c diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index cd00919587..95e40ecda1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -392,6 +392,7 @@ def err_main_template_decl : Error<"'main' cannot be a template">; def err_main_returns_nonint : Error<"'main' must return 'int'">; def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">, InGroup; +def note_main_change_return_type : Note<"change return type to 'int'">; def err_main_surplus_args : Error<"too many parameters (%0) for 'main': " "must be 0, 2, or 3">; def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b85e94bce8..5ddc26ab25 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6397,6 +6397,23 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, return Redeclaration; } +static SourceRange getResultSourceRange(const FunctionDecl *FD) { + const TypeSourceInfo *TSI = FD->getTypeSourceInfo(); + if (!TSI) + return SourceRange(); + + TypeLoc TL = TSI->getTypeLoc(); + FunctionTypeLoc *FunctionTL = dyn_cast(&TL); + if (!FunctionTL) + return SourceRange(); + + TypeLoc ResultTL = FunctionTL->getResultLoc(); + if (isa(ResultTL.getUnqualifiedLoc())) + return ResultTL.getSourceRange(); + + return SourceRange(); +} + void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { // C++11 [basic.start.main]p3: A program that declares main to be inline, // static or constexpr is ill-formed. @@ -6433,9 +6450,20 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { } else if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) { Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint); + SourceRange ResultRange = getResultSourceRange(FD); + if (ResultRange.isValid()) + Diag(ResultRange.getBegin(), diag::note_main_change_return_type) + << FixItHint::CreateReplacement(ResultRange, "int"); + // Otherwise, this is just a flat-out error. } else { - Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint); + SourceRange ResultRange = getResultSourceRange(FD); + if (ResultRange.isValid()) + Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint) + << FixItHint::CreateReplacement(ResultRange, "int"); + else + Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint); + FD->setInvalidDecl(true); } diff --git a/test/Sema/gnu89.c b/test/Sema/gnu89.c index 189e6b0097..1b7f10fee9 100644 --- a/test/Sema/gnu89.c +++ b/test/Sema/gnu89.c @@ -2,4 +2,4 @@ int f(int restrict); -void main() {} // expected-warning {{return type of 'main' is not 'int'}} +void main() {} // expected-warning {{return type of 'main' is not 'int'}} expected-note {{change return type to 'int'}} diff --git a/test/Sema/warn-main-return-type.c b/test/Sema/warn-main-return-type.c new file mode 100644 index 0000000000..bd7c59f2d3 --- /dev/null +++ b/test/Sema/warn-main-return-type.c @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s + +// expected-note@+1 5{{previous definition is here}} +int main() { + return 0; +} + +// expected-error@+3 {{conflicting types for 'main}} +// expected-warning@+2 {{return type of 'main' is not 'int'}} +// expected-note@+1 {{change return type to 'int'}} +void main() { +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:5}:"int" +} + +// expected-error@+3 {{conflicting types for 'main}} +// expected-warning@+2 {{return type of 'main' is not 'int'}} +// expected-note@+1 {{change return type to 'int'}} +double main() { +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:7}:"int" + return 0.0; +} + +// Currently we suggest to replace only 'float' here because we don't store +// enough source locations. +// +// expected-error@+3 {{conflicting types for 'main}} +// expected-warning@+2 {{return type of 'main' is not 'int'}} +// expected-note@+1 {{change return type to 'int'}} +const float main() { +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:12}:"int" + return 0.0f; +} + +typedef void *(*fptr)(int a); + +// expected-error@+2 {{conflicting types for 'main}} +// expected-warning@+1 {{return type of 'main' is not 'int'}} +fptr main() { + return (fptr) 0; +} + +// expected-error@+2 {{conflicting types for 'main}} +// expected-warning@+1 {{return type of 'main' is not 'int'}} +void *(*main())(int a) { + return (fptr) 0; +} + -- 2.50.1