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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181981 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b8f4787..cbd5588 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -273,6 +273,45 @@
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 @@
continue;
case TemplateArgument::Type:
- LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ LV.merge(getLIForTemplateTypeArgument(arg.getAsType()));
continue;
case TemplateArgument::Declaration: