// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++20 -emit-llvm -o - %s | FileCheck %s // CHECK-DAG: define {{.*}} @_ZeqRK6TargetS1_({{.*}}) [[NORMAL_ATTRS:#[0-9]+]] // CHECK-DAG: define {{.*}} @_ZeqRK12StrictTargetS1_({{.*}}) [[STRICT_ATTRS:#[0-9]+]] // CHECK-DAG: define {{.*}} @_ZN12AssignTargetaSERKS_({{.*}}) [[NORMAL_ATTRS]] // CHECK-DAG: define {{.*}} @_ZN18StrictAssignTargetaSERKS_({{.*}}) [[STRICT_ATTRS]] // Templates // CHECK-DAG: define {{.*}} @_ZeqRK14TemplateTargetIdES2_({{.*}}) [[NORMAL_ATTRS]] // CHECK-DAG: define {{.*}} @_ZeqRK14TemplateTargetIfES2_({{.*}}) [[NORMAL_ATTRS]] // CHECK-DAG: define {{.*}} @_ZeqRK20StrictTemplateTargetIdES2_({{.*}}) [[STRICT_ATTRS]] // --- NON-STRICT DECLARATIONS (at top of file, default FP is non-strict) --- struct Target { double d; friend bool operator==(const Target&, const Target&) = default; }; struct Member { double d; Member& operator=(const Member& Other) { d = Other.d + 1.0; return *this; } }; struct AssignTarget { Member m; }; template struct TemplateTarget { T d; friend bool operator==(const TemplateTarget&, const TemplateTarget&) = default; }; // Trigger instantiation of TemplateTarget::operator== in non-strict context. bool test_template_non_strict(TemplateTarget a, TemplateTarget b) { return a == b; } // --- STRICT CONTEXT (pragmas enabled) --- #pragma STDC FENV_ACCESS ON // Use-sites triggering synthesis of non-strict defaulted functions in strict context. bool test_non_strict_cmp(Target a, Target b) { return a == b; } void test_non_strict_assign(AssignTarget& a, AssignTarget& b) { a = b; } // Trigger instantiation of TemplateTarget::operator== in strict context. // It should still be non-strict because the template was defined in non-strict context. bool test_template_strict(TemplateTarget a, TemplateTarget b) { return a == b; } // Strict declarations (must get strictfp) struct StrictTarget { double d; friend bool operator==(const StrictTarget&, const StrictTarget&) = default; }; bool test_strict_cmp(StrictTarget a, StrictTarget b) { return a == b; } struct StrictAssignTarget { Member m; }; void test_strict_assign(StrictAssignTarget& a, StrictAssignTarget& b) { a = b; } template struct StrictTemplateTarget { T d; friend bool operator==(const StrictTemplateTarget&, const StrictTemplateTarget&) = default; }; // --- NON-STRICT CONTEXT AGAIN --- #pragma STDC FENV_ACCESS OFF // Trigger instantiation of StrictTemplateTarget::operator== in non-strict context. // It should be strict because the template was defined in strict context. bool test_strict_template_non_strict(StrictTemplateTarget a, StrictTemplateTarget b) { return a == b; } // CHECK-DAG: attributes [[STRICT_ATTRS]] = { {{.*}}strictfp{{.*}} } // CHECK-DAG: attributes [[NORMAL_ATTRS]] = { {{.*}} } // CHECK-NOT: attributes [[NORMAL_ATTRS]] = { {{.*}}strictfp