diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1363,6 +1363,10 @@ /// type specified. UnionParsedType TrailingReturnType; + /// If HasTrailingReturnType is true, this is the location of the trailing + /// return type. + unsigned TrailingReturnTypeLoc; + /// Reset the parameter list to having zero parameters. /// /// This is used in various places for error recovery. @@ -1499,6 +1503,11 @@ /// Get the trailing-return-type for this function declarator. ParsedType getTrailingReturnType() const { return TrailingReturnType; } + + /// Get the trailing-return-type location for this function declarator. + SourceLocation getTrailingReturnTypeLoc() const { + return SourceLocation::getFromRawEncoding(TrailingReturnTypeLoc); + } }; struct BlockPointerTypeInfo { @@ -1633,6 +1642,8 @@ Declarator &TheDeclarator, TypeResult TrailingReturnType = TypeResult(), + SourceLocation TrailingReturnTypeLoc = + SourceLocation(), DeclSpec *MethodQualifiers = nullptr); /// Return a DeclaratorChunk for a block. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -6429,6 +6429,7 @@ CachedTokens *ExceptionSpecTokens = nullptr; ParsedAttributesWithRange FnAttrs(AttrFactory); TypeResult TrailingReturnType; + SourceLocation TrailingReturnTypeLoc; /* LocalEndLoc is the end location for the local FunctionTypeLoc. EndLoc is the end location for the function declarator. @@ -6539,6 +6540,7 @@ SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range, D.mayBeFollowedByCXXDirectInit()); + TrailingReturnTypeLoc = Range.getBegin(); EndLoc = Range.getEnd(); } } else if (standardAttributesAllowed()) { @@ -6571,7 +6573,8 @@ DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, ExceptionSpecTokens, DeclsInPrototype, StartLoc, - LocalEndLoc, D, TrailingReturnType, &DS), + LocalEndLoc, D, TrailingReturnType, TrailingReturnTypeLoc, + &DS), std::move(FnAttrs), EndLoc); } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3898,6 +3898,7 @@ auto &FunctionChunk = D.getFunctionTypeInfo(); FunctionChunk.HasTrailingReturnType = TrailingReturnType.isUsable(); FunctionChunk.TrailingReturnType = TrailingReturnType.get(); + FunctionChunk.TrailingReturnTypeLoc = Range.getBegin().getRawEncoding(); } else SkipUntil({tok::equal, tok::l_brace, tok::arrow, tok::kw_try, tok::comma}, StopAtSemi | StopBeforeMatch); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1293,6 +1293,7 @@ } TypeResult TrailingReturnType; + SourceLocation TrailingReturnTypeLoc; if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | @@ -1379,6 +1380,7 @@ SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false); + TrailingReturnTypeLoc = Range.getBegin(); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } @@ -1395,7 +1397,7 @@ NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/ nullptr, /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, - TrailingReturnType, &DS), + TrailingReturnType, TrailingReturnTypeLoc, &DS), std::move(Attr), DeclEndLoc); // Parse requires-clause[opt]. diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -181,6 +181,8 @@ SourceLocation LocalRangeEnd, Declarator &TheDeclarator, TypeResult TrailingReturnType, + SourceLocation + TrailingReturnTypeLoc, DeclSpec *MethodQualifiers) { assert(!(MethodQualifiers && MethodQualifiers->getTypeQualifiers() & DeclSpec::TQ_atomic) && "function cannot have _Atomic qualifier"); @@ -210,6 +212,7 @@ I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); + I.Fun.TrailingReturnTypeLoc = TrailingReturnTypeLoc.getRawEncoding(); I.Fun.MethodQualifiers = nullptr; I.Fun.QualAttrFactory = nullptr; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3084,12 +3084,12 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, Declarator &D, unsigned FunctionChunkIndex) { - if (D.getTypeObject(FunctionChunkIndex).Fun.hasTrailingReturnType()) { - // FIXME: TypeSourceInfo doesn't preserve location information for - // qualifiers. + const DeclaratorChunk::FunctionTypeInfo &FTI = + D.getTypeObject(FunctionChunkIndex).Fun; + if (FTI.hasTrailingReturnType()) { S.diagnoseIgnoredQualifiers(diag::warn_qual_return_type, RetTy.getLocalCVRQualifiers(), - D.getIdentifierLoc()); + FTI.getTrailingReturnTypeLoc()); return; } diff --git a/clang/test/SemaCXX/return.cpp b/clang/test/SemaCXX/return.cpp --- a/clang/test/SemaCXX/return.cpp +++ b/clang/test/SemaCXX/return.cpp @@ -61,9 +61,12 @@ int atomic(); -auto - trailing_return_type() -> // expected-warning {{'const' type qualifier on return type has no effect}} - const int; +auto trailing_return_type() -> + const int; // expected-warning {{'const' type qualifier on return type has no effect}} + +auto trailing_return_type_lambda = [](const int &x) -> + const int // expected-warning {{'const' type qualifier on return type has no effect}} + { return x; }; const int ret_array()[4]; // expected-error {{cannot return array}} }