/// 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<FunctionType>() && "Expected a FunctionType!");
FunctionTypeLoc,
FunctionType,
FunctionLocInfo> {
+ bool hasExceptionSpec() const {
+ if (auto *FPT = dyn_cast<FunctionProtoType>(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;
return SourceRange(getLParenLoc(), getRParenLoc());
}
+ SourceRange getExceptionSpecRange() const {
+ if (hasExceptionSpec())
+ return *getExceptionSpecRangePtr();
+ return SourceRange();
+ }
+ void setExceptionSpecRange(SourceRange R) {
+ if (hasExceptionSpec())
+ *getExceptionSpecRangePtr() = R;
+ }
+
ArrayRef<ParmVarDecl *> getParams() const {
return llvm::makeArrayRef(getParmArray(), getNumParams());
}
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 *); }
return RTRange;
}
+SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
+ const TypeSourceInfo *TSI = getTypeSourceInfo();
+ if (!TSI)
+ return SourceRange();
+ FunctionTypeLoc FTL =
+ TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
+ if (!FTL)
+ return SourceRange();
+
+ return FTL.getExceptionSpecRange();
+}
+
const Attr *FunctionDecl::getUnusedResultAttr() const {
QualType RetType = getReturnType();
if (RetType->isRecordType()) {
Actions.CheckBooleanCondition(KeywordLoc, NoexceptExpr.get());
NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
} else {
- NoexceptType = EST_None;
+ NoexceptType = EST_BasicNoexcept;
}
} else {
// There is no argument.
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
TL.setParam(tpi++, Param);
}
- // FIXME: exception specs
+ TL.setExceptionSpecRange(FTI.getExceptionSpecRange());
}
void VisitParenTypeLoc(ParenTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Paren);
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]);
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<ParmVarDecl>(*F, Record, Idx));
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));
Language::Lang_CXX11));
}
+class ExceptionSpecRangeVerifier : public RangeVerifier<TypeLoc> {
+protected:
+ SourceRange getRange(const TypeLoc &Node) override {
+ auto T =
+ Node.getUnqualifiedLoc().castAs<FunctionProtoTypeLoc>();
+ assert(!T.isNull());
+ return T.getExceptionSpecRange();
+ }
+};
+
+class ParmVarExceptionSpecRangeVerifier : public RangeVerifier<ParmVarDecl> {
+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<FunctionProtoTypeLoc>()) {
+ 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<std::string> 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