summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2013-05-16 04:30:21 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2013-05-16 04:30:21 +0000
commitc1b38a29e7714e2d2a71cf69897bc5bd31473c69 (patch)
tree6038e6ab4f75b4f3da2333c0e8bb9daaa331c426 /clang
parent7dd22c51b1531ac2f6620c3ef2b30890190920c4 (diff)
downloadbcm5719-llvm-c1b38a29e7714e2d2a71cf69897bc5bd31473c69.tar.gz
bcm5719-llvm-c1b38a29e7714e2d2a71cf69897bc5bd31473c69.zip
Fix pr15930.
In the case of inline functions, we have to special case local types when they are used as template arguments to make sure the template instantiations are still uniqued in case the function itself is inlined. llvm-svn: 181981
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/AST/Decl.cpp41
-rw-r--r--clang/test/CodeGenCXX/linkage.cpp95
2 files changed, 135 insertions, 1 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index b8f478728f0..cbd55889c9e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -273,6 +273,45 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
static LinkageInfo getLVForDecl(const NamedDecl *D,
LVComputationKind computation);
+static const FunctionDecl *getOutermostFunctionContext(const Decl *D) {
+ const FunctionDecl *Ret = NULL;
+ const DeclContext *DC = D->getDeclContext();
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ const FunctionDecl *F = dyn_cast<FunctionDecl>(DC);
+ if (F)
+ Ret = F;
+ DC = DC->getParent();
+ }
+ return Ret;
+}
+
+/// Get the linkage and visibility to be used when this type is a template
+/// argument. This is normally just the linkage and visibility of the type,
+/// but for function local types we need to check the linkage and visibility
+/// of the function.
+static LinkageInfo getLIForTemplateTypeArgument(QualType T) {
+ LinkageInfo LI = T->getLinkageAndVisibility();
+ if (LI.getLinkage() != NoLinkage)
+ return LI;
+
+ const TagType *TT = dyn_cast<TagType>(T);
+ if (!TT)
+ return LI;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TT->getDecl());
+ if (!RD)
+ return LI;
+
+ const FunctionDecl *FD = getOutermostFunctionContext(RD);
+ if (!FD)
+ return LI;
+
+ if (!FD->isInlined())
+ return LI;
+
+ return FD->getLinkageAndVisibility();
+}
+
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
///
@@ -291,7 +330,7 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
continue;
case TemplateArgument::Type:
- LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ LV.merge(getLIForTemplateTypeArgument(arg.getAsType()));
continue;
case TemplateArgument::Declaration:
diff --git a/clang/test/CodeGenCXX/linkage.cpp b/clang/test/CodeGenCXX/linkage.cpp
new file mode 100644
index 00000000000..a940e89c1d4
--- /dev/null
+++ b/clang/test/CodeGenCXX/linkage.cpp
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -O1 -disable-llvm-optzns %s -o - | FileCheck %s
+
+// CHECK: define internal void @_ZN5test31fIZNS_1gEvE1SEEvT_(
+// CHECK: define linkonce_odr void @_ZN5test41fIZNS_1gILi1EEEPvvE1SEEvT_(
+// CHECK: define linkonce_odr void @_ZN5test51fIZNS_1gILi1EEEPvvE1S_1EEvT_(
+// CHECK: define internal void @_ZN5test71fIZZNS_1gEvEN1S1hEvE1T_4EEvv(
+// CHECK: define linkonce_odr void @_ZN5test61fIZZNS_1gEvEN1S1hE_2vE1T_3EEvv(
+// CHECK: define internal void @_ZN5test21fIZNS_L1gEvE1S_0EEvT_(
+// CHECK: define linkonce_odr void @_ZN5test11fIZNS_1gEvE1SEEvT_(
+
+namespace test1 {
+ template <typename T> void f(T) {}
+ inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test2 {
+ template <typename T> void f(T) {}
+ static inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test3 {
+ template <typename T> void f(T) {}
+ void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ void *h() { return g(); }
+}
+
+namespace test4 {
+ template <typename T> void f(T) {}
+ template <int N> inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ extern template void *g<1>();
+ template void *g<1>();
+}
+
+namespace test5 {
+ template <typename T> void f(T) {}
+ template <int N> inline void *g() {
+ struct S {
+ } s;
+ return reinterpret_cast<void *>(f<S>);
+ }
+ extern template void *g<1>();
+ void *h() { return g<1>(); }
+}
+
+namespace test6 {
+ template <typename T> void f() {}
+
+ inline void *g() {
+ struct S {
+ void *h() {
+ struct T {
+ };
+ return (void *)f<T>;
+ }
+ } s;
+ return s.h();
+ }
+
+ void *h() { return g(); }
+}
+
+namespace test7 {
+ template <typename T> void f() {}
+
+ void *g() {
+ struct S {
+ void *h() {
+ struct T {
+ };
+ return (void *)f<T>;
+ }
+ } s;
+ return s.h();
+ }
+
+ void *h() { return g(); }
+}
OpenPOWER on IntegriCloud