diff options
author | Dmitri Gribenko <gribozavr@gmail.com> | 2013-01-17 00:26:13 +0000 |
---|---|---|
committer | Dmitri Gribenko <gribozavr@gmail.com> | 2013-01-17 00:26:13 +0000 |
commit | a6f97071338e525d18e607ca286e338639dd2a5e (patch) | |
tree | 9109d53f1a48f09636d738e49ef63e5aab348c15 | |
parent | 90a2d39d3082518566d5a22409a7bbba0d42f054 (diff) |
Implement a fixit for -Wmain-return-type
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172684 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 30 | ||||
-rw-r--r-- | test/Sema/gnu89.c | 2 | ||||
-rw-r--r-- | test/Sema/warn-main-return-type.c | 49 |
4 files changed, 80 insertions, 2 deletions
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<MainReturnType>; +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<FunctionTypeLoc>(&TL); + if (!FunctionTL) + return SourceRange(); + + TypeLoc ResultTL = FunctionTL->getResultLoc(); + if (isa<BuiltinTypeLoc>(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; +} + |