Files
llvm-tms34010/clang/test/CodeGenCXX/defaulted-function-fp-features.cpp
Kyungtak Woo 5114f5e426 [Clang][Sema] Ensure explicitly defaulted functions respect FP pragmas from their declaration site (#207429)
Currently, when an explicitly defaulted function is synthesized (e.g.,
at its first use), it erroneously adopts the floating-point (FP) pragma
state of the synthesis site rather than its declaration site. This leads
to mismatched or incorrect FP features being applied to the generated
body, completely ignoring `#pragma STDC FENV_ACCESS` pragmas that were
active when the function was explicitly defaulted.
This change should fix this issue by capturing and restoring the FP
features at the appropriate times.

Fixes #207266 

I also added the following fixes to support the above:
- AST Importer Fix: Updated ASTImporter::VisitFunctionDecl to correctly
import FPFeatures and Lookups for defaulted/deleted functions, whereas
before it was silently dropping them.
- AST Version Bump: Bumped VERSION_MAJOR to 39 in ASTBitCodes.h to
reflect the new FunctionDecl binary layout changes in the AST
serialization.
2026-07-09 12:58:50 -06:00

102 lines
2.9 KiB
C++

// 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 <typename T>
struct TemplateTarget {
T d;
friend bool operator==(const TemplateTarget&, const TemplateTarget&) = default;
};
// Trigger instantiation of TemplateTarget<double>::operator== in non-strict context.
bool test_template_non_strict(TemplateTarget<double> a, TemplateTarget<double> 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<float>::operator== in strict context.
// It should still be non-strict because the template was defined in non-strict context.
bool test_template_strict(TemplateTarget<float> a, TemplateTarget<float> 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 <typename T>
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<double>::operator== in non-strict context.
// It should be strict because the template was defined in strict context.
bool test_strict_template_non_strict(StrictTemplateTarget<double> a, StrictTemplateTarget<double> b) {
return a == b;
}
// CHECK-DAG: attributes [[STRICT_ATTRS]] = { {{.*}}strictfp{{.*}} }
// CHECK-DAG: attributes [[NORMAL_ATTRS]] = { {{.*}} }
// CHECK-NOT: attributes [[NORMAL_ATTRS]] = { {{.*}}strictfp