diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2174,21 +2174,19 @@ FuncAttrs.addAttribute(llvm::Attribute::NoMerge); } - // 'const', 'pure' and 'noalias' attributed functions are also nounwind. + // 'const', 'pure' and 'noalias' attributed functions are also nounwind, + // but that is manifested in AST, so we don't need to deal with that here. if (TargetDecl->hasAttr()) { FuncAttrs.addMemoryAttr(llvm::MemoryEffects::none()); - FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); // gcc specifies that 'const' functions have greater restrictions than // 'pure' functions, so they also cannot have infinite loops. FuncAttrs.addAttribute(llvm::Attribute::WillReturn); } else if (TargetDecl->hasAttr()) { FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly()); - FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); // gcc specifies that 'pure' functions cannot have infinite loops. FuncAttrs.addAttribute(llvm::Attribute::WillReturn); } else if (TargetDecl->hasAttr()) { FuncAttrs.addMemoryAttr(llvm::MemoryEffects::argMemOnly()); - FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } if (TargetDecl->hasAttr()) RetAttrs.addAttribute(llvm::Attribute::NoAlias); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -8790,6 +8790,27 @@ if (!AL.isUsedAsTypeAttr()) handleSimpleAttribute(S, D, AL); break; + case ParsedAttr::AT_Pure: + handleSimpleAttribute(S, D, AL); + if (!D->hasAttr()) { + handleSimpleAttribute(S, D, AL); + D->getAttr()->setImplicit(true); + } + break; + case ParsedAttr::AT_Const: + handleSimpleAttribute(S, D, AL); + if (!D->hasAttr()) { + handleSimpleAttribute(S, D, AL); + D->getAttr()->setImplicit(true); + } + break; + case ParsedAttr::AT_NoAlias: + handleSimpleAttribute(S, D, AL); + if (!D->hasAttr()) { + handleSimpleAttribute(S, D, AL); + D->getAttr()->setImplicit(true); + } + break; case ParsedAttr::AT_CUDAShared: handleSharedAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -7771,7 +7771,10 @@ return true; } - if (attr.getKind() == ParsedAttr::AT_NoThrow) { + if (attr.getKind() == ParsedAttr::AT_NoThrow || + attr.getKind() == ParsedAttr::AT_Pure || + attr.getKind() == ParsedAttr::AT_Const || + attr.getKind() == ParsedAttr::AT_NoAlias) { // Delay if this is not a function type. if (!unwrapped.isFunctionType()) return false; @@ -8522,8 +8525,11 @@ break; case ParsedAttr::AT_NoThrow: - // Exception Specifications aren't generally supported in C mode throughout - // clang, so revert to attribute-based handling for C. + case ParsedAttr::AT_Pure: // (implies nothrow attr) + case ParsedAttr::AT_Const: // (implies nothrow attr) + case ParsedAttr::AT_NoAlias: // (implies nothrow attr) + // Exception Specifications aren't generally supported in C mode + // throughout clang, so revert to attribute-based handling for C. if (!state.getSema().getLangOpts().CPlusPlus) break; [[fallthrough]]; diff --git a/clang/test/CodeGenCXX/pr58798.cpp b/clang/test/CodeGenCXX/pr58798.cpp --- a/clang/test/CodeGenCXX/pr58798.cpp +++ b/clang/test/CodeGenCXX/pr58798.cpp @@ -14,7 +14,7 @@ // CHECK: Function Attrs: mustprogress noinline nounwind optnone willreturn memory(read) // CHECK-LABEL: define {{[^@]+}}@_Z22callee_with_clang_attri -// CHECK-SAME: (i32 noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-SAME: (i32 noundef [[A:%.*]]) #[[ATTR0]] personality ptr @__gxx_personality_v0 { // CHECK-NEXT: entry: // CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 // CHECK-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 @@ -24,10 +24,18 @@ // CHECK: if.then: // CHECK-NEXT: [[EXCEPTION:%.*]] = call ptr @__cxa_allocate_exception(i64 4) #[[ATTR4:[0-9]+]] // CHECK-NEXT: store i32 42, ptr [[EXCEPTION]], align 16 -// CHECK-NEXT: call void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR5:[0-9]+]] -// CHECK-NEXT: unreachable +// CHECK-NEXT: invoke void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR5:[0-9]+]] +// CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[TERMINATE_LPAD:%.*]] // CHECK: if.end: // CHECK-NEXT: ret i32 24 +// CHECK: terminate.lpad: +// CHECK-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } +// CHECK-NEXT: catch ptr null +// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 +// CHECK-NEXT: call void @__clang_call_terminate(ptr [[TMP2]]) #[[ATTR6:[0-9]+]] +// CHECK-NEXT: unreachable +// CHECK: unreachable: +// CHECK-NEXT: unreachable // // CHECK: Function Attrs: mustprogress noinline nounwind optnone @@ -72,7 +80,7 @@ // CHECK-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } // CHECK-NEXT: catch ptr null // CHECK-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 -// CHECK-NEXT: call void @__clang_call_terminate(ptr [[TMP2]]) #[[ATTR6:[0-9]+]] +// CHECK-NEXT: call void @__clang_call_terminate(ptr [[TMP2]]) #[[ATTR6]] // CHECK-NEXT: unreachable // CHECK: unreachable: // CHECK-NEXT: unreachable @@ -89,7 +97,6 @@ // CHECK-NEXT: ret i32 [[CALL]] // - // Forward declarations: __attribute__((pure)) int callee_with_clang_attr(int a); diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp --- a/clang/test/OpenMP/declare_variant_messages.cpp +++ b/clang/test/OpenMP/declare_variant_messages.cpp @@ -130,6 +130,7 @@ template int score_and_cond_const_inst(); +// FIXME: why does this produce: error: exception specification in declaration does not match previous declaration __attribute__((pure)) int pure() { return 0; } #pragma omp declare variant(pure) match(user = {condition(1)}) // expected-warning {{ignoring return value of function declared with pure attribute}} diff --git a/clang/test/SemaCXX/attr-print.cpp b/clang/test/SemaCXX/attr-print.cpp --- a/clang/test/SemaCXX/attr-print.cpp +++ b/clang/test/SemaCXX/attr-print.cpp @@ -7,14 +7,14 @@ // CHECK: int y __declspec(align(4)); __declspec(align(4)) int y; -// CHECK: void foo() __attribute__((const)); +// CHECK: void foo() noexcept __attribute__((const)); void foo() __attribute__((const)); -// CHECK: void bar() __attribute__((__const)); +// CHECK: void bar() noexcept __attribute__((__const)); void bar() __attribute__((__const)); // FIXME: Print this with correct format. -// CHECK: void foo1() __attribute__((noinline)) __attribute__((pure)); +// CHECK: void foo1() noexcept __attribute__((noinline)) __attribute__((pure)); void foo1() __attribute__((noinline, pure)); // CHECK: typedef int Small1 __attribute__((mode(byte))); diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp --- a/clang/test/SemaCXX/cxx11-attr-print.cpp +++ b/clang/test/SemaCXX/cxx11-attr-print.cpp @@ -31,10 +31,10 @@ // CHECK: int c11_alignas _Alignas(alignof(int)); _Alignas(int) int c11_alignas; -// CHECK: void foo() __attribute__((const)); +// CHECK: void foo() noexcept __attribute__((const)); void foo() __attribute__((const)); -// CHECK: void bar() __attribute__((__const)); +// CHECK: void bar() noexcept __attribute__((__const)); void bar() __attribute__((__const)); // FIXME: It's unfortunate that the string literal prints with the below three @@ -65,8 +65,8 @@ // CHECK: int m __attribute__((aligned(4 // CHECK: int n alignas(4 -// CHECK: static int f() __attribute__((pure)) -// CHECK: static int g() {{\[}}[gnu::pure]] +// CHECK: static int f() noexcept __attribute__((pure)) +// CHECK: static int g() noexcept {{\[}}[gnu::pure]] template struct S { __attribute__((aligned(4))) int m; alignas(4) int n; @@ -80,8 +80,8 @@ // CHECK: int m __attribute__((aligned(4 // CHECK: int n alignas(4 -// CHECK: static int f() __attribute__((pure)) -// CHECK: static int g() {{\[}}[gnu::pure]] +// CHECK: static int f() noexcept __attribute__((pure)) +// CHECK: static int g() noexcept {{\[}}[gnu::pure]] template struct S; // CHECK: using Small2 {{\[}}[gnu::mode(byte)]] = int; diff --git a/clang/test/SemaCXX/warn-throw-out-noexcept-func.cpp b/clang/test/SemaCXX/warn-throw-out-noexcept-func.cpp --- a/clang/test/SemaCXX/warn-throw-out-noexcept-func.cpp +++ b/clang/test/SemaCXX/warn-throw-out-noexcept-func.cpp @@ -23,6 +23,9 @@ void __declspec(nothrow) SomeDeclspecThrow() {// expected-note {{function declared non-throwing here}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } + void __attribute__((pure)) SomeAnotherThrow() {// expected-note {{function declared non-throwing here}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} + } }; struct M_ShouldNotDiag { @@ -240,7 +243,7 @@ } } // As seen in p34973, this should not throw the warning. If there is an active -// exception, catch(...) catches everything. +// exception, catch(...) catches everything. void o_ShouldNotDiag() noexcept { try { throw;