Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -2019,6 +2019,10 @@ /// limited representation in the AST. SourceRange getReturnTypeSourceRange() const; + /// \brief Attempt to compute an informative source range covering the + /// function exception specification, if any. + SourceRange getExceptionSpecSourceRange() const; + /// \brief Determine the type of an expression that calls this function. QualType getCallResultType() const { assert(getType()->getAs() && "Expected a FunctionType!"); Index: include/clang/AST/TypeLoc.h =================================================================== --- include/clang/AST/TypeLoc.h +++ include/clang/AST/TypeLoc.h @@ -1248,6 +1248,7 @@ SourceLocation LocalRangeBegin; SourceLocation LParenLoc; SourceLocation RParenLoc; + SourceRange ExceptionSpecRange; SourceLocation LocalRangeEnd; }; @@ -1289,6 +1290,13 @@ return SourceRange(getLParenLoc(), getRParenLoc()); } + SourceRange getExceptionSpecRange() const { + return this->getLocalData()->ExceptionSpecRange; + } + void setExceptionSpecRange(SourceRange R) { + this->getLocalData()->ExceptionSpecRange = R; + } + ArrayRef getParams() const { return llvm::makeArrayRef(getParmArray(), getNumParams()); } @@ -1318,6 +1326,7 @@ setLocalRangeBegin(Loc); setLParenLoc(Loc); setRParenLoc(Loc); + setExceptionSpecRange(SourceRange(Loc)); setLocalRangeEnd(Loc); for (unsigned i = 0, e = getNumParams(); i != e; ++i) setParam(i, nullptr); Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2935,6 +2935,18 @@ return RTRange; } +SourceRange FunctionDecl::getExceptionSpecSourceRange() const { + const TypeSourceInfo *TSI = getTypeSourceInfo(); + if (!TSI) + return SourceRange(); + FunctionTypeLoc FTL = + TSI->getTypeLoc().IgnoreParens().getAs(); + if (!FTL) + return SourceRange(); + + return FTL.getExceptionSpecRange(); +} + const Attr *FunctionDecl::getUnusedResultAttr() const { QualType RetType = getReturnType(); if (RetType->isRecordType()) { Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -3400,7 +3400,8 @@ // If we already had a dynamic specification, parse the noexcept for, // recovery, but emit a diagnostic and don't store the results. - SourceRange NoexceptRange; + SourceRange NoexceptRange(Tok.getLocation(), + Tok.getEndLoc().getLocWithOffset(-1)); ExceptionSpecificationType NoexceptType = EST_None; SourceLocation KeywordLoc = ConsumeToken(); @@ -3423,7 +3424,6 @@ } else { // There is no argument. NoexceptType = EST_BasicNoexcept; - NoexceptRange = SourceRange(KeywordLoc, KeywordLoc); } if (Result == EST_None) { Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5065,7 +5065,7 @@ ParmVarDecl *Param = cast(FTI.Params[i].Param); TL.setParam(tpi++, Param); } - // FIXME: exception specs + TL.setExceptionSpecRange(FTI.getExceptionSpecRange()); } void VisitParenTypeLoc(ParenTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Paren); Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -4919,6 +4919,7 @@ NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setExceptionSpecRange(TL.getExceptionSpecRange()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); for (unsigned i = 0, e = NewTL.getNumParams(); i != e; ++i) NewTL.setParam(i, ParamDecls[i]); Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5812,6 +5812,8 @@ TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setExceptionSpecRange(SourceRange(ReadSourceLocation(Record, Idx), + ReadSourceLocation(Record, Idx))); TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) { TL.setParam(i, ReadDeclAs(Record, Idx)); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -572,6 +572,7 @@ Record.AddSourceLocation(TL.getLocalRangeBegin()); Record.AddSourceLocation(TL.getLParenLoc()); Record.AddSourceLocation(TL.getRParenLoc()); + Record.AddSourceRange(TL.getExceptionSpecRange()); Record.AddSourceLocation(TL.getLocalRangeEnd()); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) Record.AddDeclRef(TL.getParam(i)); Index: unittests/AST/SourceLocationTest.cpp =================================================================== --- unittests/AST/SourceLocationTest.cpp +++ unittests/AST/SourceLocationTest.cpp @@ -580,5 +580,72 @@ Language::Lang_CXX11)); } +class ExceptionSpecRangeVerifier : public RangeVerifier { +protected: + SourceRange getRange(const TypeLoc &Node) override { + auto T = + Node.getUnqualifiedLoc().castAs(); + assert(!T.isNull()); + return T.getExceptionSpecRange(); + } +}; + +class ParmVarExceptionSpecRangeVerifier : public RangeVerifier { +protected: + SourceRange getRange(const ParmVarDecl &Node) override { + if (const TypeSourceInfo *TSI = Node.getTypeSourceInfo()) { + TypeLoc TL = TSI->getTypeLoc(); + if (TL.getType()->isPointerType()) { + TL = TL.getNextTypeLoc().IgnoreParens(); + if (auto FPTL = TL.getAs()) { + return FPTL.getExceptionSpecRange(); + } + } + } + return SourceRange(); + } +}; + +TEST(FunctionDecl, ExceptionSpecifications) { + ExceptionSpecRangeVerifier Verifier; + + Verifier.expectRange(1, 10, 1, 16); + EXPECT_TRUE(Verifier.match("void f() throw();\n", loc(functionType()))); + + Verifier.expectRange(1, 10, 1, 34); + EXPECT_TRUE(Verifier.match("void f() throw(void(void) throw());\n", + loc(functionType()))); + + Verifier.expectRange(1, 10, 1, 19); + std::vector Args; + Args.push_back("-fms-extensions"); + EXPECT_TRUE(Verifier.match("void f() throw(...);\n", loc(functionType()), + Args, Language::Lang_CXX)); + + Verifier.expectRange(1, 10, 1, 17); + EXPECT_TRUE(Verifier.match("void f() noexcept;\n", loc(functionType()), + Language::Lang_CXX11)); + + Verifier.expectRange(1, 10, 1, 24); + EXPECT_TRUE(Verifier.match("void f() noexcept(false);\n", loc(functionType()), + Language::Lang_CXX11)); + + Verifier.expectRange(1, 10, 1, 32); + EXPECT_TRUE(Verifier.match("void f() noexcept(noexcept(1+1));\n", + loc(functionType()), Language::Lang_CXX11)); + + ParmVarExceptionSpecRangeVerifier Verifier2; + Verifier2.expectRange(1, 25, 1, 31); + EXPECT_TRUE(Verifier2.match("void g(void (*fp)(void) throw());\n", + parmVarDecl(hasType(pointerType(pointee( + parenType(innerType(functionType())))))))); + + Verifier2.expectRange(1, 25, 1, 38); + EXPECT_TRUE(Verifier2.match("void g(void (*fp)(void) noexcept(true));\n", + parmVarDecl(hasType(pointerType(pointee( + parenType(innerType(functionType())))))), + Language::Lang_CXX11)); +} + } // end namespace ast_matchers } // end namespace clang