Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -2061,6 +2061,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 @@ -1351,6 +1351,19 @@ FunctionTypeLoc, FunctionType, FunctionLocInfo> { + bool hasExceptionSpec() const { + if (auto *FPT = dyn_cast(getTypePtr())) { + return FPT->hasExceptionSpec(); + } + return false; + } + + SourceRange *getExceptionSpecRangePtr() const { + assert(hasExceptionSpec() && "No exception spec range"); + // After the Info comes the ParmVarDecl array, and after that comes the + // exception specification information. + return (SourceRange *)(getParmArray() + getNumParams()); + } public: SourceLocation getLocalRangeBegin() const { return getLocalData()->LocalRangeBegin; @@ -1384,6 +1397,16 @@ return SourceRange(getLParenLoc(), getRParenLoc()); } + SourceRange getExceptionSpecRange() const { + if (hasExceptionSpec()) + return *getExceptionSpecRangePtr(); + return SourceRange(); + } + void setExceptionSpecRange(SourceRange R) { + if (hasExceptionSpec()) + *getExceptionSpecRangePtr() = R; + } + ArrayRef getParams() const { return llvm::makeArrayRef(getParmArray(), getNumParams()); } @@ -1416,12 +1439,15 @@ setLocalRangeEnd(Loc); for (unsigned i = 0, e = getNumParams(); i != e; ++i) setParam(i, nullptr); + if (hasExceptionSpec()) + setExceptionSpecRange(Loc); } /// \brief Returns the size of the type source info data block that is /// specific to this type. unsigned getExtraLocalDataSize() const { - return getNumParams() * sizeof(ParmVarDecl *); + unsigned ExceptSpecSize = hasExceptionSpec() ? sizeof(SourceRange) : 0; + return (getNumParams() * sizeof(ParmVarDecl *)) + ExceptSpecSize; } unsigned getExtraLocalDataAlignment() const { return alignof(ParmVarDecl *); } Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2990,6 +2990,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 @@ -3545,7 +3545,7 @@ Actions.CheckBooleanCondition(KeywordLoc, NoexceptExpr.get()); NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); } else { - NoexceptType = EST_None; + NoexceptType = EST_BasicNoexcept; } } else { // There is no argument. Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5263,7 +5263,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 @@ -5023,6 +5023,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 @@ -5990,6 +5990,8 @@ TL.setLocalRangeBegin(ReadSourceLocation()); TL.setLParenLoc(ReadSourceLocation()); TL.setRParenLoc(ReadSourceLocation()); + TL.setExceptionSpecRange(SourceRange(Reader->ReadSourceLocation(*F, Record, Idx), + Reader->ReadSourceLocation(*F, Record, Idx))); TL.setLocalRangeEnd(ReadSourceLocation()); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) { TL.setParam(i, Reader->ReadDeclAs(*F, Record, Idx)); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -629,6 +629,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 @@ -670,5 +670,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, 10); + 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