diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10072,6 +10072,7 @@ const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); + void updateAttrsForLateParsedTemplate(const Decl *Pattern, Decl *Inst); void InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -606,6 +606,13 @@ New->addAttr(Attr.clone(S.getASTContext())); } +static void instantiateDependentStrictFPAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const StrictFPAttr &Attr, Decl *New) { + if (!New->hasAttr()) + New->addAttr(Attr.clone(S.getASTContext())); +} + /// Determine whether the attribute A might be relevant to the declaration D. /// If not, we can skip instantiating it. The attribute may or may not have /// been instantiated yet. @@ -811,6 +818,11 @@ continue; } + if (auto *A = dyn_cast(TmplAttr)) { + instantiateDependentStrictFPAttr(*this, TemplateArgs, *A, New); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the @@ -834,6 +846,22 @@ } } +/// Update instantiation attributes after template was late parsed. +/// +/// Some attributes are evaluated based on the body of template. If it is +/// late parsed, such attributes cannot be evaluated when declaration is +/// instantiated. This function is used to update instantiation attributes when +/// template definition is ready. +void Sema::updateAttrsForLateParsedTemplate(const Decl *Pattern, Decl *Inst) { + for (const auto *TmplAttr : Pattern->attrs()) { + if (auto *A = dyn_cast(TmplAttr)) { + instantiateDependentStrictFPAttr(*this, MultiLevelTemplateArgumentList(), + *A, Inst); + continue; + } + } +} + /// In the MS ABI, we need to instantiate default arguments of dllexported /// default constructors along with the constructor definition. This allows IR /// gen to emit a constructor closure which calls the default constructor with @@ -4916,6 +4944,7 @@ "missing LateParsedTemplate"); LateTemplateParser(OpaqueParser, *LPTIter->second); Pattern = PatternDecl->getBody(PatternDecl); + updateAttrsForLateParsedTemplate(PatternDecl, Function); } // Note, we should never try to instantiate a deleted function template. diff --git a/clang/test/CodeGen/fp-template.cpp b/clang/test/CodeGen/fp-template.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/fp-template.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fdelayed-template-parsing -o - %s | FileCheck %s + +template +T templ_01(T x, T y) { +#pragma STDC FENV_ACCESS ON + return x + y; +} + +float func_01(float x, float y) { + return templ_01(x, y); +} + +// CHECK-LABEL: define {{.*}} @_Z8templ_01IfET_S0_S0_ +// CHECK-SAME: (float noundef %{{.*}}, float noundef %{{.*}}) #[[ATTR01:[0-9]+]]{{.*}} { +// CHECK: call float @llvm.experimental.constrained.fadd.f32 + +// CHECK: attributes #[[ATTR01]] = { {{.*}}strictfp