From: Nathan Wilson Date: Wed, 26 Aug 2015 04:19:36 +0000 (+0000) Subject: Modify DeclaratorChuck::getFunction to be passed an Exception Specification SourceRange X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c56d3e3191c74cd0feff9d3996d50c2e9ee123e4;p=clang Modify DeclaratorChuck::getFunction to be passed an Exception Specification SourceRange Summary: - Store the exception specification range's begin and end SourceLocation in DeclaratorChuck::FunctionTypeInfo. These SourceLocations can be used in a FixItHint Range. - Add diagnostic; function concept having an exception specification. Reviewers: hubert.reinterpretcast, fraggamuffin, faisalv, aaron.ballman, rsmith Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D11789 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@246005 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 819324609a..7b21e1068c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1977,6 +1977,8 @@ def err_function_concept_not_defined : Error< "function concept declaration must be a definition">; def err_var_concept_not_initialized : Error< "variable concept declaration must be initialized">; +def err_function_concept_exception_spec : Error< + "function concept cannot have exception specification">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 41d4900632..980ac55140 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1255,8 +1255,11 @@ struct DeclaratorChunk { /// any. unsigned MutableLoc; - /// \brief The location of the keyword introducing the spec, if any. - unsigned ExceptionSpecLoc; + /// \brief The beginning location of the exception specification, if any. + unsigned ExceptionSpecLocBeg; + + /// \brief The end location of the exception specification, if any. + unsigned ExceptionSpecLocEnd; /// Params - This is a pointer to a new[]'d array of ParamInfo objects that /// describe the parameters specified by this function declarator. null if @@ -1323,8 +1326,16 @@ struct DeclaratorChunk { return SourceLocation::getFromRawEncoding(RParenLoc); } - SourceLocation getExceptionSpecLoc() const { - return SourceLocation::getFromRawEncoding(ExceptionSpecLoc); + SourceLocation getExceptionSpecLocBeg() const { + return SourceLocation::getFromRawEncoding(ExceptionSpecLocBeg); + } + + SourceLocation getExceptionSpecLocEnd() const { + return SourceLocation::getFromRawEncoding(ExceptionSpecLocEnd); + } + + SourceRange getExceptionSpecRange() const { + return SourceRange(getExceptionSpecLocBeg(), getExceptionSpecLocEnd()); } /// \brief Retrieve the location of the ref-qualifier, if any. @@ -1496,7 +1507,7 @@ struct DeclaratorChunk { SourceLocation RestrictQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, - SourceLocation ESpecLoc, + SourceRange ESpecRange, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index debbd50d66..80d25426f6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5620,7 +5620,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, VolatileQualifierLoc, RestrictQualifierLoc, /*MutableLoc=*/SourceLocation(), - ESpecType, ESpecRange.getBegin(), + ESpecType, ESpecRange, DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index ed8073a80c..52690470f2 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2768,7 +2768,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index c1dafe9b49..87f3809130 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1149,7 +1149,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, MutableLoc, - ESpecType, ESpecRange.getBegin(), + ESpecType, ESpecRange, DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), @@ -1217,7 +1217,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*RestrictQualifierLoc=*/NoLoc, MutableLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 4adbb2b6af..357f2d3a03 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -177,7 +177,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, - SourceLocation ESpecLoc, + SourceRange ESpecRange, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, @@ -212,7 +212,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Fun.RestrictQualifierLoc = RestrictQualifierLoc.getRawEncoding(); I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; - I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); + I.Fun.ExceptionSpecLocBeg = ESpecRange.getBegin().getRawEncoding(); + I.Fun.ExceptionSpecLocEnd = ESpecRange.getEnd().getRawEncoding(); I.Fun.NumExceptions = 0; I.Fun.Exceptions = nullptr; I.Fun.NoexceptExpr = nullptr; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 63093b9fdd..a91980c9f5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7476,6 +7476,22 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } + // C++ Concepts TS [dcl.spec.concept]p1: [...] A function concept shall + // have no exception-specification and is treated as if it were specified + // with noexcept(true) (15.4). [...] + if (const FunctionProtoType *FPT = R->getAs()) { + if (FPT->hasExceptionSpec()) { + SourceRange Range; + if (D.isFunctionDeclarator()) + Range = D.getFunctionTypeInfo().getExceptionSpecRange(); + Diag(NewFD->getLocation(), diag::err_function_concept_exception_spec) + << FixItHint::CreateRemoval(Range); + NewFD->setInvalidDecl(); + } else { + Context.adjustExceptionSpec(NewFD, EST_BasicNoexcept); + } + } + // C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is // implicity defined to be a constexpr declaration (implicitly inline) NewFD->setImplicitlyInline(); @@ -11123,7 +11139,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index aa6a45bafb..6b7a49dc33 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -700,7 +700,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, @@ -3833,9 +3833,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Exception specs are not allowed in typedefs. Complain, but add it // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) - S.Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) - << (D.getContext() == Declarator::AliasDeclContext || - D.getContext() == Declarator::AliasTemplateContext); + S.Diag(FTI.getExceptionSpecLocBeg(), + diag::err_exception_spec_in_typedef) + << (D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext); // If we see "T var();" or "T var(T());" at block scope, it is probably // an attempt to initialize a variable, not a function declaration. diff --git a/test/SemaCXX/cxx-concept-declaration.cpp b/test/SemaCXX/cxx-concept-declaration.cpp index ccdf55e52e..e51a441795 100644 --- a/test/SemaCXX/cxx-concept-declaration.cpp +++ b/test/SemaCXX/cxx-concept-declaration.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s +// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -fcxx-exceptions -x c++ -verify %s namespace A { template concept bool C1() { return true; } @@ -6,6 +6,9 @@ namespace A { template concept bool C2 = true; } +template concept bool C3() { return (throw 0, true); } +static_assert(noexcept(C3()), "function concept should be treated as if noexcept(true) specified"); + template concept bool D1(); // expected-error {{function concept declaration must be a definition}} struct B { @@ -23,6 +26,9 @@ concept bool D5 = true; // expected-error {{'concept' can only appear on the def template concept bool D6; // expected-error {{variable concept declaration must be initialized}} +template +concept bool D7() throw(int) { return true; } // expected-error {{function concept cannot have exception specification}} + // Tag concept class CC1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}} concept struct CS1 {}; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}