From bf37536a351a2db55efe830437866010ae050eea Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 3 Jun 2019 18:36:33 +0000 Subject: [PATCH] Make NoThrow FunctionLike, make FunctionLike include references, fix 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 | 8 ++++++++ clang/include/clang/Basic/Attr.td | 2 +- clang/lib/AST/DeclBase.cpp | 2 ++ clang/lib/AST/TypePrinter.cpp | 2 ++ .../Misc/pragma-attribute-supported-attributes-list.test | 2 +- clang/test/SemaCXX/nothrow-vs-exception-specs.cpp | 14 ++++++++++++++ 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 66c3de7..3f71a7e 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} + inline bool Type::isMemberPointerType() const { return isa(CanonicalType); } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ad17900..c20a565 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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]; } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 511925d..3198548 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -957,6 +957,8 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { if (Ty->isFunctionPointerType()) Ty = Ty->getAs()->getPointeeType(); + else if (Ty->isFunctionReferenceType()) + Ty = Ty->getAs()->getPointeeType(); else if (BlocksToo && Ty->isBlockPointerType()) Ty = Ty->getAs()->getPointeeType(); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 13b105b..ca3e346 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -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 diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index f85c89a..6e07e8e 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -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) diff --git a/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp b/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp index 7a00783..a065dad 100644 --- a/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp +++ b/clang/test/SemaCXX/nothrow-vs-exception-specs.cpp @@ -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; +} -- 2.7.4