Index: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ include/clang/AST/DeclCXX.h @@ -257,30 +257,6 @@ TypeSourceInfo *getTypeSourceInfo() const { return BaseTypeInfo; } }; -/// \brief A lazy pointer to the definition data for a declaration. -/// FIXME: This is a little CXXRecordDecl-specific that the moment. -template class LazyDefinitionDataPtr { - llvm::PointerUnion DataOrCanonicalDecl; - - LazyDefinitionDataPtr update() { - if (Decl *Canon = DataOrCanonicalDecl.template dyn_cast()) { - if (Canon->isCanonicalDecl()) - Canon->getMostRecentDecl(); - else - // Declaration isn't canonical any more; - // update it and perform path compression. - *this = Canon->getPreviousDecl()->DefinitionData.update(); - } - return *this; - } - -public: - LazyDefinitionDataPtr(Decl *Canon) : DataOrCanonicalDecl(Canon) {} - LazyDefinitionDataPtr(T *Data) : DataOrCanonicalDecl(Data) {} - T *getNotUpdated() { return DataOrCanonicalDecl.template dyn_cast(); } - T *get() { return update().getNotUpdated(); } -}; - /// \brief Represents a C++ struct/union/class. class CXXRecordDecl : public RecordDecl { @@ -543,11 +519,7 @@ CXXBaseSpecifier *getVBasesSlowCase() const; }; - typedef LazyDefinitionDataPtr - DefinitionDataPtr; - friend class LazyDefinitionDataPtr; - - mutable DefinitionDataPtr DefinitionData; + mutable DefinitionData* DefinitionData; /// \brief Describes a C++ closure type (generated by a lambda expression). struct LambdaDefinitionData : public DefinitionData { @@ -611,7 +583,8 @@ }; struct DefinitionData &data() const { - auto *DD = DefinitionData.get(); + // Complete the redecl chain reading all necessary information. + auto *DD = getMostRecentDecl()->DefinitionData; assert(DD && "queried property of class with no definition"); return *DD; } @@ -619,7 +592,7 @@ struct LambdaDefinitionData &getLambdaData() const { // No update required: a merged definition cannot change any lambda // properties. - auto *DD = DefinitionData.getNotUpdated(); + auto *DD = DefinitionData; assert(DD && DD->IsLambda && "queried lambda property of non-lambda class"); return static_cast(*DD); } @@ -696,11 +669,11 @@ } CXXRecordDecl *getDefinition() const { - auto *DD = DefinitionData.get(); + auto *DD = DefinitionData; return DD ? DD->Definition : nullptr; } - bool hasDefinition() const { return DefinitionData.get(); } + bool hasDefinition() const { return DefinitionData; } static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -1044,7 +1017,7 @@ /// \brief Determine whether this class describes a lambda function object. bool isLambda() const { // An update record can't turn a non-lambda into a lambda. - auto *DD = DefinitionData.getNotUpdated(); + auto *DD = DefinitionData; return DD && DD->IsLambda; } Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -88,7 +88,7 @@ CXXRecordDecl *PrevDecl) : RecordDecl(K, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl), DefinitionData(PrevDecl ? PrevDecl->DefinitionData - : DefinitionDataPtr(this)), + : nullptr), TemplateOrInstantiation() {} CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1540,9 +1540,9 @@ void ASTDeclReader::MergeDefinitionData( CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &&MergeDD) { - assert(D->DefinitionData.getNotUpdated() && + assert(D->DefinitionData && "merging class definition into non-definition"); - auto &DD = *D->DefinitionData.getNotUpdated(); + auto &DD = *D->DefinitionData; if (DD.Definition != MergeDD.Definition) { // Track that we merged the definitions. @@ -1665,7 +1665,7 @@ // because we're reading an update record, or because we've already done some // merging. Either way, just merge into it. CXXRecordDecl *Canon = D->getCanonicalDecl(); - if (Canon->DefinitionData.getNotUpdated()) { + if (Canon->DefinitionData) { MergeDefinitionData(Canon, std::move(*DD)); D->DefinitionData = Canon->DefinitionData; return; @@ -2001,8 +2001,8 @@ // This declaration might be a definition. Merge with any existing // definition. - if (auto *DDD = D->DefinitionData.getNotUpdated()) { - if (CanonSpec->DefinitionData.getNotUpdated()) + if (auto *DDD = D->DefinitionData) { + if (CanonSpec->DefinitionData) MergeDefinitionData(CanonSpec, std::move(*DDD)); else CanonSpec->DefinitionData = D->DefinitionData; @@ -2326,8 +2326,8 @@ // FIXME: This is duplicated in several places. Refactor. auto *ExistingClass = cast(ExistingPattern)->getCanonicalDecl(); - if (auto *DDD = DClass->DefinitionData.getNotUpdated()) { - if (ExistingClass->DefinitionData.getNotUpdated()) { + if (auto *DDD = DClass->DefinitionData) { + if (ExistingClass->DefinitionData) { MergeDefinitionData(ExistingClass, std::move(*DDD)); } else { ExistingClass->DefinitionData = DClass->DefinitionData; @@ -2765,9 +2765,9 @@ if (CXXRecordDecl *RD = dyn_cast(DC)) { // Try to dig out the definition. - auto *DD = RD->DefinitionData.getNotUpdated(); + auto *DD = RD->DefinitionData; if (!DD) - DD = RD->getCanonicalDecl()->DefinitionData.getNotUpdated(); + DD = RD->getCanonicalDecl()->DefinitionData; // If there's no definition yet, then DC's definition is added by an update // record, but we've not yet loaded that update record. In this case, we @@ -3772,7 +3772,7 @@ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { auto *RD = cast(D); - auto *OldDD = RD->getCanonicalDecl()->DefinitionData.getNotUpdated(); + auto *OldDD = RD->getCanonicalDecl()->DefinitionData; bool HadRealDefinition = OldDD && (OldDD->Definition != RD || !Reader.PendingFakeDefinitionData.count(OldDD)); Index: test/Modules/Inputs/PR27754/RConversionRuleParser.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR27754/RConversionRuleParser.h @@ -0,0 +1,7 @@ +#define _STL_ALGOBASE_H +template < typename _Tp, _Tp > struct integral_constant +{ +}; +typedef integral_constant < bool, true > true_type; +#include +#include "TSchemaType.h" Index: test/Modules/Inputs/PR27754/TMetaUtils.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR27754/TMetaUtils.h @@ -0,0 +1,2 @@ +#include "RConversionRuleParser.h" +void fn1() { true_type(); } Index: test/Modules/Inputs/PR27754/TSchemaType.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR27754/TSchemaType.h @@ -0,0 +1,4 @@ +#ifndef _STL_ALGOBASE_H +template struct integral_constant {}; +struct A : integral_constant {}; +#endif Index: test/Modules/Inputs/PR27754/map =================================================================== --- /dev/null +++ test/Modules/Inputs/PR27754/map @@ -0,0 +1,3 @@ +class _Rb_tree { + _Rb_tree() { true_type(); } +}; Index: test/Modules/Inputs/PR27754/module.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/PR27754/module.modulemap @@ -0,0 +1,3 @@ +module "RConversionRuleParser.h" { header "RConversionRuleParser.h" } +module "TMetaUtils.h" { header "TMetaUtils.h" } +module "TSchemaType.h" { header "TSchemaType.h" } Index: test/Modules/pr27754.cpp =================================================================== --- /dev/null +++ test/Modules/pr27754.cpp @@ -0,0 +1,7 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -std=c++11 -I%S/Inputs/PR27754 -verify %s +// RUN: %clang_cc1 -std=c++11 -fmodules -fmodule-map-file=%S/Inputs/PR27754/module.modulemap -fmodules-cache-path=%t -I%S/Inputs/PR27754/ -verify %s + +#include "TMetaUtils.h" + +// expected-no-diagnostics