Modular Codegen: Support homing debug info for types in modular objects
Matching the function-homing support for modular codegen. Any type implicitly (implicit template specializations) or explicitly defined in a module is attached to that module's object file and omitted elsewhere (only a declaration used if necessary for references). llvm-svn: 299987
This commit is contained in:
		
							parent
							
								
									ddb9ae192a
								
							
						
					
					
						commit
						1ac9c98e6c
					
				| 
						 | 
					@ -172,7 +172,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
 | 
					  enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual ExtKind hasExternalDefinitions(const FunctionDecl *FD);
 | 
					  virtual ExtKind hasExternalDefinitions(const Decl *D);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// \brief Finds all declarations lexically contained within the given
 | 
					  /// \brief Finds all declarations lexically contained within the given
 | 
				
			||||||
  /// DeclContext, after applying an optional filter predicate.
 | 
					  /// DeclContext, after applying an optional filter predicate.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +90,7 @@ public:
 | 
				
			||||||
  /// initializers themselves.
 | 
					  /// initializers themselves.
 | 
				
			||||||
  CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
 | 
					  CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ExtKind hasExternalDefinitions(const FunctionDecl *FD) override;
 | 
					  ExtKind hasExternalDefinitions(const Decl *D) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// \brief Find all declarations with the given name in the
 | 
					  /// \brief Find all declarations with the given name in the
 | 
				
			||||||
  /// given context.
 | 
					  /// given context.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1115,7 +1115,7 @@ private:
 | 
				
			||||||
  /// predefines buffer may contain additional definitions.
 | 
					  /// predefines buffer may contain additional definitions.
 | 
				
			||||||
  std::string SuggestedPredefines;
 | 
					  std::string SuggestedPredefines;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  llvm::DenseMap<const FunctionDecl *, bool> BodySource;
 | 
					  llvm::DenseMap<const Decl *, bool> BodySource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// \brief Reads a statement from the specified cursor.
 | 
					  /// \brief Reads a statement from the specified cursor.
 | 
				
			||||||
  Stmt *ReadStmtFromStream(ModuleFile &F);
 | 
					  Stmt *ReadStmtFromStream(ModuleFile &F);
 | 
				
			||||||
| 
						 | 
					@ -1999,7 +1999,7 @@ public:
 | 
				
			||||||
  /// \brief Return a descriptor for the corresponding module.
 | 
					  /// \brief Return a descriptor for the corresponding module.
 | 
				
			||||||
  llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
 | 
					  llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ExtKind hasExternalDefinitions(const FunctionDecl *FD) override;
 | 
					  ExtKind hasExternalDefinitions(const Decl *D) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// \brief Retrieve a selector from the given module with its local ID
 | 
					  /// \brief Retrieve a selector from the given module with its local ID
 | 
				
			||||||
  /// number.
 | 
					  /// number.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ ExternalASTSource::getSourceDescriptor(unsigned ID) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ExternalASTSource::ExtKind
 | 
					ExternalASTSource::ExtKind
 | 
				
			||||||
