diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ba7645e4b7c9b7ea866b4a36b3b0c21dc8500fd0..0f04c08742f9a79454cc84973556211091c8188d 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1896,6 +1896,8 @@ public: return getType()->getAs<FunctionType>()->getReturnType(); } + SourceRange getReturnTypeSourceRange() const; + /// \brief Determine the type of an expression that calls this function. QualType getCallResultType() const { return getType()->getAs<FunctionType>()->getCallResultType(getASTContext()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d910a669abf2973be2552043627496cdbe48c99c..702a2e32e3ea311671886f55d2ae3bdc4fad9813 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2687,6 +2687,23 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { return FoundBody; } +SourceRange FunctionDecl::getReturnTypeSourceRange() const { + const TypeSourceInfo *TSI = getTypeSourceInfo(); + if (!TSI) + return SourceRange(); + + TypeLoc TL = TSI->getTypeLoc(); + FunctionTypeLoc FunctionTL = TL.getAs<FunctionTypeLoc>(); + if (!FunctionTL) + return SourceRange(); + + TypeLoc ResultTL = FunctionTL.getReturnLoc(); + if (ResultTL.getUnqualifiedLoc().getAs<BuiltinTypeLoc>()) + return ResultTL.getSourceRange(); + + return SourceRange(); +} + /// \brief For an inline function definition in C, or for a gnu_inline function /// in C++, determine whether the definition will be externally visible. /// diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ef2035c29078ad8a7c63f18ac1f2b9afb4d2c7b1..849926327d0814e937feea7307e87e0e20a139d5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2519,11 +2519,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { if (New->isCXXClassMember() && New->isOutOfLine()) - Diag(New->getLocation(), - diag::err_member_def_does_not_match_ret_type) << New; + Diag(New->getLocation(), diag::err_member_def_does_not_match_ret_type) + << New << New->getReturnTypeSourceRange(); else - Diag(New->getLocation(), diag::err_ovl_diff_return_type); - Diag(OldLocation, PrevDiag) << Old << Old->getType(); + Diag(New->getLocation(), diag::err_ovl_diff_return_type) + << New->getReturnTypeSourceRange(); + Diag(OldLocation, PrevDiag) << Old << Old->getType() + << Old->getReturnTypeSourceRange(); return true; } else @@ -7494,8 +7496,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // OpenCL v1.2, s6.9 -- Kernels can only have return type void. if (!NewFD->getReturnType()->isVoidType()) { - Diag(D.getIdentifierLoc(), - diag::err_expected_kernel_void_return_type); + SourceRange RTRange = NewFD->getReturnTypeSourceRange(); + Diag(D.getIdentifierLoc(), diag::err_expected_kernel_void_return_type) + << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void") + : FixItHint()); D.setInvalidType(); } @@ -7835,23 +7839,6 @@ 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 = TL.getAs<FunctionTypeLoc>(); - if (!FunctionTL) - return SourceRange(); - - TypeLoc ResultTL = FunctionTL.getReturnLoc(); - if (ResultTL.getUnqualifiedLoc().getAs<BuiltinTypeLoc>()) - 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 @@ -7904,19 +7891,17 @@ 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"); + SourceRange RTRange = FD->getReturnTypeSourceRange(); + if (RTRange.isValid()) + Diag(RTRange.getBegin(), diag::note_main_change_return_type) + << FixItHint::CreateReplacement(RTRange, "int"); // Otherwise, this is just a flat-out error. } else { - 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); + SourceRange RTRange = FD->getReturnTypeSourceRange(); + Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint) + << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "int") + : FixItHint()); FD->setInvalidDecl(true); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 03600d02f84bf56a202d39a510c6ee946ed8673f..621ba1daa180a7bd7b73fbbfdcc65e8aad8b7d5e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12304,8 +12304,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, if (NewClassTy.isNull()) { Diag(New->getLocation(), diag::err_different_return_type_for_overriding_virtual_function) - << New->getDeclName() << NewTy << OldTy; - Diag(Old->getLocation(), diag::note_overridden_virtual_function); + << New->getDeclName() << NewTy << OldTy + << New->getReturnTypeSourceRange(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); return true; } @@ -12325,25 +12327,27 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) { // Check if the new class derives from the old class. if (!IsDerivedFrom(NewClassTy, OldClassTy)) { - Diag(New->getLocation(), - diag::err_covariant_return_not_derived) - << New->getDeclName() << NewTy << OldTy; - Diag(Old->getLocation(), diag::note_overridden_virtual_function); + Diag(New->getLocation(), diag::err_covariant_return_not_derived) + << New->getDeclName() << NewTy << OldTy + << New->getReturnTypeSourceRange(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); return true; } // Check if we the conversion from derived to base is valid. - if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, - diag::err_covariant_return_inaccessible_base, - diag::err_covariant_return_ambiguous_derived_to_base_conv, - // FIXME: Should this point to the return type? - New->getLocation(), SourceRange(), New->getDeclName(), - nullptr)) { + if (CheckDerivedToBaseConversion( + NewClassTy, OldClassTy, + diag::err_covariant_return_inaccessible_base, + diag::err_covariant_return_ambiguous_derived_to_base_conv, + New->getLocation(), New->getReturnTypeSourceRange(), + New->getDeclName(), nullptr)) { // FIXME: this note won't trigger for delayed access control // diagnostics, and it's impossible to get an undelayed error // here from access control during the original parse because // the ParsingDeclSpec/ParsingDeclarator are still in scope. - Diag(Old->getLocation(), diag::note_overridden_virtual_function); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); return true; } } @@ -12352,8 +12356,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) { Diag(New->getLocation(), diag::err_covariant_return_type_different_qualifications) - << New->getDeclName() << NewTy << OldTy; - Diag(Old->getLocation(), diag::note_overridden_virtual_function); + << New->getDeclName() << NewTy << OldTy + << New->getReturnTypeSourceRange(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); return true; }; @@ -12362,8 +12368,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, if (NewClassTy.isMoreQualifiedThan(OldClassTy)) { Diag(New->getLocation(), diag::err_covariant_return_type_class_type_more_qualified) - << New->getDeclName() << NewTy << OldTy; - Diag(Old->getLocation(), diag::note_overridden_virtual_function); + << New->getDeclName() << NewTy << OldTy + << New->getReturnTypeSourceRange(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); return true; };