Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1977,6 +1977,8 @@ "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< Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -1255,8 +1255,11 @@ /// 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 @@ 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 @@ SourceLocation RestrictQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, - SourceLocation ESpecLoc, + SourceRange ESpecRange, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -5620,7 +5620,7 @@ VolatileQualifierLoc, RestrictQualifierLoc, /*MutableLoc=*/SourceLocation(), - ESpecType, ESpecRange.getBegin(), + ESpecType, ESpecRange, DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -2747,7 +2747,7 @@ /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1149,7 +1149,7 @@ /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, MutableLoc, - ESpecType, ESpecRange.getBegin(), + ESpecType, ESpecRange, DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), @@ -1217,7 +1217,7 @@ /*RestrictQualifierLoc=*/NoLoc, MutableLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -177,7 +177,7 @@ SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, - SourceLocation ESpecLoc, + SourceRange ESpecRange, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, @@ -212,7 +212,8 @@ 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; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -7466,6 +7466,22 @@ 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(); @@ -11099,7 +11115,7 @@ /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -700,7 +700,7 @@ /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, - /*ESpecLoc=*/NoLoc, + /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, @@ -3833,9 +3833,10 @@ // 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. Index: test/SemaCXX/cxx-concept-declaration.cpp =================================================================== --- test/SemaCXX/cxx-concept-declaration.cpp +++ 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 @@ 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 @@ 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}}