]> granicus.if.org Git - clang/commitdiff
Tracking exception specification source locations
authorMalcolm Parsons <malcolm.parsons@gmail.com>
Thu, 12 Jan 2017 16:11:28 +0000 (16:11 +0000)
committerMalcolm Parsons <malcolm.parsons@gmail.com>
Thu, 12 Jan 2017 16:11:28 +0000 (16:11 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291771 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/AST/TypeLoc.h
lib/AST/Decl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
unittests/AST/SourceLocationTest.cpp

index b2e332d6d85cbe4b6687cd9cbf933409e24cdc56..8b52891af2f8bff6d53c85d2762c02885acd9685 100644 (file)
@@ -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!");
index 7de666838d444a66955536c217a8ed7d9c8c4b8e..5b7d9e6e3ce1037afd2e2a77bd6e98b062aa9f3d 100644 (file)
@@ -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 *); }
index c3fa1c87affd1b14bbb7d2a16714803d32c274ac..81f08787d515d18d09156882eb84735f697bb801 100644 (file)
@@ -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()) {
index 1fdf14c0e9c5be300b1a45a9e7f0866f2a0d9a7f..3f1fe7e06fe339c775fb31bd61fea19664845782 100644 (file)
@@ -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.
index ae9a3ee790e1a7f510e5cfbc7e903e031970274f..29b21426790edc72d293d83677daa15f0b1abe31 100644 (file)
@@ -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);
index 786b5c54ecd3a770429730d16644a7e60c3ee9fd..c2aa3fef67c8c7ff62f604ee888280c6c36d2f87 100644 (file)
@@ -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]);
index 7f890051e641e73d0233eb68ba5b7f5d5f1438d0..53224e2b493d4bb0e180e50573529c4faaaea79a 100644 (file)
@@ -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));
index 39e842db2baaee7c9cb3ae0d65d5284b81829d59..886523ea943198756248cbccca6bb43350e36d0f 100644 (file)
@@ -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));
index add85c3660244fce21ac078d5b2e7d6550bbb483..5f69c54043614ad2e6c3c1541bbc9897a08f8b7a 100644 (file)
@@ -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