Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ms] CXXRecordDecl::getMSInheritanceModel() dereferences null MSInheritanceAttr #36747

Closed
llvmbot opened this issue May 9, 2018 · 14 comments
Closed
Labels
bugzilla Issues migrated from bugzilla clang:frontend Language frontend issues, e.g. anything involving "Sema"

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented May 9, 2018

Bugzilla Link 37399
Resolution FIXED
Resolved on Jun 01, 2018 09:13
Version trunk
OS Windows XP
Attachments Testcase, Patch with potential fix
Reporter LLVM Bugzilla Contributor
CC @majnemer,@rnk

Extended Description

Compile the following:

template
class Functor
{
void (ObjT::*PtrToMemberFunction)();
};

template class DerivedFunctor;

template
class DerivedFunctor
: public Functor<DerivedFunctor >
{
};

DerivedFunctor AFunctor;

with:

clang-cpp.exe -cc1 -emit-llvm-only -x c++ test.cpp

This generates the following ASSERT (debug build) / AV (release build):

C:\Temp\clang\clang>c:\workspaces\llvm-build\Debug\bin\clang-cpp.exe -cc1 -emit-llvm-only -x c++ test.cpp
Assertion failed: IA && "Expected MSInheritanceAttr on the CXXRecordDecl!", file c:\workspaces\llvm\tools\clang\lib\ast\microsoftcxxabi.cpp, line 171
Wrote crash dump file "C:\Users\14166\AppData\Local\Temp\clang-cpp.exe-346498.dmp"
...

The failing callstack which tries to use a null MSInheritanceAttr looks like this:

