Commit 8be5478f authored by Hans Wennborg's avatar Hans Wennborg
Browse files

Merging r323935:

------------------------------------------------------------------------
r323935 | rsmith | 2018-02-01 01:28:36 +0100 (Thu, 01 Feb 2018) | 5 lines

PR36181: Teach CodeGen to properly ignore requests to emit dependent entities.

Previously, friend function definitions within class templates slipped through
the gaps and caused the MS mangler to assert.

------------------------------------------------------------------------

llvm-svn: 324215
parent e71868f8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -836,6 +836,10 @@ public:

  void setLexicalDeclContext(DeclContext *DC);

  /// Determine whether this declaration is a templated entity (whether it is
  // within the scope of a template parameter).
  bool isTemplated() const;

  /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
  /// scoped decl is defined outside the current function or method.  This is
  /// roughly global variables and functions, but also handles enums (which
+13 −0
Original line number Diff line number Diff line
@@ -236,10 +236,23 @@ TemplateDecl *Decl::getDescribedTemplate() const {
    return RD->getDescribedClassTemplate();
  else if (auto *VD = dyn_cast<VarDecl>(this))
    return VD->getDescribedVarTemplate();
  else if (auto *AD = dyn_cast<TypeAliasDecl>(this))
    return AD->getDescribedAliasTemplate();

  return nullptr;
}

bool Decl::isTemplated() const {
  // A declaration is dependent if it is a template or a template pattern, or
  // is within (lexcially for a friend, semantically otherwise) a dependent
  // context.
  // FIXME: Should local extern declarations be treated like friends?
  if (auto *AsDC = dyn_cast<DeclContext>(this))
    return AsDC->isDependentContext();
  auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
  return DC->isDependentContext() || isTemplateDecl() || getDescribedTemplate();
}

const DeclContext *Decl::getParentFunctionOrMethod() const {
  for (const DeclContext *DC = getDeclContext();
       DC && !DC->isTranslationUnit() && !DC->isNamespace(); 
+1 −17
Original line number Diff line number Diff line
@@ -4000,18 +4000,13 @@ void CodeGenModule::EmitDeclContext(const DeclContext *DC) {
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void CodeGenModule::EmitTopLevelDecl(Decl *D) {
  // Ignore dependent declarations.
  if (D->getDeclContext() && D->getDeclContext()->isDependentContext())
  if (D->isTemplated())
    return;

  switch (D->getKind()) {
  case Decl::CXXConversion:
  case Decl::CXXMethod:
  case Decl::Function:
    // Skip function templates
    if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
        cast<FunctionDecl>(D)->isLateTemplateParsed())
      return;

    EmitGlobal(cast<FunctionDecl>(D));
    // Always provide some coverage mapping
    // even for the functions that aren't emitted.
@@ -4024,10 +4019,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {

  case Decl::Var:
  case Decl::Decomposition:
    // Skip variable templates
    if (cast<VarDecl>(D)->getDescribedVarTemplate())
      return;
    LLVM_FALLTHROUGH;
  case Decl::VarTemplateSpecialization:
    EmitGlobal(cast<VarDecl>(D));
    if (auto *DD = dyn_cast<DecompositionDecl>(D))
@@ -4086,16 +4077,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
      DI->EmitUsingDirective(cast<UsingDirectiveDecl>(*D));
    return;
  case Decl::CXXConstructor:
    // Skip function templates
    if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
        cast<FunctionDecl>(D)->isLateTemplateParsed())
      return;

    getCXXABI().EmitCXXConstructors(cast<CXXConstructorDecl>(D));
    break;
  case Decl::CXXDestructor:
    if (cast<FunctionDecl>(D)->isLateTemplateParsed())
      return;
    getCXXABI().EmitCXXDestructors(cast<CXXDestructorDecl>(D));
    break;

+11 −0
Original line number Diff line number Diff line
// RUN: %clang_cc1 -emit-llvm-only -fmodules -triple x86_64-windows %s
// PR36181
#pragma clang module build foo
module foo {}
#pragma clang module contents
template <typename T> struct A {
  friend void f(A<T>) {}
};
#pragma clang module endbuild
#pragma clang module import foo
void g() { f(A<int>()); }