From: Reid Kleckner Date: Wed, 1 Apr 2015 16:23:44 +0000 (+0000) Subject: Mark instantiated function decls as inline specified if any pattern is X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c53a86c0cb8a657864ca6826c97e62c0d4b356dc;p=clang Mark instantiated function decls as inline specified if any pattern is A function template pattern can be declared without the 'inline' specifier and defined later with the 'inline' specifier. However, during instantiation, we were only looking at the canonical decl to see if we should mark the instantiated decl as inline specified. Since the instantiated decl actually represents many pattern declarations, put the inline specifier on the instantiation decl if any of the pattern decls have it. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@233817 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6936539f1c..677c3b8bb1 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1304,6 +1304,15 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context, NewFunc->getParamTypes(), NewEPI); } +/// Return true if any redeclaration of FD was inline specified. Useful for +/// propagating the 'inline' specifier onto function template instantiations. +static bool isAnyRedeclInlineSpecified(const FunctionDecl *FD) { + for (const auto *R : FD->redecls()) + if (R->isInlineSpecified()) + return true; + return false; +} + /// Normal class members are of more specific types and therefore /// don't make it here. This function serves two purposes: /// 1) instantiating function templates @@ -1372,7 +1381,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo, D->getCanonicalDecl()->getStorageClass(), - D->isInlineSpecified(), D->hasWrittenPrototype(), + isAnyRedeclInlineSpecified(D), + D->hasWrittenPrototype(), D->isConstexpr()); Function->setRangeEnd(D->getSourceRange().getEnd()); @@ -1669,7 +1679,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method = CXXConstructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), - Constructor->isInlineSpecified(), + isAnyRedeclInlineSpecified(Constructor), false, Constructor->isConstexpr()); // Claim that the instantiation of a constructor or constructor template @@ -1704,12 +1714,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - Destructor->isInlineSpecified(), + isAnyRedeclInlineSpecified(Destructor), false); } else if (CXXConversionDecl *Conversion = dyn_cast(D)) { Method = CXXConversionDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - Conversion->isInlineSpecified(), + isAnyRedeclInlineSpecified(Conversion), Conversion->isExplicit(), Conversion->isConstexpr(), Conversion->getLocEnd()); @@ -1717,7 +1727,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StorageClass SC = D->isStatic() ? SC_Static : SC_None; Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - SC, D->isInlineSpecified(), + SC, isAnyRedeclInlineSpecified(D), D->isConstexpr(), D->getLocEnd()); } diff --git a/test/CodeGenCXX/inlinehint.cpp b/test/CodeGenCXX/inlinehint.cpp new file mode 100644 index 0000000000..57873b173d --- /dev/null +++ b/test/CodeGenCXX/inlinehint.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple %s -emit-llvm -o - | FileCheck %s + +inline void InlineFunc() {} +// CHECK: define linkonce_odr void @_Z10InlineFuncv() #[[INLINEHINTATTR:[0-9]+]] comdat { + +struct MyClass { + static void InlineStaticMethod(); + void InlineInstanceMethod(); +}; +inline void MyClass::InlineStaticMethod() {} +// CHECK: define linkonce_odr void @_ZN7MyClass18InlineStaticMethodEv() #[[INLINEHINTATTR]] comdat +inline void MyClass::InlineInstanceMethod() {} +// CHECK: define linkonce_odr void @_ZN7MyClass20InlineInstanceMethodEv(%struct.MyClass* %this) #[[INLINEHINTATTR]] comdat + +template +struct MyTemplate { + static void InlineStaticMethod(); + void InlineInstanceMethod(); +}; +template inline void MyTemplate::InlineStaticMethod() {} +// CHECK: define linkonce_odr void @_ZN10MyTemplateIiE18InlineStaticMethodEv() #[[INLINEHINTATTR]] comdat +template inline void MyTemplate::InlineInstanceMethod() {} +// CHECK: define linkonce_odr void @_ZN10MyTemplateIiE20InlineInstanceMethodEv(%struct.MyTemplate* %this) #[[INLINEHINTATTR]] comdat + +void UseThem() { + InlineFunc(); + MyClass::InlineStaticMethod(); + MyClass().InlineInstanceMethod(); + MyTemplate::InlineStaticMethod(); + MyTemplate().InlineInstanceMethod(); +} + +// CHECK: attributes #[[INLINEHINTATTR]] = { {{.*}}inlinehint{{.*}} }