[clang] 46757cc - [clang] functions with the 'const' or 'pure' attribute must always return.

Jeroen Dobbelaere via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 18 08:33:55 PST 2021


Author: Jeroen Dobbelaere
Date: 2021-02-18T17:29:46+01:00
New Revision: 46757ccb49ab88da54ca8ddd43665d5255ee80f7

URL: https://github.com/llvm/llvm-project/commit/46757ccb49ab88da54ca8ddd43665d5255ee80f7
DIFF: https://github.com/llvm/llvm-project/commit/46757ccb49ab88da54ca8ddd43665d5255ee80f7.diff

LOG: [clang] functions with the 'const' or 'pure' attribute must always return.

As described in
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute

An `__attribute__((pure))` function must always return, as well as an `__attribute__((const))` function.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D96960

Added: 
    

Modified: 
    clang/lib/CodeGen/CGCall.cpp
    clang/test/CodeGen/complex-builtins.c
    clang/test/CodeGen/complex-libcalls.c
    clang/test/CodeGen/function-attributes.c
    clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
    clang/test/Sema/libbuiltins-ctype-powerpc64.c
    clang/test/Sema/libbuiltins-ctype-x86_64.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 405b4d2e1980..992e87319943 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1994,9 +1994,14 @@ void CodeGenModule::ConstructAttributeList(
     if (TargetDecl->hasAttr<ConstAttr>()) {
       FuncAttrs.addAttribute(llvm::Attribute::ReadNone);
       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<PureAttr>()) {
       FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
       FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+      // gcc specifies that 'pure' functions cannot have infinite loops.
+      FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
     } else if (TargetDecl->hasAttr<NoAliasAttr>()) {
       FuncAttrs.addAttribute(llvm::Attribute::ArgMemOnly);
       FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);

diff  --git a/clang/test/CodeGen/complex-builtins.c b/clang/test/CodeGen/complex-builtins.c
index 96c0e7117016..6fea8a9f028c 100644
--- a/clang/test/CodeGen/complex-builtins.c
+++ b/clang/test/CodeGen/complex-builtins.c
@@ -133,7 +133,7 @@ void foo(float f) {
 // NO__ERRNO: declare { x86_fp80, x86_fp80 } @cprojl({ x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16) [[NOT_READNONE]]
 // HAS_ERRNO: declare { double, double } @cproj(double, double) [[READNONE:#[0-9]+]]
 // HAS_ERRNO: declare <2 x float> @cprojf(<2 x float>) [[READNONE]]
-// HAS_ERRNO: declare { x86_fp80, x86_fp80 } @cprojl({ x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16) [[NOT_READNONE]]
+// HAS_ERRNO: declare { x86_fp80, x86_fp80 } @cprojl({ x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16) [[WILLRETURN_NOT_READNONE:#[0-9]+]]
 
   __builtin_cpow(f,f);       __builtin_cpowf(f,f);      __builtin_cpowl(f,f);
 
@@ -202,3 +202,4 @@ void foo(float f) {
 
 // HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} }
 // HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} }
+// HAS_ERRNO: attributes [[WILLRETURN_NOT_READNONE]] = { nounwind willreturn {{.*}} }

diff  --git a/clang/test/CodeGen/complex-libcalls.c b/clang/test/CodeGen/complex-libcalls.c
index 9bd419a83821..44d6849c0a71 100644
--- a/clang/test/CodeGen/complex-libcalls.c
+++ b/clang/test/CodeGen/complex-libcalls.c
@@ -133,7 +133,7 @@ void foo(float f) {
 // NO__ERRNO: declare { x86_fp80, x86_fp80 } @cprojl({ x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16) [[NOT_READNONE]]
 // HAS_ERRNO: declare { double, double } @cproj(double, double) [[READNONE:#[0-9]+]]
 // HAS_ERRNO: declare <2 x float> @cprojf(<2 x float>) [[READNONE]]
-// HAS_ERRNO: declare { x86_fp80, x86_fp80 } @cprojl({ x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16) [[NOT_READNONE]]
+// HAS_ERRNO: declare { x86_fp80, x86_fp80 } @cprojl({ x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16) [[WILLRETURN_NOT_READNONE:#[0-9]+]]
 
   cpow(f,f);       cpowf(f,f);      cpowl(f,f);
 
@@ -202,3 +202,4 @@ void foo(float f) {
 
 // HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind {{.*}} }
 // HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} }
+// HAS_ERRNO: attributes [[WILLRETURN_NOT_READNONE]] = { nounwind willreturn {{.*}} }

diff  --git a/clang/test/CodeGen/function-attributes.c b/clang/test/CodeGen/function-attributes.c
index ffb86a6cd272..f14f24801006 100644
--- a/clang/test/CodeGen/function-attributes.c
+++ b/clang/test/CodeGen/function-attributes.c
@@ -115,5 +115,5 @@ void f20(void) {
 // CHECK: attributes [[SR]] = { nounwind optsize{{.*}} "stackrealign"{{.*}} }
 // CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} }
 // CHECK: attributes [[NR]] = { noreturn optsize }
-// CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone }
+// CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone willreturn }
 // CHECK: attributes [[RT_CALL]] = { optsize returns_twice }

diff  --git a/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp b/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
index 25400a552e5d..e1d539608fcc 100644
--- a/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
+++ b/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
@@ -15,8 +15,8 @@ int f(void) {
 // CHECK: declare i32 @_Z1tv() [[TF2:#[0-9]+]]
 
 // CHECK: attributes [[TF]] = { {{.*}} }
-// CHECK: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
-// CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} }
+// CHECK: attributes [[NUW_RN]] = { nounwind readnone willreturn{{.*}} }
+// CHECK: attributes [[NUW_RO]] = { nounwind readonly willreturn{{.*}} }
 // CHECK: attributes [[TF2]] = { {{.*}} }
-// CHECK: attributes [[NUW_RN_CALL]] = { nounwind readnone }
-// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly }
+// CHECK: attributes [[NUW_RN_CALL]] = { nounwind readnone willreturn }
+// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly willreturn }

diff  --git a/clang/test/Sema/libbuiltins-ctype-powerpc64.c b/clang/test/Sema/libbuiltins-ctype-powerpc64.c
index bfd79acb0ab0..ba0efb205944 100644
--- a/clang/test/Sema/libbuiltins-ctype-powerpc64.c
+++ b/clang/test/Sema/libbuiltins-ctype-powerpc64.c
@@ -62,4 +62,4 @@ void test(int x) {
 // CHECK: declare signext i32 @toupper(i32 signext) [[NUW_RO:#[0-9]+]]
 
 // CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} }
-// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly }
+// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly willreturn }

diff  --git a/clang/test/Sema/libbuiltins-ctype-x86_64.c b/clang/test/Sema/libbuiltins-ctype-x86_64.c
index 4934e6f16752..b8a2c7e81584 100644
--- a/clang/test/Sema/libbuiltins-ctype-x86_64.c
+++ b/clang/test/Sema/libbuiltins-ctype-x86_64.c
@@ -62,4 +62,4 @@ void test(int x) {
 // CHECK: declare i32 @toupper(i32) [[NUW_RO:#[0-9]+]]
 
 // CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} }
-// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly }
+// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly willreturn }


        


More information about the cfe-commits mailing list