r291771 - Tracking exception specification source locations

Malcolm Parsons via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 12 08:11:28 PST 2017


Author: malcolm.parsons
Date: Thu Jan 12 10:11:28 2017
New Revision: 291771

URL: http://llvm.org/viewvc/llvm-project?rev=291771&view=rev
Log:
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

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

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Jan 12 10:11:28 2017
@@ -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!");

Modified: cfe/trunk/include/clang/AST/TypeLoc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TypeLoc.h (original)
+++ cfe/trunk/include/clang/AST/TypeLoc.h Thu Jan 12 10:11:28 2017
@@ -1351,6 +1351,19 @@ class FunctionTypeLoc : public ConcreteT
                                                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 *); }

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Jan 12 10:11:28 2017
@@ -2990,6 +2990,18 @@ SourceRange FunctionDecl::getReturnTypeS
   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()) {

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Jan 12 10:11:28 2017
@@ -3544,7 +3544,7 @@ Parser::tryParseExceptionSpecification(b
           Actions.CheckBooleanCondition(KeywordLoc, NoexceptExpr.get());
       NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
     } else {
-      NoexceptType = EST_None;
+      NoexceptType = EST_BasicNoexcept;
     }
   } else {
     // There is no argument.

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu Jan 12 10:11:28 2017
@@ -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);

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Jan 12 10:11:28 2017
@@ -5023,6 +5023,7 @@ QualType TreeTransform<Derived>::Transfo
   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]);

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jan 12 10:11:28 2017
@@ -5990,6 +5990,8 @@ void TypeLocReader::VisitFunctionTypeLoc
   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));

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Jan 12 10:11:28 2017
@@ -629,6 +629,7 @@ void TypeLocWriter::VisitFunctionTypeLoc
   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));

Modified: cfe/trunk/unittests/AST/SourceLocationTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/SourceLocationTest.cpp?rev=291771&r1=291770&r2=291771&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/SourceLocationTest.cpp (original)
+++ cfe/trunk/unittests/AST/SourceLocationTest.cpp Thu Jan 12 10:11:28 2017
@@ -670,5 +670,72 @@ TEST(CXXMethodDecl, CXXMethodDeclWithNoE
       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




More information about the cfe-commits mailing list