Make NoThrow FunctionLike, make FunctionLike include references, fix
authorErich Keane <erich.keane@intel.com>
Mon, 3 Jun 2019 18:36:33 +0000 (18:36 +0000)
committerErich Keane <erich.keane@intel.com>
Mon, 3 Jun 2019 18:36:33 +0000 (18:36 +0000)
prettyprint

__declspec(nothrow) should work on function pointers as well as function
references, so this changes it to FunctionLike.  Additionally,
FunctionLike needed to be modified to permit function references.

Finally, the TypePrinter didn't properly print the NoThrow exception
specifier, so make sure we get that right as well.

llvm-svn: 362435

clang/include/clang/AST/Type.h
clang/include/clang/Basic/Attr.td
clang/lib/AST/DeclBase.cpp
clang/lib/AST/TypePrinter.cpp
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/SemaCXX/nothrow-vs-exception-specs.cpp

index 66c3de72f5f48b9f2c693f07f62d54e762cfab54..3f71a7ec6ffe980d741dd87b2553e74591aaedd3 100644 (file)
@@ -1962,6 +1962,7 @@ public:
   bool isLValueReferenceType() const;
   bool isRValueReferenceType() const;
   bool isFunctionPointerType() const;
+  bool isFunctionReferenceType() const;
   bool isMemberPointerType() const;
   bool isMemberFunctionPointerType() const;
   bool isMemberDataPointerType() const;
@@ -6374,6 +6375,13 @@ inline bool Type::isFunctionPointerType() const {
     return false;
 }
 
+inline bool Type::isFunctionReferenceType() const {
+  if (const auto *T = getAs<ReferenceType>())
+    return T->getPointeeType()->isFunctionType();
+  else
+    return false;
+}
+
 inline bool Type::isMemberPointerType() const {
   return isa<MemberPointerType>(CanonicalType);
 }
index ad179009ea6a291ffe729245f627fa72cebb1983..c20a56532d5d7b7b969288bdf115e81e3b5b8879 100644 (file)
@@ -1657,7 +1657,7 @@ def NoStackProtector : InheritableAttr {
 
 def NoThrow : InheritableAttr {
   let Spellings = [GCC<"nothrow">, Declspec<"nothrow">];
-  let Subjects = SubjectList<[Function]>;
+  let Subjects = SubjectList<[FunctionLike]>;
   let Documentation = [NoThrowDocs];
 }
 
index 511925d1b140e8e92a9f4d15db1e6b95e2dcb34e..31985486d1d935abe15d97f4313bf12f5804bae3 100644 (file)
@@ -957,6 +957,8 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
 
   if (Ty->isFunctionPointerType())
     Ty = Ty->getAs<PointerType>()->getPointeeType();
+  else if (Ty->isFunctionReferenceType())
+    Ty = Ty->getAs<ReferenceType>()->getPointeeType();
   else if (BlocksToo && Ty->isBlockPointerType())
     Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
 
index 13b105bc5729fda0b409f2c4e06f35368037443c..ca3e34666841b680d16d9813274fcb4337fd2d06 100644 (file)
@@ -734,6 +734,8 @@ FunctionProtoType::printExceptionSpecification(raw_ostream &OS,
         OS << getExceptionType(I).stream(Policy);
       }
     OS << ')';
+  } else if (EST_NoThrow == getExceptionSpecType()) {
+    OS << " __attribute__((nothrow))";
   } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
     OS << " noexcept";
     // FIXME:Is it useful to print out the expression for a non-dependent
index f85c89ae015dcb1b260918dcbf181821bc98c879..6e07e8e811129570478db2cb2d43744843dbe2e0 100644 (file)
@@ -86,7 +86,7 @@
 // CHECK-NEXT: NoSplitStack (SubjectMatchRule_function)
 // CHECK-NEXT: NoStackProtector (SubjectMatchRule_function)
 // CHECK-NEXT: NoThreadSafetyAnalysis (SubjectMatchRule_function)
-// CHECK-NEXT: NoThrow (SubjectMatchRule_function)
+// CHECK-NEXT: NoThrow (SubjectMatchRule_hasType_functionType)
 // CHECK-NEXT: NotTailCalled (SubjectMatchRule_function)
 // CHECK-NEXT: OSConsumed (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: OSReturnsNotRetained (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_variable_is_parameter)
index 7a00783b0b78165c35b356b764e0de81cdf8331b..a065dad77246133c84ca70f2907a2a39ee723c72 100644 (file)
@@ -88,3 +88,17 @@ public:
   void foo() {}
 };
 }
+
+namespace FuncPointerReferenceConverts
+void FuncToBeRefed();
+
+#ifndef CPP17
+// expected-error@+6{{target exception specification is not superset of source}}
+// expected-error@+6{{target exception specification is not superset of source}}
+#else
+// expected-error@+3{{non-const lvalue reference to type 'void () __attribute__((nothrow))' cannot bind to a value of unrelated type 'void ()'}}
+// expected-error@+3{{cannot initialize a variable of type 'void (*)() __attribute__((nothrow))' with an lvalue of type 'void ()': different exception specifications}}
+#endif
+__declspec(nothrow) void (&FuncRef)() = FuncToBeRefed;
+__declspec(nothrow) void (*FuncPtr)() = FuncToBeRefed;
+}