clang-cpp.exe!clang::CXXRecordDecl::getMSInheritanceModel() Line 171 C++
clang-cpp.exe!getMSMemberPointerSlots(const clang::MemberPointerType * MPT) Line 213 C++
clang-cpp.exe!anonymous namespace'::MicrosoftCXXABI::getMemberPointerInfo(const clang::MemberPointerType * MPT) Line 239 C++ clang-cpp.exe!clang::ASTContext::getTypeInfoImpl(const clang::Type * T) Line 1858 C++ clang-cpp.exe!clang::ASTContext::getTypeInfo(const clang::Type * T) Line 1657 C++ clang-cpp.exe!clang::ASTContext::getTypeInfoInChars(const clang::Type * T) Line 1609 C++ clang-cpp.exe!anonymous namespace'::MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(const clang::FieldDecl * FD) Line 2387 C++
clang-cpp.exe!anonymous namespace'::MicrosoftRecordLayoutBuilder::layoutField(const clang::FieldDecl * FD) Line 2646 C++ clang-cpp.exe!anonymous namespace'::MicrosoftRecordLayoutBuilder::layoutFields(const clang::RecordDecl * RD) Line 2636 C++
clang-cpp.exe!anonymous namespace'::MicrosoftRecordLayoutBuilder::cxxLayout(const clang::CXXRecordDecl * RD) Line 2439 C++ clang-cpp.exe!clang::ASTContext::getASTRecordLayout(const clang::RecordDecl * D) Line 2980 C++ clang-cpp.exe!anonymous namespace'::CGRecordLowering::CGRecordLowering(clang::CodeGen::CodeGenTypes & Types, const clang::RecordDecl * D, bool Packed) Line 221 C++
clang-cpp.exe!clang::CodeGen::CodeGenTypes::ComputeRecordLayout(const clang::RecordDecl * D, llvm::StructType * Ty) Line 726 C++
clang-cpp.exe!clang::CodeGen::CodeGenTypes::ConvertRecordDeclType(const clang::RecordDecl * RD) Line 710 C++
clang-cpp.exe!clang::CodeGen::CodeGenTypes::ConvertRecordDeclType(const clang::RecordDecl * RD) Line 706 C++
clang-cpp.exe!clang::CodeGen::CodeGenTypes::getCGRecordLayout(const clang::RecordDecl * RD) Line 743 C++
clang-cpp.exe!clang::CodeGen::CodeGenTypes::isZeroInitializable(const clang::RecordDecl * RD) Line 784 C++
clang-cpp.exe!clang::CodeGen::CodeGenTypes::isZeroInitializable(clang::QualType T) Line 772 C++
clang-cpp.exe!clang::CodeGen::CodeGenModule::EmitNullConstant(clang::QualType T) Line 2103 C++
clang-cpp.exe!clang::CodeGen::ConstantEmitter::tryEmitPrivateForVarInit(const clang::VarDecl & D) Line 1406 C++
clang-cpp.exe!clang::CodeGen::ConstantEmitter::tryEmitForInitializer(const clang::VarDecl & D) Line 1191 C++
clang-cpp.exe!clang::CodeGen::CodeGenModule::EmitGlobalVarDefinition(const clang::VarDecl * D, bool IsTentative) Line 3156 C++
clang-cpp.exe!clang::CodeGen::CodeGenModule::EmitGlobalDefinition(clang::GlobalDecl GD, llvm::GlobalValue * GV) Line 2304 C++
clang-cpp.exe!clang::CodeGen::CodeGenModule::EmitGlobal(clang::GlobalDecl GD) Line 2077 C++
clang-cpp.exe!clang::CodeGen::CodeGenModule::EmitTopLevelDecl(clang::Decl * D) Line 4393 C++
clang-cpp.exe!`anonymous namespace'::CodeGeneratorImpl::HandleTopLevelDecl(clang::DeclGroupRef DG) Line 160 C++
clang-cpp.exe!clang::BackendConsumer::HandleTopLevelDecl(clang::DeclGroupRef D) Line 168 C++
clang-cpp.exe!clang::ParseAST(clang::Sema & S, bool PrintStats, bool SkipFunctionBodies) Line 156 C++
clang-cpp.exe!clang::ASTFrontendAction::ExecuteAction() Line 1005 C++
clang-cpp.exe!clang::CodeGenAction::ExecuteAction() Line 1044 C++
clang-cpp.exe!clang::FrontendAction::Execute() Line 904 C++
clang-cpp.exe!clang::CompilerInstance::ExecuteAction(clang::FrontendAction & Act) Line 990 C++
clang-cpp.exe!clang::ExecuteCompilerInvocation(clang::CompilerInstance * Clang) Line 255 C++
clang-cpp.exe!cc1_main(llvm::ArrayRef<char const *> Argv, const char * Argv0, void * MainAddr) Line 222 C++
clang-cpp.exe!ExecuteCC1Tool(llvm::ArrayRef<char const *> argv, llvm::StringRef Tool) Line 310 C++
clang-cpp.exe!main(int argc_, const char * * argv_) Line 382 C++
clang-cpp.exe!invoke_main() Line 78 C++

The AST looks like this (with -ast-dump):

TranslationUnitDecl 0xc7e6ad0 <>
|-TypedefDecl 0xc7e6fe8 <> implicit __NSConstantString '__NSConstantString_tag'
| -RecordType 0xc7e6e40 '__NSConstantString_tag' | -CXXRecord 0xc7e6de0 '__NSConstantString_tag'
|-CXXRecordDecl 0xc7e7018 <> implicit class type_info
| -TypeVisibilityAttr 0xc7e7098 <<invalid sloc>> Implicit Default |-TypedefDecl 0xc7e70e0 <<invalid sloc>> <invalid sloc> implicit size_t 'unsigned int' | -BuiltinType 0xc7e6ba0 'unsigned int'
|-TypedefDecl 0xc7e7140 <> implicit __builtin_va_list 'char '
| -PointerType 0xc7e7110 'char *' | -BuiltinType 0xc7e6b20 'char'
|-ClassTemplateDecl 0xc7e7250 <test.cpp:1:1, line:5:1> line:2:7 Functor
| |-TemplateTypeParmDecl 0xc7e7170 <line:1:10, col:19> col:19 typename depth 0 index 0 ObjT
| |-CXXRecordDecl 0xc7e71f0 <line:2:1, line:5:1> line:2:7 class Functor definition
| | |-DefinitionData pass_in_registers standard_layout trivially_copyable trivial
| | | |-DefaultConstructor exists trivial needs_implicit
| | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveConstructor exists simple trivial needs_implicit
| | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveAssignment exists simple trivial needs_implicit
| | | -Destructor simple irrelevant trivial needs_implicit | | |-CXXRecordDecl 0xc7e73f8 <col:1, col:7> col:7 implicit class Functor | | -FieldDecl 0xc7e7558 <line:4:4, col:38> col:17 PtrToMemberFunction 'void (ObjT::
)() attribute((thiscall))'
| -ClassTemplateSpecializationDecl 0xe986ad0 <line:1:1, line:5:1> line:2:7 class Functor definition | |-DefinitionData pass_in_registers standard_layout trivially_copyable trivial literal | | |-DefaultConstructor exists trivial | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param | | |-MoveConstructor exists simple trivial | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param | | |-MoveAssignment exists simple trivial needs_implicit | | -Destructor simple irrelevant trivial
| |-TemplateArgument type 'DerivedFunctor'
| |-CXXRecordDecl 0xe986c40 prev 0xe986ad0 <col:1, col:7> col:7 implicit class Functor
| |-FieldDecl 0xe986d70 <line:4:4, col:38> col:17 PtrToMemberFunction 'void (DerivedFunctor::*)() attribute((thiscall))'
| |-CXXConstructorDecl 0xe986f10 line:2:7 col:7 implicit used Functor 'void () attribute((thiscall)) noexcept' inline default trivial
| | -CompoundStmt 0xe9874e0 <col:7> | |-CXXDestructorDecl 0xe986fb0 <col:7> col:7 implicit ~Functor 'void () __attribute__((thiscall))' inline default trivial noexcept-unevaluated 0xe986fb0 | |-CXXConstructorDecl 0xe987078 <col:7> col:7 implicit constexpr Functor 'void (const Functor<DerivedFunctor<void> > &) __attribute__((thiscall))' inline default trivial noexcept-unevaluated 0xe987078 | | -ParmVarDecl 0xe987138 col:7 col:7 'const Functor<DerivedFunctor > &'
| -CXXConstructorDecl 0xe987198 <col:7> col:7 implicit constexpr Functor 'void (Functor<DerivedFunctor<void> > &&) __attribute__((thiscall))' inline default trivial noexcept-unevaluated 0xe987198 | -ParmVarDecl 0xe987258 col:7 col:7 'Functor<DerivedFunctor > &&'
|-ClassTemplateDecl 0xc7e7650 <line:7:1, col:35> col:35 DerivedFunctor
| |-TemplateTypeParmDecl 0xc7e7598 <col:10, col:19> col:19 typename depth 0 index 0 SomeType
| |-CXXRecordDecl 0xc7e75f0 <col:29, col:35> col:35 class DerivedFunctor
| -ClassTemplateSpecializationDecl 0xe986840 <line:9:1, line:13:1> line:10:7 class DerivedFunctor definition | |-DefinitionData pass_in_registers standard_layout trivially_copyable trivial literal | | |-DefaultConstructor exists trivial | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param | | |-MoveConstructor exists simple trivial | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param | | |-MoveAssignment exists simple trivial needs_implicit | | -Destructor simple irrelevant trivial needs_implicit
| |-public 'Functor<DerivedFunctor >':'Functor<DerivedFunctor >'
| |-TemplateArgument type 'void'
| |-MSInheritanceAttr 0xe986d40 <line:9:1, line:13:1> Implicit __single_inheritance BestCase
| |-CXXRecordDecl 0xe986de0 prev 0xe986840 <line:10:1, col:7> col:7 implicit class DerivedFunctor
| |-CXXConstructorDecl 0xe986e60 col:7 col:7 implicit used DerivedFunctor 'void () attribute((thiscall)) noexcept' inline default trivial
| | |-CXXCtorInitializer 'Functor<DerivedFunctor >':'Functor<DerivedFunctor >'
| | | -CXXConstructExpr 0xe9874f0 <col:7> 'Functor<DerivedFunctor<void> >':'Functor<DerivedFunctor<void> >' 'void () __attribute__((thiscall)) noexcept' | | -CompoundStmt 0xe987590 col:7
| |-CXXConstructorDecl 0xe987298 col:7 col:7 implicit constexpr DerivedFunctor 'void (const DerivedFunctor &) attribute((thiscall))' inline default trivial noexcept-unevaluated 0xe987298
| | -ParmVarDecl 0xe987358 <col:7> col:7 'const DerivedFunctor<void> &' | -CXXConstructorDecl 0xe9873b8 col:7 col:7 implicit constexpr DerivedFunctor 'void (DerivedFunctor &&) attribute((thiscall))' inline default trivial noexcept-unevaluated 0xe9873b8
| -ParmVarDecl 0xe987478 <col:7> col:7 'DerivedFunctor<void> &&' |-ClassTemplateDecl 0xc7e7860 prev 0xc7e7650 <line:9:1, line:13:1> line:10:7 DerivedFunctor | |-TemplateTypeParmDecl 0xc7e77a8 <line:9:10, col:19> col:19 referenced typename depth 0 index 0 SomeType | |-CXXRecordDecl 0xc7e7800 prev 0xc7e75f0 <line:10:1, line:13:1> line:10:7 class DerivedFunctor definition | | |-DefinitionData pass_in_registers empty standard_layout trivially_copyable trivial literal has_constexpr_non_copy_move_ctor can_const_default_init | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param | | | |-MoveConstructor exists simple trivial needs_implicit | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param | | | |-MoveAssignment exists simple trivial needs_implicit | | | -Destructor simple irrelevant trivial needs_implicit
| | |-public 'Functor<DerivedFunctor >'
| | -CXXRecordDecl 0xe9867c0 <col:1, col:7> col:7 implicit class DerivedFunctor | -ClassTemplateSpecialization 0xe986840 'DerivedFunctor'
-VarDecl 0xe986988 <line:15:1, col:22> col:22 AFunctor 'DerivedFunctor<void>':'DerivedFunctor<void>' callinit -CXXConstructExpr 0xe9875a0 col:22 'DerivedFunctor':'DerivedFunctor' 'void () attribute((thiscall)) noexcept'

The problem occurs because assignInheritanceModel() is called on the "class DerivedFunctor" CXXRecordDecl, when it is the RD returned by MPTy->getMostRecentCXXRecordDecl():

clang-cpp.exe!assignInheritanceModel(clang::Sema & S, clang::CXXRecordDecl * RD) Line 7544 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7591 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID) Line 7750 C++
clang-cpp.exe!clang::Sema::CheckFieldDecl(clang::DeclarationName Name, clang::QualType T, clang::TypeSourceInfo * TInfo, clang::RecordDecl * Record, clang::SourceLocation Loc, bool Mutable, clang::Expr * BitWidth, clang::InClassInitStyle InitStyle, clang::SourceLocation TSSL, clang::AccessSpecifier AS, clang::NamedDecl * PrevDecl, clang::Declarator * D) Line 14886 C++
clang-cpp.exe!clang::TemplateDeclInstantiator::VisitFieldDecl(clang::FieldDecl * D) Line 804 C++
clang-cpp.exe!clang::declvisitor::Base<clang::declvisitor::make_ptr,clang::TemplateDeclInstantiator,clang::Decl *>::Visit(clang::Decl * D) Line 369 C++
clang-cpp.exe!clang::Sema::InstantiateClass(clang::SourceLocation PointOfInstantiation, clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs, clang::TemplateSpecializationKind TSK, bool Complain) Line 2091 C++
clang-cpp.exe!clang::Sema::InstantiateClassTemplateSpecialization(clang::SourceLocation PointOfInstantiation, clang::ClassTemplateSpecializationDecl * ClassTemplateSpec, clang::TemplateSpecializationKind TSK, bool Complain) Line 2542 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7683 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeclang::SourceRange(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID, const clang::SourceRange & <Args_0>) Line 1616 C++
clang-cpp.exe!clang::Sema::CheckBaseSpecifier(clang::CXXRecordDecl * Class, clang::SourceRange SpecifierRange, bool Virtual, clang::AccessSpecifier Access, clang::TypeSourceInfo * TInfo, clang::SourceLocation EllipsisLoc) Line 2220 C++
clang-cpp.exe!clang::Sema::SubstBaseSpecifiers(clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs) Line 1950 C++
clang-cpp.exe!clang::Sema::InstantiateClass(clang::SourceLocation PointOfInstantiation, clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs, clang::TemplateSpecializationKind TSK, bool Complain) Line 2064 C++
clang-cpp.exe!clang::Sema::InstantiateClassTemplateSpecialization(clang::SourceLocation PointOfInstantiation, clang::ClassTemplateSpecializationDecl * ClassTemplateSpec, clang::TemplateSpecializationKind TSK, bool Complain) Line 2542 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7683 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID) Line 7750 C++
clang-cpp.exe!clang::Sema::ActOnUninitializedDecl(clang::Decl * RealDecl) Line 11197 C++
clang-cpp.exe!clang::Parser::ParseDeclarationAfterDeclaratorAndAttributes(clang::Declarator & D, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::Parser::ForRangeInit * FRI) Line 2372 C++
clang-cpp.exe!clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec & DS, clang::DeclaratorContext Context, clang::SourceLocation * DeclEnd, clang::Parser::ForRangeInit * FRI) Line 2042 C++
clang-cpp.exe!clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec & DS, clang::AccessSpecifier AS) Line 1012 C++
clang-cpp.exe!clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS, clang::AccessSpecifier AS) Line 1028 C++
clang-cpp.exe!clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS) Line 853 C++
clang-cpp.exe!clang::Parser::ParseTopLevelDecl(clang::OpaquePtrclang::DeclGroupRef & Result) Line 609 C++
clang-cpp.exe!clang::ParseAST(clang::Sema & S, bool PrintStats, bool SkipFunctionBodies) Line 152 C++
clang-cpp.exe!clang::ASTFrontendAction::ExecuteAction() Line 1005 C++
clang-cpp.exe!clang::CodeGenAction::ExecuteAction() Line 1044 C++
clang-cpp.exe!clang::FrontendAction::Execute() Line 904 C++
clang-cpp.exe!clang::CompilerInstance::ExecuteAction(clang::FrontendAction & Act) Line 990 C++
clang-cpp.exe!clang::ExecuteCompilerInvocation(clang::CompilerInstance * Clang) Line 255 C++
clang-cpp.exe!cc1_main(llvm::ArrayRef<char const *> Argv, const char * Argv0, void * MainAddr) Line 222 C++
clang-cpp.exe!ExecuteCC1Tool(llvm::ArrayRef<char const *> argv, llvm::StringRef Tool) Line 310 C++

but then the "implicit class DerivedFunctor" CXXRecordDecl is added as the 'latest' decl (returned by MPTy->getMostRecentCXXRecordDecl()), as the template is instantiated:

clang-cpp.exe!llvm::PointerIntPair<void *,1,bool,llvm::PointerUnionUIntTraits<llvm::PointerUnion<clang::Decl *,void const *>,clang::LazyGenerationalUpdatePtr<clang::Decl const *,clang::Decl *,{clang::ExternalASTSource::vcall'{60}',0}> >,llvm::PointerIntPairInfo<void *,1,llvm::PointerUnionUIntTraits<llvm::PointerUnion<clang::Decl *,void const *>,clang::LazyGenerationalUpdatePtr<clang::Decl const *,clang::Decl *,{clang::ExternalASTSource::vcall'{60}',0}> > > >::setPointerAndInt(void * PtrVal, bool IntVal) Line 75 C++
clang-cpp.exe!llvm::PointerUnion<llvm::PointerUnion<clang::Decl *,void const *>,clang::LazyGenerationalUpdatePtr<clang::Decl const *,clang::Decl *,{clang::ExternalASTSource::vcall'{60}',0}> >::operator=(const clang::LazyGenerationalUpdatePtr<clang::Decl const *,clang::Decl *,{clang::ExternalASTSource::vcall'{60}',0}> & RHS) Line 182 C++
clang-cpp.exe!clang::Redeclarableclang::TagDecl::DeclLink::setLatest(clang::TagDecl * D) Line 159 C++
clang-cpp.exe!clang::Redeclarableclang::TagDecl::setPreviousDecl(clang::TagDecl * PrevDecl) Line 4285 C++
clang-cpp.exe!clang::TagDecl::TagDecl(clang::Decl::Kind DK, clang::TagTypeKind TK, const clang::ASTContext & C, clang::DeclContext * DC, clang::SourceLocation L, clang::IdentifierInfo * Id, clang::TagDecl * PrevDecl, clang::SourceLocation StartL) Line 3093 C++
clang-cpp.exe!clang::RecordDecl::RecordDecl(clang::Decl::Kind DK, clang::TagTypeKind TK, const clang::ASTContext & C, clang::DeclContext * DC, clang::SourceLocation StartLoc, clang::SourceLocation IdLoc, clang::IdentifierInfo * Id, clang::RecordDecl * PrevDecl) Line 3968 C++
clang-cpp.exe!clang::CXXRecordDecl::CXXRecordDecl(clang::Decl::Kind K, clang::TagTypeKind TK, const clang::ASTContext & C, clang::DeclContext * DC, clang::SourceLocation StartLoc, clang::SourceLocation IdLoc, clang::IdentifierInfo * Id, clang::CXXRecordDecl * PrevDecl) Line 122 C++
clang-cpp.exe!clang::CXXRecordDecl::Create(const clang::ASTContext & C, clang::TagTypeKind TK, clang::DeclContext * DC, clang::SourceLocation StartLoc, clang::SourceLocation IdLoc, clang::IdentifierInfo * Id, clang::CXXRecordDecl * PrevDecl, bool DelayTypeCreation) Line 129 C++
clang-cpp.exe!clang::TemplateDeclInstantiator::VisitCXXRecordDecl(clang::CXXRecordDecl * D) Line 1489 C++
clang-cpp.exe!clang::declvisitor::Base<clang::declvisitor::make_ptr,clang::TemplateDeclInstantiator,clang::Decl *>::Visit(clang::Decl * D) Line 251 C++
clang-cpp.exe!clang::Sema::InstantiateClass(clang::SourceLocation PointOfInstantiation, clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs, clang::TemplateSpecializationKind TSK, bool Complain) Line 2091 C++
clang-cpp.exe!clang::Sema::InstantiateClassTemplateSpecialization(clang::SourceLocation PointOfInstantiation, clang::ClassTemplateSpecializationDecl * ClassTemplateSpec, clang::TemplateSpecializationKind TSK, bool Complain) Line 2542 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7683 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID) Line 7750 C++
clang-cpp.exe!clang::Sema::ActOnUninitializedDecl(clang::Decl * RealDecl) Line 11197 C++
clang-cpp.exe!clang::Parser::ParseDeclarationAfterDeclaratorAndAttributes(clang::Declarator & D, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::Parser::ForRangeInit * FRI) Line 2372 C++
clang-cpp.exe!clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec & DS, clang::DeclaratorContext Context, clang::SourceLocation * DeclEnd, clang::Parser::ForRangeInit * FRI) Line 2042 C++
clang-cpp.exe!clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec & DS, clang::AccessSpecifier AS) Line 1012 C++
clang-cpp.exe!clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS, clang::AccessSpecifier AS) Line 1028 C++
clang-cpp.exe!clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS) Line 853 C++
clang-cpp.exe!clang::Parser::ParseTopLevelDecl(clang::OpaquePtrclang::DeclGroupRef & Result) Line 609 C++
clang-cpp.exe!clang::ParseAST(clang::Sema & S, bool PrintStats, bool SkipFunctionBodies) Line 152 C++
clang-cpp.exe!clang::ASTFrontendAction::ExecuteAction() Line 1005 C++
clang-cpp.exe!clang::CodeGenAction::ExecuteAction() Line 1044 C++
clang-cpp.exe!clang::FrontendAction::Execute() Line 904 C++
clang-cpp.exe!clang::CompilerInstance::ExecuteAction(clang::FrontendAction & Act) Line 990 C++
clang-cpp.exe!clang::ExecuteCompilerInvocation(clang::CompilerInstance * Clang) Line 255 C++
clang-cpp.exe!cc1_main(llvm::ArrayRef<char const *> Argv, const char * Argv0, void * MainAddr) Line 222 C++
clang-cpp.exe!ExecuteCC1Tool(llvm::ArrayRef<char const *> argv, llvm::StringRef Tool) Line 310 C++

Since the "implicit class DerivedFunctor" CXXRecordDecl doesn't have a MSInheritanceAttr (but the "class DerivedFunctor" CXXRecordDecl does), when the "implicit class DerivedFunctor" CXXRecordDecl is later selected by MPTy->getMostRecentCXXRecordDecl() no MSInheritanceAttr can be found.

I debugged this and TemplateDeclInstantiator::VisitCXXRecordDecl() looks like an ideal place to move information forward from the "class DerivedFunctor" CXXRecordDecl to the "implicit class DerivedFunctor" CXXRecordDecl. I have created a fix which calls back into the semantic analysis code and check if the previous decl has a MSInheritanceAttr, and if so to just add a MSInheritanceAttr to the new decl being created.

clang-cpp.exe!clang::Sema::CheckCXXRecordDecl(clang::CXXRecordDecl * Record, clang::CXXRecordDecl * Prev) Line 7083 C++
clang-cpp.exe!clang::TemplateDeclInstantiator::VisitCXXRecordDecl(clang::CXXRecordDecl * D) Line 1556 C++
clang-cpp.exe!clang::declvisitor::Base<clang::declvisitor::make_ptr,clang::TemplateDeclInstantiator,clang::Decl *>::Visit(clang::Decl * D) Line 251 C++
clang-cpp.exe!clang::Sema::InstantiateClass(clang::SourceLocation PointOfInstantiation, clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs, clang::TemplateSpecializationKind TSK, bool Complain) Line 2091 C++
clang-cpp.exe!clang::Sema::InstantiateClassTemplateSpecialization(clang::SourceLocation PointOfInstantiation, clang::ClassTemplateSpecializationDecl * ClassTemplateSpec, clang::TemplateSpecializationKind TSK, bool Complain) Line 2542 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7683 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID) Line 7750 C++
clang-cpp.exe!clang::Sema::ActOnUninitializedDecl(clang::Decl * RealDecl) Line 11197 C++
clang-cpp.exe!clang::Parser::ParseDeclarationAfterDeclaratorAndAttributes(clang::Declarator & D, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::Parser::ForRangeInit * FRI) Line 2372 C++
clang-cpp.exe!clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec & DS, clang::DeclaratorContext Context, clang::SourceLocation * DeclEnd, clang::Parser::ForRangeInit * FRI) Line 2042 C++
clang-cpp.exe!clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec & DS, clang::AccessSpecifier AS) Line 1012 C++
clang-cpp.exe!clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS, clang::AccessSpecifier AS) Line 1028 C++
clang-cpp.exe!clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS) Line 853 C++
clang-cpp.exe!clang::Parser::ParseTopLevelDecl(clang::OpaquePtrclang::DeclGroupRef & Result) Line 609 C++
clang-cpp.exe!clang::ParseAST(clang::Sema & S, bool PrintStats, bool SkipFunctionBodies) Line 152 C++
clang-cpp.exe!clang::ASTFrontendAction::ExecuteAction() Line 1005 C++
clang-cpp.exe!clang::CodeGenAction::ExecuteAction() Line 1044 C++
clang-cpp.exe!clang::FrontendAction::Execute() Line 904 C++
clang-cpp.exe!clang::CompilerInstance::ExecuteAction(clang::FrontendAction & Act) Line 990 C++
clang-cpp.exe!clang::ExecuteCompilerInvocation(clang::CompilerInstance * Clang) Line 255 C++
clang-cpp.exe!cc1_main(llvm::ArrayRef<char const *> Argv, const char * Argv0, void * MainAddr) Line 222 C++
clang-cpp.exe!ExecuteCC1Tool(llvm::ArrayRef<char const *> argv, llvm::StringRef Tool) Line 310 C++

This fix resolves this crash, which was hit over multiple different source files in some code I'mm porting to build with clang / MS ABI.

@rnk
Copy link
Collaborator

rnk commented May 9, 2018

The way that I would've expected this to work is for assignInheritanceModel to apply the attribute to the most recent declaration, and every re-declaration of the class would naturally inherit the attribute. I think most attributes are inherited by redeclarations, and this should be no different.


Was this a recent regression? CRTP with member function pointers is nothing new. I vaguely recall making sure this pattern worked in the past.

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 9, 2018

We hit this in the v6.0.0 binary release of clange/LLVM for Win32 - I haven't tried to reproduce with older versions.

I am a clang newbie - and will have to look more at how attributes are inherited...

Thanks, Andrew R

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 9, 2018

I've done some archaeology using the binary releases - it appears this was introduced between 3.7.1 and 3.8.0:

C:\Temp\clang\clang>\llvm-3.7\bin\clang-cl.exe -cc1 -emit-llvm-only -x c++ -v test.cpp
clang -cc1 version 3.7.0 based upon LLVM 3.7.0 default target i686-pc-windows-gnu
#include "..." search starts here:
End of search list.

C:\Temp\clang\clang>\llvm-3.7.1\bin\clang-cl.exe -cc1 -emit-llvm-only -x c++ -v test.cpp
clang -cc1 version 3.7.1 based upon LLVM 3.7.1 default target i686-pc-windows-gnu
#include "..." search starts here:
End of search list.

C:\Temp\clang\clang>\llvm-3.8\bin\clang-cl.exe -cc1 -emit-llvm-only -x c++ -v test.cpp
clang -cc1 version 3.8.0 based upon LLVM 3.8.0 default target i686-pc-windows-msvc
#include "..." search starts here:
End of search list.
Assertion failed: IA && "Expected MSInheritanceAttr on the CXXRecordDecl!", file D:\src\llvm_package_3.8.0-final\llvm\tools\clang\lib\AST\MicrosoftCXXABI.cpp, line 182
0x01EEEC08 (0x00000016 0x03860B62 0x00BA31A0 0x00B1BA98)
0x0386601E (0x0436C7E8 0x0436C74E 0x000000B6 0x00B74268)
0x035D54B1 (0x00000567 0x000004E7 0x00B74310 0x00B74374)
0x035D591E (0x0538D370 0x00BA31A0 0x00002000 0x00B10000)
0x034C372A (0x0538D3F8 0x00BA31A0 0x00B6B170 0x00000000)
0x034C2E7E (0x0538D450 0x00BA31A0 0x00BCA468 0x0538D92C)
0x034C2B18 (0x0538D4E0 0x00BA31A0 0x00000200 0x00000000)
0x035989F2 (0x00BA3210 0x00B6D4F8 0x00000070 0x0538DAB0)
0x03597943 (0x0538D948 0x00000020 0x00000000 0x00BA66C4)
0x0359147B (0x00BA2F90 0x0000000D 0x0000001D 0x00000000)
0x022DA762 (0x00BA2F90 0x00B69EE8 0x0388B354 0x00000000)

Thanks, Andrew R

@majnemer
Copy link
Mannequin

majnemer mannequin commented May 10, 2018

Adding my 2c here: I'd have thought that calculateInheritanceModel() handles this case by checking isParsingBaseSpecifiers().

@rnk
Copy link
Collaborator

rnk commented May 11, 2018

I think what's going on here is that the injected class name CXXRecordDecl redeclaration doesn't inherit most attributes. I'm not yet sure where that gets created, but we might want to skip injected class names when we assign inheritance and look it up if it doesn't copy attributes from previous declarations.

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 11, 2018

Hi Reid,

You're right - the key issue here is that in this case the injected-class-name is added into the decl list (clang::Redeclarableclang::TagDecl) for the DerivedFunctor after we've called assignInheritanceModel() during parsing of PtrToMemberFunction.

I took a look at how the following (roughly equivalent) non-template code is compiled:

class Foo;

class Functor
{
void (Foo::*PtrToMemberFunction)();
};

class Bar
{
};

class Foo
: public Functor, public Bar
{
};

Foo AFunctor;

In it, the injected-class-name is still created after we've called assignInheritanceModel() during parsing of PtrToMemberFunction, but it isn't added into the decl list (clang::Redeclarableclang::TagDecl) for the class Foo. In particular, this is because when not instantiating class templates, the PrevDecl passed to create the CXXRecordDecl for an injected-class-name is nullptr (c.f. below from Sema::ActOnStartCXXMemberDeclarations()):

// C++ [class]p2:
// [...] The class-name is also inserted into the scope of the
// class itself; this is known as the injected-class-name. For
// purposes of access checking, the injected-class-name is treated
// as if it were a public member name.
CXXRecordDecl *InjectedClassName
= CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext,
Record->getLocStart(), Record->getLocation(),
Record->getIdentifier(),
/PrevDecl=/nullptr,
/DelayTypeCreation=/true);

This compares with the following code in TemplateDeclInstantiator::VisitCXXRecordDecl(), which creates both the class declarations and the injected-class-name:

CXXRecordDecl *PrevDecl = nullptr;
if (D->isInjectedClassName())
PrevDecl = cast(Owner);
else if (CXXRecordDecl *PatternPrev = getPreviousDeclForInstantiation(D)) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
PatternPrev,
TemplateArgs);
if (!Prev) return nullptr;
PrevDecl = cast(Prev);
}

CXXRecordDecl *Record
= CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
D->getLocStart(), D->getLocation(),
D->getIdentifier(), PrevDecl);

I have briefly experimented with changing the first couple lines to:

CXXRecordDecl *PrevDecl;
if (D->isInjectedClassName())
PrevDecl = nullptr;
else
...

so that the injected-class-name for a class template instantiation isn't linked into the decl list for the instantiated class type and this then prevents the issue I reported happening and gives the injected-class-name for a class template instantiation similar semantics to the injected-class-name for a normal class - it also seems like a cleaner fix.

I haven't had chance to run a broader test suite yet, but do you think this makes sense as a route to fixing this problem?

Thanks, Andrew R

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 11, 2018

To respond to David's point about isParsingBaseSpecifiers(), it should be noted that isParsingBaseSpecifiers() is only true during a call to Parser::ParseBaseClause(), with:

ParseBaseClause() -> ParseBaseSpecifier() -> Sema::ActOnBaseSpecifier() -> CXXRecordDecl::setIsParsingBaseSpecifiers()

setting isParsingBaseSpecifiers() to true and:

ParseBaseClause() -> Sema::ActOnBaseSpecifiers() -> AttachBaseSpecifiers() -> CXXRecordDecl::setBases()

setting isParsingBaseSpecifiers() back to false.

Parser::ParseBaseClause() is called as the template declaration is parsed:

clang-cpp.exe!clang::Parser::ParseBaseClause(clang::Decl * ClassDecl) Line 2016	C++
clang-cpp.exe!clang::Parser::ParseCXXMemberSpecification(clang::SourceLocation RecordLoc, clang::SourceLocation AttrFixitLoc, clang::Parser::ParsedAttributesWithRange & Attrs, unsigned int TagType, clang::Decl * TagDecl) Line 3205	C++
clang-cpp.exe!clang::Parser::ParseClassSpecifier(clang::tok::TokenKind TagTokKind, clang::SourceLocation StartLoc, clang::DeclSpec & DS, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::AccessSpecifier AS, bool EnteringContext, clang::Parser::DeclSpecContext DSC, clang::Parser::ParsedAttributesWithRange & Attributes) Line 1916	C++
clang-cpp.exe!clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec & DS, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::AccessSpecifier AS, clang::Parser::DeclSpecContext DSContext, clang::Parser::LateParsedAttrList * LateAttrs) Line 3674	C++
clang-cpp.exe!clang::Parser::ParseSingleDeclarationAfterTemplate(clang::DeclaratorContext Context, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::ParsingDeclRAIIObject & DiagsFromTParams, clang::SourceLocation & DeclEnd, clang::AccessSpecifier AS, clang::AttributeList * AccessAttrs) Line 214	C++
clang-cpp.exe!clang::Parser::ParseTemplateDeclarationOrSpecialization(clang::DeclaratorContext Context, clang::SourceLocation & DeclEnd, clang::AccessSpecifier AS, clang::AttributeList * AccessAttrs) Line 152	C++
clang-cpp.exe!clang::Parser::ParseDeclarationStartingWithTemplate(clang::DeclaratorContext Context, clang::SourceLocation & DeclEnd, clang::AccessSpecifier AS, clang::AttributeList * AccessAttrs) Line 38	C++
clang-cpp.exe!clang::Parser::ParseDeclaration(clang::DeclaratorContext Context, clang::SourceLocation & DeclEnd, clang::Parser::ParsedAttributesWithRange & attrs) Line 1685	C++
clang-cpp.exe!clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS) Line 786	C++
clang-cpp.exe!clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef> & Result) Line 609	C++
clang-cpp.exe!clang::ParseAST(clang::Sema & S, bool PrintStats, bool SkipFunctionBodies) Line 152	C++
clang-cpp.exe!clang::ASTFrontendAction::ExecuteAction() Line 1005	C++
clang-cpp.exe!clang::CodeGenAction::ExecuteAction() Line 1044	C++
clang-cpp.exe!clang::FrontendAction::Execute() Line 904	C++
clang-cpp.exe!clang::CompilerInstance::ExecuteAction(clang::FrontendAction & Act) Line 990	C++
clang-cpp.exe!clang::ExecuteCompilerInvocation(clang::CompilerInstance * Clang) Line 255	C++
clang-cpp.exe!cc1_main(llvm::ArrayRef<char const *> Argv, const char * Argv0, void * MainAddr) Line 222	C++

and well before assignInheritanceModel() is called, during the parsing of the declaration of AFunctor, which causes the implicit instantiation of DerivedFunctor:

RD = class DerivedFunctor
clang-cpp.exe!assignInheritanceModel(clang::Sema & S, clang::CXXRecordDecl * RD) Line 7544 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7591 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID) Line 7750 C++
clang-cpp.exe!clang::Sema::CheckFieldDecl(clang::DeclarationName Name, clang::QualType T, clang::TypeSourceInfo * TInfo, clang::RecordDecl * Record, clang::SourceLocation Loc, bool Mutable, clang::Expr * BitWidth, clang::InClassInitStyle InitStyle, clang::SourceLocation TSSL, clang::AccessSpecifier AS, clang::NamedDecl * PrevDecl, clang::Declarator * D) Line 14886 C++
D = PtrToMemberFunction
clang-cpp.exe!clang::TemplateDeclInstantiator::VisitFieldDecl(clang::FieldDecl * D) Line 804 C++
clang-cpp.exe!clang::declvisitor::Base<clang::declvisitor::make_ptr,clang::TemplateDeclInstantiator,clang::Decl *>::Visit(clang::Decl * D) Line 369 C++
Pattern = class Functor
Instantiation = class Functor<DerivedFunctor >
clang-cpp.exe!clang::Sema::InstantiateClass(clang::SourceLocation PointOfInstantiation, clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs, clang::TemplateSpecializationKind TSK, bool Complain) Line 2091 C++
clang-cpp.exe!clang::Sema::InstantiateClassTemplateSpecialization(clang::SourceLocation PointOfInstantiation, clang::ClassTemplateSpecializationDecl * ClassTemplateSpec, clang::TemplateSpecializationKind TSK, bool Complain) Line 2542 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7683 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeclang::SourceRange(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID, const clang::SourceRange & <Args_0>) Line 1616 C++
clang-cpp.exe!clang::Sema::CheckBaseSpecifier(clang::CXXRecordDecl * Class, clang::SourceRange SpecifierRange, bool Virtual, clang::AccessSpecifier Access, clang::TypeSourceInfo * TInfo, clang::SourceLocation EllipsisLoc) Line 2220 C++
clang-cpp.exe!clang::Sema::SubstBaseSpecifiers(clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs) Line 1950 C++
Pattern = class DerivedFunctor
Instantiation = class DerivedFunctor
clang-cpp.exe!clang::Sema::InstantiateClass(clang::SourceLocation PointOfInstantiation, clang::CXXRecordDecl * Instantiation, clang::CXXRecordDecl * Pattern, const clang::MultiLevelTemplateArgumentList & TemplateArgs, clang::TemplateSpecializationKind TSK, bool Complain) Line 2064 C++
clang-cpp.exe!clang::Sema::InstantiateClassTemplateSpecialization(clang::SourceLocation PointOfInstantiation, clang::ClassTemplateSpecializationDecl * ClassTemplateSpec, clang::TemplateSpecializationKind TSK, bool Complain) Line 2542 C++
clang-cpp.exe!clang::Sema::RequireCompleteTypeImpl(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser * Diagnoser) Line 7683 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, clang::Sema::TypeDiagnoser & Diagnoser) Line 7449 C++
clang-cpp.exe!clang::Sema::RequireCompleteType(clang::SourceLocation Loc, clang::QualType T, unsigned int DiagID) Line 7750 C++
clang-cpp.exe!clang::Sema::ActOnUninitializedDecl(clang::Decl * RealDecl) Line 11197 C++
D = AFunctor
clang-cpp.exe!clang::Parser::ParseDeclarationAfterDeclaratorAndAttributes(clang::Declarator & D, const clang::Parser::ParsedTemplateInfo & TemplateInfo, clang::Parser::ForRangeInit * FRI) Line 2372 C++
clang-cpp.exe!clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec & DS, clang::DeclaratorContext Context, clang::SourceLocation * DeclEnd, clang::Parser::ForRangeInit * FRI) Line 2042 C++
clang-cpp.exe!clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec & DS, clang::AccessSpecifier AS) Line 1012 C++
clang-cpp.exe!clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS, clang::AccessSpecifier AS) Line 1028 C++
clang-cpp.exe!clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange & attrs, clang::ParsingDeclSpec * DS) Line 853 C++
clang-cpp.exe!clang::Parser::ParseTopLevelDecl(clang::OpaquePtrclang::DeclGroupRef & Result) Line 609 C++
clang-cpp.exe!clang::ParseAST(clang::Sema & S, bool PrintStats, bool SkipFunctionBodies) Line 152 C++
clang-cpp.exe!clang::ASTFrontendAction::ExecuteAction() Line 1005 C++
clang-cpp.exe!clang::CodeGenAction::ExecuteAction() Line 1044 C++
clang-cpp.exe!clang::FrontendAction::Execute() Line 904 C++
clang-cpp.exe!clang::CompilerInstance::ExecuteAction(clang::FrontendAction & Act) Line 990 C++
clang-cpp.exe!clang::ExecuteCompilerInvocation(clang::CompilerInstance * Clang) Line 255 C++
clang-cpp.exe!cc1_main(llvm::ArrayRef<char const *> Argv, const char * Argv0, void * MainAddr) Line 222 C++

Therefore, since the template declaration (including its base sepcifiers) is parsed well before the declaration which triggers the template instantiation (and template instantiation does not trigger further parsing of base specifiers), isParsingBaseSpecifiers() isn't of any use in this situation.

Thanks, Andrew R

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 11, 2018

Hi Reid,

I'm still finding my feet, so apologies here...

I've worked out how to run the SemaTemplate tests and they make clear that the idea of changing the injected-class-name for the template instantiation to have a nullptr PrevDecl isn't a good idea (causes 43/225 tests to fail!).

The good news is that the original fix I suggested doesn't cause any test regressions - though I agree the naming could be improved...

Since the injected-class-name is a special case where PrevDecl is Owner, rather than found via using the pattern from getPreviousDeclForInstantiation(D), how about restricting the call to just injected-class-name decls and renaming to e.g:

if (D->isInjectedClassName())
SemaRef.CheckTemplateInstantiationInjectedClassNameDecl(Record, PrevDecl);

[that's now a lot more accurate, but a bit of a mouth full!]

This change then still fixes my original problem and causes no regressions in the 225 SemaTemplate tests - what do you think?

If you are happy, I will rebase and update with a patch containing this new naming.

Thanks, Andrew R

@rnk
Copy link
Collaborator

rnk commented May 18, 2018

I think there's two ways to go on this issue:

  1. The long term introduction of a new injected class name declaration type that isn't part of the CXXRecordDecl redeclaration chain.
  2. The short term workaround.

I think propagating the attributes to the injected class name is also a workaround, since it doesn't move towards the long term solution. If we're going to have a workaround, I think we should introduce a new CXXRecordDecl::getMostNonInjectedDecl method that gets the most recent non-injected class name redeclaration, and then we'll use that instead when we apply implicit attributes and look for inheritance attributes.

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 21, 2018

Attempt to use non-injected name decl
This patch attempts to fix the original bug using the strategy Reid suggested of always going to the non-inject name decl when assigning / querying the MS inheritance model.

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 21, 2018

Hi Reid,

As per my last comment, the patch attached will fix the original problem I reported, I hope using the strategy you envisioned.

However the following slightly expanded example:

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 21, 2018

Hi Reid,

As per the previous comment, I created a patch which attempts to make the fix you suggested of just using the non-injected name decl whenever the MS inheritance attribute is accessed or set. This patch fixes the case I originally reported.

However, the following slightly expanded example code:

template
class Functor
{
public:
void (ObjT::*PtrToMemberFunction)();
};

template class DerivedFunctor;

template
class DerivedFunctor
: public Functor<DerivedFunctor >
{
public:
void Foo() {}
};

DerivedFunctor BFunctor;

int main()
{
BFunctor.PtrToMemberFunction = &DerivedFunctor::Foo;
}

Then fails to compile:

c:\temp\clang\clang\test.cpp:22:33: error: incomplete type 'void (DerivedFunctor::*)()' is not assignable
BFunctor.PtrToMemberFunction = &DerivedFunctor::Foo;

1 error generated.

Whereas this code compiles cleanly on clang trunk on linux, c.f.: https://godbolt.org/g/nCeXvB

I haven't had time to investigate this yet (so could be a bug in the patch I just attached!), but this code did compile cleanly with the original patch which propagated the attribute to the injected class name did compile this code OK...

Thanks, Andrew R

@llvmbot
Copy link
Collaborator Author

llvmbot commented May 22, 2018

Hi Reid,

I found I'd missed one case in Type::isIncompleteType(). Adding it fixed the code I quoted and all clang tests passed with this patch.

I've put the new patch on https://reviews.llvm.org/D46664.

Thanks, Andrew R

@llvmbot
Copy link
Collaborator Author

llvmbot commented Jun 1, 2018

Fixed by rC333680:

https://reviews.llvm.org/rC333680.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla clang:frontend Language frontend issues, e.g. anything involving "Sema"
Projects
None yet
Development

No branches or pull requests

2 participants