summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMalcolm Parsons <malcolm.parsons@gmail.com>2017-01-12 16:11:28 +0000
committerMalcolm Parsons <malcolm.parsons@gmail.com>2017-01-12 16:11:28 +0000
commita3220ce6a3d0b651accc7fe46374ab98232ceb95 (patch)
tree66ca3c8586d1fe26545f449b29fd686a091a4178
parentb7391dd3b434ae17e92be724bb043f74617b93e2 (diff)
downloadbcm5719-llvm-a3220ce6a3d0b651accc7fe46374ab98232ceb95.tar.gz
bcm5719-llvm-a3220ce6a3d0b651accc7fe46374ab98232ceb95.zip
Tracking exception specification source locations
Summary: We do not currently track the source locations for exception specifications such that their source range can be queried through the AST. This leads to trying to write more complex code to determine the source range for uses like FixItHints (see D18575 for an example). In addition to use within tools like clang-tidy, I think this information may become more important to track as exception specifications become more integrated into the type system. Patch by Don Hinton. Reviewers: rsmith Subscribers: malcolm.parsons, sbarzowski, alexfh, hintonda, cfe-commits Differential Revision: https://reviews.llvm.org/D20428 llvm-svn: 291771
-rw-r--r--clang/include/clang/AST/Decl.h4
-rw-r--r--clang/include/clang/AST/TypeLoc.h28
-rw-r--r--clang/lib/AST/Decl.cpp12
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp2
-rw-r--r--clang/lib/Sema/SemaType.cpp2
-rw-r--r--clang/lib/Sema/TreeTransform.h1
-rw-r--r--clang/lib/Serialization/ASTReader.cpp2
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp1
-rw-r--r--clang/unittests/AST/SourceLocationTest.cpp67
9 files changed, 116 insertions, 3 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index b2e332d6d85..8b52891af2f 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2061,6 +2061,10 @@ public:
/// 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!");
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 7de666838d4..5b7d9e6e3ce 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -1351,6 +1351,19 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
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;
@@ -1384,6 +1397,16 @@ public:
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());
}
@@ -1416,12 +1439,15 @@ public:
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 *); }
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index c3fa1c87aff..81f08787d51 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2990,6 +2990,18 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const {
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()) {
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 1fdf14c0e9c..3f1fe7e06fe 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3544,7 +3544,7 @@ Parser::tryParseExceptionSpecification(bool Delayed,
Actions.CheckBooleanCondition(KeywordLoc, NoexceptExpr.get());
NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
} else {
- NoexceptType = EST_None;
+ NoexceptType = EST_BasicNoexcept;
}
} else {
// There is no argument.
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index ae9a3ee790e..29b21426790 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -5263,7 +5263,7 @@ namespace {
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);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 786b5c54ecd..c2aa3fef67c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5023,6 +5023,7 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
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]);
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 7f890051e64..53224e2b493 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -5990,6 +5990,8 @@ void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
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));
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 39e842db2ba..886523ea943 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -629,6 +629,7 @@ void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
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));
diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp
index add85c36602..5f69c540436 100644
--- a/clang/unittests/AST/SourceLocationTest.cpp
+++ b/clang/unittests/AST/SourceLocationTest.cpp
@@ -670,5 +670,72 @@ TEST(CXXMethodDecl, CXXMethodDeclWithNoExceptSpecification) {
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
OpenPOWER on IntegriCloud