diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 30 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 28 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp | 66 |
3 files changed, 107 insertions, 17 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 28d0a8357e2..a6996a4bfe5 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -643,10 +643,33 @@ unsigned FunctionDecl::getMinRequiredArguments() const { } bool FunctionDecl::isInlined() const { - return isInlineSpecified() || (isa<CXXMethodDecl>(this) && !isOutOfLine()); + if (isInlineSpecified() || (isa<CXXMethodDecl>(this) && !isOutOfLine())) + return true; + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // Handle below. + break; + } + + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(PatternDecl); + + if (Pattern && PatternDecl) + return PatternDecl->isInlined(); + + return false; } -/// \brief For an inline function definition in C, determine whether the +/// \brief For an inline function definition in C or C++, determine whether the /// definition will be externally visible. /// /// Inline function definitions are always available for inlining optimizations. @@ -666,8 +689,9 @@ bool FunctionDecl::isInlined() const { bool FunctionDecl::isInlineDefinitionExternallyVisible() const { assert(isThisDeclarationADefinition() && "Must have the function definition"); assert(isInlined() && "Function must be inline"); + ASTContext &Context = getASTContext(); - if (!getASTContext().getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { + if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { // GNU inline semantics. Based on a number of examples, we came up with the // following heuristic: if the "inline" keyword is present on a // declaration of the function but "extern" is not present on that diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a40701851e3..db609f62453 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -253,6 +253,10 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->isInAnonymousNamespace()) return CodeGenModule::GVA_Internal; + // "static" functions get internal linkage. + if (FD->getStorageClass() == FunctionDecl::Static && !isa<CXXMethodDecl>(FD)) + return CodeGenModule::GVA_Internal; + // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; @@ -260,18 +264,6 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) External = CodeGenModule::GVA_TemplateInstantiation; - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - // C++ member functions defined inside the class are always inline. - if (MD->isInlined()) - return CodeGenModule::GVA_CXXInline; - - return External; - } - - // "static" functions get internal linkage. - if (FD->getStorageClass() == FunctionDecl::Static) - return CodeGenModule::GVA_Internal; - if (!FD->isInlined()) return External; @@ -285,8 +277,16 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, return CodeGenModule::GVA_C99Inline; } - // C++ inline semantics - assert(Features.CPlusPlus && "Must be in C++ mode"); + // C++0x [temp.explicit]p9: + // [ Note: The intent is that an inline function that is the subject of + // an explicit instantiation declaration will still be implicitly + // instantiated when used so that the body can be considered for + // inlining, but that no out-of-line copy of the inline function would be + // generated in the translation unit. -- end note ] + if (FD->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return CodeGenModule::GVA_C99Inline; + return CodeGenModule::GVA_CXXInline; } diff --git a/clang/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp b/clang/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp new file mode 100644 index 00000000000..59705d8a20e --- /dev/null +++ b/clang/test/CXX/temp/temp.spec/temp.explicit/p9-linkage.cpp @@ -0,0 +1,66 @@ +// RUN: clang-cc -emit-llvm -std=c++0x -o - %s | FileCheck %s + +template<typename T> +struct X0 { + void f(T &t) { + t = 0; + } + + void g(T &t); + + void h(T &t); + + static T static_var; +}; + +template<typename T> +inline void X0<T>::g(T & t) { + t = 0; +} + +template<typename T> +void X0<T>::h(T & t) { + t = 0; +} + +template<typename T> +T X0<T>::static_var = 0; + +extern template struct X0<int*>; + +int *&test(X0<int*> xi, int *ip) { + // CHECK: define available_externally void @_ZN2X0IPiE1fERS0_ + xi.f(ip); + // CHECK: define available_externally void @_ZN2X0IPiE1gERS0_ + xi.g(ip); + // CHECK: declare void @_ZN2X0IPiE1hERS0_ + xi.h(ip); + return X0<int*>::static_var; +} + +template<typename T> +void f0(T& t) { + t = 0; +} + +template<typename T> +inline void f1(T& t) { + t = 0; +} + +extern template void f0<>(int *&); +extern template void f1<>(int *&); + +void test_f0(int *ip, float *fp) { + // CHECK: declare void @_Z2f0IPiEvRT_ + f0(ip); + // CHECK: define linkonce_odr void @_Z2f0IPfEvRT_ + f0(fp); +} + +void test_f1(int *ip, float *fp) { + // CHECK: define available_externally void @_Z2f1IPiEvRT_ + f1(ip); + // CHECK: define linkonce_odr void @_Z2f1IPfEvRT_ + f1(fp); +} |