ExternalASTSource::hasExternalDefinitions(const FunctionDecl *FD) {
 | 
					ExternalASTSource::hasExternalDefinitions(const Decl *D) {
 | 
				
			||||||
  return EK_ReplyHazy;
 | 
					  return EK_ReplyHazy;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1820,6 +1820,10 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
 | 
				
			||||||
  if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
 | 
					  if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (auto *ES = RD->getASTContext().getExternalSource())
 | 
				
			||||||
 | 
					    if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always)
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (DebugKind > codegenoptions::LimitedDebugInfo)
 | 
					  if (DebugKind > codegenoptions::LimitedDebugInfo)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2552,11 +2556,17 @@ void CGDebugInfo::completeTemplateDefinition(
 | 
				
			||||||
    const ClassTemplateSpecializationDecl &SD) {
 | 
					    const ClassTemplateSpecializationDecl &SD) {
 | 
				
			||||||
  if (DebugKind <= codegenoptions::DebugLineTablesOnly)
 | 
					  if (DebugKind <= codegenoptions::DebugLineTablesOnly)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					  completeUnusedClass(SD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  completeClassData(&SD);
 | 
					void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
 | 
				
			||||||
 | 
					  if (DebugKind <= codegenoptions::DebugLineTablesOnly)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  completeClassData(&D);
 | 
				
			||||||
  // In case this type has no member function definitions being emitted, ensure
 | 
					  // In case this type has no member function definitions being emitted, ensure
 | 
				
			||||||
  // it is retained
 | 
					  // it is retained
 | 
				
			||||||
  RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
 | 
					  RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
 | 
					llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -438,6 +438,7 @@ public:
 | 
				
			||||||
  void completeClass(const RecordDecl *RD);
 | 
					  void completeClass(const RecordDecl *RD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
 | 
					  void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
 | 
				
			||||||
 | 
					  void completeUnusedClass(const CXXRecordDecl &D);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Create debug info for a macro defined by a #define directive or a macro
 | 
					  /// Create debug info for a macro defined by a #define directive or a macro
 | 
				
			||||||
  /// undefined by a #undef directive.
 | 
					  /// undefined by a #undef directive.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3820,6 +3820,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
 | 
				
			||||||
    EmitDeclContext(cast<NamespaceDecl>(D));
 | 
					    EmitDeclContext(cast<NamespaceDecl>(D));
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  case Decl::CXXRecord:
 | 
					  case Decl::CXXRecord:
 | 
				
			||||||
 | 
					    if (DebugInfo) {
 | 
				
			||||||
 | 
					      if (auto *ES = D->getASTContext().getExternalSource())
 | 
				
			||||||
 | 
					        if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
 | 
				
			||||||
 | 
					          DebugInfo->completeUnusedClass(cast<CXXRecordDecl>(*D));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    // Emit any static data members, they may be definitions.
 | 
					    // Emit any static data members, they may be definitions.
 | 
				
			||||||
    for (auto *I : cast<CXXRecordDecl>(D)->decls())
 | 
					    for (auto *I : cast<CXXRecordDecl>(D)->decls())
 | 
				
			||||||
      if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
 | 
					      if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,9 +95,9 @@ MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ExternalASTSource::ExtKind
 | 
					ExternalASTSource::ExtKind
 | 
				
			||||||
MultiplexExternalSemaSource::hasExternalDefinitions(const FunctionDecl *FD) {
 | 
					MultiplexExternalSemaSource::hasExternalDefinitions(const Decl *D) {
 | 
				
			||||||
  for (const auto &S : Sources)
 | 
					  for (const auto &S : Sources)
 | 
				
			||||||
    if (auto EK = S->hasExternalDefinitions(FD))
 | 
					    if (auto EK = S->hasExternalDefinitions(D))
 | 
				
			||||||
      if (EK != EK_ReplyHazy)
 | 
					      if (EK != EK_ReplyHazy)
 | 
				
			||||||
        return EK;
 | 
					        return EK;
 | 
				
			||||||
  return EK_ReplyHazy;
 | 
					  return EK_ReplyHazy;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8147,8 +8147,7 @@ ASTReader::getSourceDescriptor(unsigned ID) {
 | 
				
			||||||
  return None;
 | 
					  return None;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ExternalASTSource::ExtKind
 | 
					ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) {
 | 
				
			||||||
ASTReader::hasExternalDefinitions(const FunctionDecl *FD) {
 | 
					 | 
				
			||||||
  auto I = BodySource.find(FD);
 | 
					  auto I = BodySource.find(FD);
 | 
				
			||||||
  if (I == BodySource.end())
 | 
					  if (I == BodySource.end())
 | 
				
			||||||
    return EK_ReplyHazy;
 | 
					    return EK_ReplyHazy;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,8 @@ namespace clang {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
 | 
					    void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
 | 
				
			||||||
    void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data);
 | 
					    void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
 | 
				
			||||||
 | 
					                               const CXXRecordDecl *D);
 | 
				
			||||||
    void MergeDefinitionData(CXXRecordDecl *D,
 | 
					    void MergeDefinitionData(CXXRecordDecl *D,
 | 
				
			||||||
                             struct CXXRecordDecl::DefinitionData &&NewDD);
 | 
					                             struct CXXRecordDecl::DefinitionData &&NewDD);
 | 
				
			||||||
    void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
 | 
					    void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
 | 
				
			||||||
| 
						 | 
					@ -1490,7 +1491,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ASTDeclReader::ReadCXXDefinitionData(
 | 
					void ASTDeclReader::ReadCXXDefinitionData(
 | 
				
			||||||
                                   struct CXXRecordDecl::DefinitionData &Data) {
 | 
					    struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) {
 | 
				
			||||||
  // Note: the caller has deserialized the IsLambda bit already.
 | 
					  // Note: the caller has deserialized the IsLambda bit already.
 | 
				
			||||||
  Data.UserDeclaredConstructor = Record.readInt();
 | 
					  Data.UserDeclaredConstructor = Record.readInt();
 | 
				
			||||||
  Data.UserDeclaredSpecialMembers = Record.readInt();
 | 
					  Data.UserDeclaredSpecialMembers = Record.readInt();
 | 
				
			||||||
| 
						 | 
					@ -1536,6 +1537,12 @@ void ASTDeclReader::ReadCXXDefinitionData(
 | 
				
			||||||
  Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
 | 
					  Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
 | 
				
			||||||
  Data.ODRHash = Record.readInt();
 | 
					  Data.ODRHash = Record.readInt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (Record.readInt()) {
 | 
				
			||||||
 | 
					    Reader.BodySource[D] = Loc.F->Kind == ModuleKind::MK_MainFile
 | 
				
			||||||
 | 
					                               ? ExternalASTSource::EK_Never
 | 
				
			||||||
 | 
					                               : ExternalASTSource::EK_Always;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Data.NumBases = Record.readInt();
 | 
					  Data.NumBases = Record.readInt();
 | 
				
			||||||
  if (Data.NumBases)
 | 
					  if (Data.NumBases)
 | 
				
			||||||
    Data.Bases = ReadGlobalOffset();
 | 
					    Data.Bases = ReadGlobalOffset();
 | 
				
			||||||
| 
						 | 
					@ -1707,7 +1714,7 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    DD = new (C) struct CXXRecordDecl::DefinitionData(D);
 | 
					    DD = new (C) struct CXXRecordDecl::DefinitionData(D);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ReadCXXDefinitionData(*DD);
 | 
					  ReadCXXDefinitionData(*DD, D);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // We might already have a definition for this record. This can happen either
 | 
					  // We might already have a definition for this record. This can happen either
 | 
				
			||||||
  // because we're reading an update record, or because we've already done some
 | 
					  // because we're reading an update record, or because we've already done some
 | 
				
			||||||
| 
						 | 
					@ -2553,7 +2560,11 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) {
 | 
				
			||||||
           Var->isThisDeclarationADefinition() == VarDecl::Definition;
 | 
					           Var->isThisDeclarationADefinition() == VarDecl::Definition;
 | 
				
			||||||
  if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
 | 
					  if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
 | 
				
			||||||
    return Func->doesThisDeclarationHaveABody() || HasBody;
 | 
					    return Func->doesThisDeclarationHaveABody() || HasBody;
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
 | 
					  if (auto *ES = D->getASTContext().getExternalSource())
 | 
				
			||||||
 | 
					    if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5770,6 +5770,12 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
 | 
				
			||||||
  Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
 | 
					  Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
 | 
				
			||||||
  Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
 | 
					  Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
 | 
				
			||||||
  Record->push_back(Data.ODRHash);
 | 
					  Record->push_back(Data.ODRHash);
 | 
				
			||||||
 | 
					  bool ModularCodegen = Writer->Context->getLangOpts().ModularCodegen &&
 | 
				
			||||||
 | 
					                        Writer->WritingModule && !D->isDependentType();
 | 
				
			||||||
 | 
					  Record->push_back(ModularCodegen);
 | 
				
			||||||
 | 
					  if (ModularCodegen)
 | 
				
			||||||
 | 
					    Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // IsLambda bit is already saved.
 | 
					  // IsLambda bit is already saved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Record->push_back(Data.NumBases);
 | 
					  Record->push_back(Data.NumBases);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,11 @@
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void ftempl() {
 | 
					void foot() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
inline void f() {
 | 
					inline void foo() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					struct bart {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					struct bar {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@ RUN:            %S/Inputs/codegen-nodep/foo.modulemap -o - \
 | 
				
			||||||
RUN:          | llvm-bcanalyzer - -dump \
 | 
					RUN:          | llvm-bcanalyzer - -dump \
 | 
				
			||||||
RUN:          | FileCheck %s
 | 
					RUN:          | FileCheck %s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ensure there's only one modular codegen decl - the sentinel plain inline
 | 
					Ensure there are only two modular codegen decls (one for the class, one for the
 | 
				
			||||||
function, not any for the function template.
 | 
					function - none for the class and function templates).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CHECK: <MODULAR_CODEGEN_DECLS op0={{[0-9]+}}/>
 | 
					CHECK: <MODULAR_CODEGEN_DECLS op0={{[0-9]+}} op1={{[0-9]+}}/>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,8 +3,8 @@ REQUIRES: x86-registered-target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
 | 
					RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s
 | 
					RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s
 | 
				
			||||||
RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s
 | 
					RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FOO: $_Z2f1PKcz = comdat any
 | 
					FOO: $_Z2f1PKcz = comdat any
 | 
				
			||||||
FOO: $_ZN13implicit_dtorD1Ev = comdat any
 | 
					FOO: $_ZN13implicit_dtorD1Ev = comdat any
 | 
				
			||||||
| 
						 | 
					@ -25,3 +25,11 @@ FOO: define weak_odr void @_ZN13implicit_dtorD2Ev
 | 
				
			||||||
USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev
 | 
					USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev
 | 
				
			||||||
USE: define linkonce_odr void @_Z4instIiEvv
 | 
					USE: define linkonce_odr void @_Z4instIiEvv
 | 
				
			||||||
USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev
 | 
					USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Modular debug info puts the definition of a class defined in a module in that
 | 
				
			||||||
 | 
					module's object. Users of the module only get a declaration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					'distinct' is used for definition records (the flags field is empty/unspecified)
 | 
				
			||||||
 | 
					FOO: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "implicit_dtor"
 | 
				
			||||||
 | 
					Declarations are non-distinct and include the 'DIFlagFwdDecl' flag.
 | 
				
			||||||
 | 
					USE: = !DICompositeType(tag: DW_TAG_structure_type, name: "implicit_dtor", {{.*}}, flags: DIFlagFwdDecl
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue