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

llvm-svn: 246005
This commit is contained in:
Nathan Wilson 2015-08-26 04:19:36 +00:00
parent da9765b966
commit e23a9a4514
9 changed files with 54 additions and 17 deletions

View File

@ -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<

View File

@ -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,

View File

@ -5620,7 +5620,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
VolatileQualifierLoc,
RestrictQualifierLoc,
/*MutableLoc=*/SourceLocation(),
ESpecType, ESpecRange.getBegin(),
ESpecType, ESpecRange,
DynamicExceptions.data(),
DynamicExceptionRanges.data(),
DynamicExceptions.size(),

View File

@ -2768,7 +2768,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
/*RestrictQualifierLoc=*/NoLoc,
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
/*ESpecRange=*/SourceRange(),
/*Exceptions=*/nullptr,
/*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,

View File

@ -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,

View File

@ -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;

View File

@ -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<FunctionProtoType>()) {
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,

View File

@ -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.

View File

@ -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<typename T> concept bool C1() { return true; }
@ -6,6 +6,9 @@ namespace A {
template<typename T> concept bool C2 = true;
}
template<typename T> concept bool C3() { return (throw 0, true); }
static_assert(noexcept(C3<int>()), "function concept should be treated as if noexcept(true) specified");
template<typename T> 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<typename T>
concept bool D6; // expected-error {{variable concept declaration must be initialized}}
template<typename T>
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}}