From: Sebastian Redl Date: Mon, 13 Sep 2010 22:02:47 +0000 (+0000) Subject: Remove CXXRecordDecl::getDefaultConstructor(), an inherently unsafe function due... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=751025d5d174ab75dc3788211581d9fbe6224841;p=clang Remove CXXRecordDecl::getDefaultConstructor(), an inherently unsafe function due to lazy declaration of default constructors. Now that __has_nothrow_constructor doesn't use it anymore, part of PR8101 is fixed. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113794 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 3db147c1ab..c4b9292be4 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -859,9 +859,6 @@ public: /// \brief Set the kind of specialization or template instantiation this is. void setTemplateSpecializationKind(TemplateSpecializationKind TSK); - - /// getDefaultConstructor - Returns the default constructor for this class - CXXConstructorDecl *getDefaultConstructor(); /// getDestructor - Returns the destructor decl for this class. CXXDestructorDecl *getDestructor() const; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index f2f0694826..88301c2d9d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -577,28 +577,6 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { assert(false && "Not a class template or member class specialization"); } -CXXConstructorDecl * -CXXRecordDecl::getDefaultConstructor() { - ASTContext &Context = getASTContext(); - QualType ClassType = Context.getTypeDeclType(this); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = lookup(ConstructorName); - Con != ConEnd; ++Con) { - // FIXME: In C++0x, a constructor template can be a default constructor. - if (isa(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor; - } - return 0; -} - CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(this); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2d31e8cc9a..d16d9e9763 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4322,6 +4322,28 @@ namespace { }; } +static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self, + CXXRecordDecl *D) { + ASTContext &Context = Self.Context; + QualType ClassType = Context.getTypeDeclType(D); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // FIXME: In C++0x, a constructor template can be a default constructor. + if (isa(*Con)) + continue; + + CXXConstructorDecl *Constructor = cast(*Con); + if (Constructor->isDefaultConstructor()) + return Constructor; + } + return 0; +} + CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl) { // C++ [class.ctor]p5: @@ -4349,8 +4371,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); if (!BaseClassDecl->hasDeclaredDefaultConstructor()) ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); - else if (CXXConstructorDecl *Constructor - = BaseClassDecl->getDefaultConstructor()) + else if (CXXConstructorDecl *Constructor + = getDefaultConstructorUnsafe(*this, BaseClassDecl)) ExceptSpec.CalledDecl(Constructor); } } @@ -4364,7 +4386,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( if (!BaseClassDecl->hasDeclaredDefaultConstructor()) ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl)); else if (CXXConstructorDecl *Constructor - = BaseClassDecl->getDefaultConstructor()) + = getDefaultConstructorUnsafe(*this, BaseClassDecl)) ExceptSpec.CalledDecl(Constructor); } } @@ -4380,7 +4402,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( ExceptSpec.CalledDecl( DeclareImplicitDefaultConstructor(FieldClassDecl)); else if (CXXConstructorDecl *Constructor - = FieldClassDecl->getDefaultConstructor()) + = getDefaultConstructorUnsafe(*this, FieldClassDecl)) ExceptSpec.CalledDecl(Constructor); } } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d026851f62..b380a4b7a7 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2145,8 +2145,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T) { bool FoundConstructor = false; bool AllNoThrow = true; unsigned FoundTQs; - DeclarationName ConstructorName - = C.DeclarationNames.getCXXConstructorName(C.getCanonicalType(T)); DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); Con != ConEnd; ++Con) { @@ -2155,7 +2153,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); - if (!CPT->hasEmptyExceptionSpec()) { + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + if (!CPT->hasEmptyExceptionSpec() || CPT->getNumArgs() > 1) { AllNoThrow = false; break; } @@ -2178,13 +2178,17 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T) { if (RD->hasTrivialConstructor()) return true; - if (CXXConstructorDecl *Constructor = RD->getDefaultConstructor()) { - const FunctionProtoType *CPT - = Constructor->getType()->getAs(); - // TODO: check whether evaluating default arguments can throw. - // For now, we'll be conservative and assume that they can throw. - if (CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0) - return true; + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD); + Con != ConEnd; ++Con) { + CXXConstructorDecl *Constructor = cast(*Con); + if (Constructor->isDefaultConstructor()) { + const FunctionProtoType *CPT + = Constructor->getType()->getAs(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + return CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0; + } } } return false; diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 61aba07597..cb88220bb1 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -393,6 +393,7 @@ void has_nothrow_constructor() { int t20[F(__has_nothrow_constructor(HasNoThrowConstructorWithArgs))]; int t21[F(__has_nothrow_constructor(void))]; int t22[F(__has_nothrow_constructor(cvoid))]; + int t23[T(__has_nothrow_constructor(HasVirtDest))]; } void has_virtual_destructor() {