From c5a89a1cc2f168ad0a115c560b8de5f1c952d8c5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 2 Apr 2012 01:30:27 +0000 Subject: [PATCH] Basic semantic analysis support for inheriting constructor declarations in dependent contexts. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153858 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 2 +- lib/Sema/SemaDecl.cpp | 2 +- lib/Sema/SemaDeclCXX.cpp | 24 +++++++++--------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 +++++ test/CXX/special/class.inhctor/elsewhere.cpp | 26 ++++++++++++++++++++ test/CXX/special/class.inhctor/p3.cpp | 18 ++++++++++++++ test/CXX/special/class.inhctor/p7.cpp | 13 +++++++++- 7 files changed, 76 insertions(+), 15 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 045b2fa69a..747feaab30 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2978,7 +2978,7 @@ public: bool IsTypeName, SourceLocation TypenameLoc); - bool CheckInheritedConstructorUsingDecl(UsingDecl *UD); + bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 75f7f99efb..9e193bebbe 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -118,7 +118,7 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. - if (!isClassName) + if (!isClassName && !IsCtorOrDtorName) return ParsedType(); // We know from the grammar that this name refers to a type, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5a64d09bae..c6cd9a2479 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -6290,9 +6290,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } - // Constructor inheriting using decls get special treatment. + // The normal rules do not apply to inheriting constructor declarations. if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { - if (CheckInheritedConstructorUsingDecl(UD)) + if (CheckInheritingConstructorUsingDecl(UD)) UD->setInvalidDecl(); return UD; } @@ -6362,11 +6362,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, } /// Additional checks for a using declaration referring to a constructor name. -bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) { - if (UD->isTypeName()) { - // FIXME: Cannot specify typename when specifying constructor - return true; - } +bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) { + assert(!UD->isTypeName() && "expecting a constructor name"); const Type *SourceType = UD->getQualifier()->getAsType(); assert(SourceType && @@ -6381,6 +6378,8 @@ bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) { CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified(); if (CanonicalSourceType == BaseType) break; + if (BaseIt->getType()->isDependentType()) + break; } if (BaseIt == BaseE) { @@ -6392,7 +6391,8 @@ bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) { return true; } - BaseIt->setInheritConstructors(); + if (!CurContext->isDependentContext()) + BaseIt->setInheritConstructors(); return false; } @@ -7041,7 +7041,6 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { Context.getCanonicalType(CtorIt->getType()).getTypePtr()); } - Scope *S = getScopeForContext(ClassDecl); DeclarationName CreatedCtorName = Context.DeclarationNames.getCXXConstructorName( ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified()); @@ -7063,10 +7062,12 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { CtorE = BaseDecl->ctor_end(); CtorIt != CtorE; ++CtorIt) { // Find the using declaration for inheriting this base's constructors. + // FIXME: Don't perform name lookup just to obtain a source location! DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(CanonicalBase); - UsingDecl *UD = dyn_cast_or_null( - LookupSingleName(S, Name,SourceLocation(), LookupUsingDeclName)); + LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName); + LookupQualifiedName(Result, CurContext); + UsingDecl *UD = Result.getAsSingle(); SourceLocation UsingLoc = UD ? UD->getLocation() : ClassDecl->getLocation(); @@ -7177,7 +7178,6 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { NewCtor->setParams(ParamDecls); NewCtor->setInheritedConstructor(BaseCtor); - PushOnScopeChains(NewCtor, S, false); ClassDecl->addDecl(NewCtor); result.first->second.second = NewCtor; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8e4942988d..ba1bc9fd2a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1856,6 +1856,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (NewUD->isInvalidDecl()) return NewUD; + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { + if (SemaRef.CheckInheritingConstructorUsingDecl(NewUD)) + NewUD->setInvalidDecl(); + return NewUD; + } + bool isFunctionScope = Owner->isFunctionOrMethod(); // Process the shadow decls. diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp index 60cfff8088..66afa17309 100644 --- a/test/CXX/special/class.inhctor/elsewhere.cpp +++ b/test/CXX/special/class.inhctor/elsewhere.cpp @@ -29,3 +29,29 @@ struct I1 : B1 { struct D1 : I1 { using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} }; + +template struct A {}; + +template struct B : A, A { + using A::A; // expected-error {{'A::', which is not a base class of 'B'}} +}; +B bb; +B bc; +B bd; // expected-note {{here}} + +template struct C : A { + using A::A; // expected-error {{'A::', which is not a base class of 'C'}} +}; +C cb; +C cc; // expected-note {{here}} + +template struct D : A {}; +template struct E : D { + using A::A; // expected-error {{'A' is not a direct base of 'E', can not inherit}} +}; +E eb; // expected-note {{here}} + +template struct F : D { + using A::A; // expected-error {{'A' is not a direct base of 'F'}} +}; +F fb; // expected-note {{here}} diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp index 989c17c8b4..f71ab16c0f 100644 --- a/test/CXX/special/class.inhctor/p3.cpp +++ b/test/CXX/special/class.inhctor/p3.cpp @@ -28,3 +28,21 @@ struct D3 : B3 { // expected-note 2 {{candidate constructor}} using B3::B3; // expected-note {{candidate constructor (inherited)}} }; D3 fd3() { return 1; } // expected-error {{no viable conversion}} + +template struct T1 : B1 { + using B1::B1; +}; +template struct T2 : T1 { + using T1::T1; +}; +template struct T3 : T1 { + using T1::T1; +}; +struct U { + friend T1::T1(int); + friend T1::T1(int, int); + friend T2::T2(int); + friend T2::T2(int, int); + friend T3::T3(int); + friend T3::T3(int, int); +}; diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp index 736754d8a3..9ae160f054 100644 --- a/test/CXX/special/class.inhctor/p7.cpp +++ b/test/CXX/special/class.inhctor/p7.cpp @@ -2,7 +2,7 @@ // Straight from the standard struct B1 { - B1(int); // expected-note {{previous constructor}} + B1(int); // expected-note {{previous constructor}} expected-note {{conflicting constructor}} }; struct B2 { B2(int); // expected-note {{conflicting constructor}} @@ -16,3 +16,14 @@ struct D2 : B1, B2 { using B2::B2; D2(int); }; + +template struct B3 { + B3(T); // expected-note {{previous constructor}} +}; +template struct B4 : B3, B1 { + B4(); + using B3::B3; // expected-note {{inherited here}} + using B1::B1; // expected-error {{already inherited}} +}; +B4 b4c; +B4 b4i; // expected-note {{here}} -- 2.40.0