diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 43 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 130 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 12 |
7 files changed, 197 insertions, 47 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 314d1750f43..9f09898a957 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2774,7 +2774,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, ConstexprSpecKind ConstexprKind) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), - DeclContext(DK), redeclarable_base(C), ODRHash(0), + DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0), EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) { assert(T.isNull() || T->isFunctionType()); FunctionDeclBits.SClass = S; @@ -2789,6 +2789,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.IsTrivialForCall = false; FunctionDeclBits.IsDefaulted = false; FunctionDeclBits.IsExplicitlyDefaulted = false; + FunctionDeclBits.HasDefaultedFunctionInfo = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; FunctionDeclBits.ConstexprKind = ConstexprKind; @@ -2816,6 +2817,32 @@ bool FunctionDecl::isVariadic() const { return false; } +FunctionDecl::DefaultedFunctionInfo * +FunctionDecl::DefaultedFunctionInfo::Create(ASTContext &Context, + ArrayRef<DeclAccessPair> Lookups) { + DefaultedFunctionInfo *Info = new (Context.Allocate( + totalSizeToAlloc<DeclAccessPair>(Lookups.size()), + std::max(alignof(DefaultedFunctionInfo), alignof(DeclAccessPair)))) + DefaultedFunctionInfo; + Info->NumLookups = Lookups.size(); + std::uninitialized_copy(Lookups.begin(), Lookups.end(), + Info->getTrailingObjects<DeclAccessPair>()); + return Info; +} + +void FunctionDecl::setDefaultedFunctionInfo(DefaultedFunctionInfo *Info) { + assert(!FunctionDeclBits.HasDefaultedFunctionInfo && "already have this"); + assert(!Body && "can't replace function body with defaulted function info"); + + FunctionDeclBits.HasDefaultedFunctionInfo = true; + DefaultedInfo = Info; +} + +FunctionDecl::DefaultedFunctionInfo * +FunctionDecl::getDefaultedFunctionInfo() const { + return FunctionDeclBits.HasDefaultedFunctionInfo ? DefaultedInfo : nullptr; +} + bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { for (auto I : redecls()) { if (I->doesThisDeclarationHaveABody()) { @@ -2827,8 +2854,7 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { return false; } -bool FunctionDecl::hasTrivialBody() const -{ +bool FunctionDecl::hasTrivialBody() const { Stmt *S = getBody(); if (!S) { // Since we don't have a body for this function, we don't know if it's @@ -2856,6 +2882,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { if (!hasBody(Definition)) return nullptr; + assert(!Definition->FunctionDeclBits.HasDefaultedFunctionInfo && + "definition should not have a body"); if (Definition->Body) return Definition->Body.get(getASTContext().getExternalSource()); @@ -2863,7 +2891,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { } void FunctionDecl::setBody(Stmt *B) { - Body = B; + FunctionDeclBits.HasDefaultedFunctionInfo = false; + Body = LazyDeclStmtPtr(B); if (B) EndRangeLoc = B->getEndLoc(); } @@ -3304,9 +3333,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body.isValid(); + FoundBody |= Prev->doesThisDeclarationHaveABody(); - if (Prev->Body) { + if (Prev->doesThisDeclarationHaveABody()) { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then it is always externally visible. if (!Prev->isInlineSpecified() || @@ -3329,7 +3358,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body.isValid(); + FoundBody |= Prev->doesThisDeclarationHaveABody(); if (RedeclForcesDefC99(Prev)) return false; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1ee6ee5dcf1..6d15e1e2025 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6296,7 +6296,11 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, /// Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. -void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { +/// +/// \param S The scope in which the class was parsed. Null if we didn't just +/// parse a class definition. +/// \param Record The completed class. +void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { if (!Record) return; @@ -6412,13 +6416,17 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { DFK.asComparison() == DefaultedComparisonKind::Relational) DefaultedSecondaryComparisons.push_back(FD); else - CheckExplicitlyDefaultedFunction(FD); + CheckExplicitlyDefaultedFunction(S, FD); }; auto CompleteMemberFunction = [&](CXXMethodDecl *M) { // Check whether the explicitly-defaulted members are valid. CheckForDefaultedFunction(M); + // Skip the rest of the checks for a member of a dependent class. + if (Record->isDependentType()) + return; + // For an explicitly defaulted or deleted special member, we defer // determining triviality until the class is complete. That time is now! CXXSpecialMember CSM = getSpecialMember(M); @@ -6463,18 +6471,20 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { DefineImplicitSpecialMember(*this, M, M->getLocation()); }; + // Check the destructor before any other member function. We need to + // determine whether it's trivial in order to determine whether the claas + // type is a literal type, which is a prerequisite for determining whether + // other special member functions are valid and whether they're implicitly + // 'constexpr'. + if (CXXDestructorDecl *Dtor = Record->getDestructor()) + CompleteMemberFunction(Dtor); + bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; - if (!Record->isDependentType()) { - // Check the destructor before any other member function. We need to - // determine whether it's trivial in order to determine whether the claas - // type is a literal type, which is a prerequisite for determining whether - // other special member functions are valid and whether they're implicitly - // 'constexpr'. - if (CXXDestructorDecl *Dtor = Record->getDestructor()) - CompleteMemberFunction(Dtor); - - for (auto *M : Record->methods()) { + for (auto *M : Record->methods()) { + // FIXME: We could do this check for dependent types with non-dependent + // bases. + if (!Record->isDependentType()) { // See if a method overloads virtual methods in a base // class without overriding any. if (!M->isStatic()) @@ -6483,10 +6493,10 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { HasMethodWithOverrideControl = true; else if (M->size_overridden_methods() > 0) HasOverridingMethodWithoutOverrideControl = true; - - if (!isa<CXXDestructorDecl>(M)) - CompleteMemberFunction(M); } + + if (!isa<CXXDestructorDecl>(M)) + CompleteMemberFunction(M); } if (HasMethodWithOverrideControl && @@ -6507,7 +6517,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // Check the defaulted secondary comparisons after any other member functions. for (FunctionDecl *FD : DefaultedSecondaryComparisons) - CheckExplicitlyDefaultedFunction(FD); + CheckExplicitlyDefaultedFunction(S, FD); // ms_struct is a request to use the same ABI rules as MSVC. Check // whether this class uses any C++ features that are implemented @@ -6862,16 +6872,19 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) UpdateExceptionSpec(MD->getCanonicalDecl(), ESI); } -void Sema::CheckExplicitlyDefaultedFunction(FunctionDecl *FD) { +void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) { assert(FD->isExplicitlyDefaulted() && "not explicitly-defaulted"); DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD); - assert(DefKind && "not a defaultable function"); + if (!DefKind) { + assert(FD->getDeclContext()->isDependentContext()); + return; + } if (DefKind.isSpecialMember() ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD), DefKind.asSpecialMember()) - : CheckExplicitlyDefaultedComparison(FD, DefKind.asComparison())) + : CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison())) FD->setInvalidDecl(); } @@ -6882,6 +6895,10 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid && "not an explicitly-defaulted special member"); + // Defer all checking for special members of a dependent type. + if (RD->isDependentType()) + return false; + // Whether this was the first-declared instance of the constructor. // This affects whether we implicitly add an exception spec and constexpr. bool First = MD == MD->getCanonicalDecl(); @@ -7093,7 +7110,14 @@ public: DefaultedComparisonVisitor(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD, DefaultedComparisonKind DCK) - : S(S), RD(RD), FD(FD), DCK(DCK) {} + : S(S), RD(RD), FD(FD), DCK(DCK) { + if (auto *Info = FD->getDefaultedFunctionInfo()) { + // FIXME: Change CreateOverloadedBinOp to take an ArrayRef instead of an + // UnresolvedSet to avoid this copy. + Fns.assign(Info->getUnqualifiedLookups().begin(), + Info->getUnqualifiedLookups().end()); + } + } ResultList visit() { // The type of an lvalue naming a parameter of this function. @@ -7182,6 +7206,7 @@ protected: CXXRecordDecl *RD; FunctionDecl *FD; DefaultedComparisonKind DCK; + UnresolvedSet<16> Fns; }; /// Information about a defaulted comparison, as determined by @@ -7289,8 +7314,6 @@ private: visitBinaryOperator(OverloadedOperatorKind OO, ArrayRef<Expr *> Args, Subobject Subobj, OverloadCandidateSet *SpaceshipCandidates = nullptr) { - UnresolvedSet<4> Fns; // FIXME: Track this. - // Note that there is no need to consider rewritten candidates here if // we've already found there is no viable 'operator<=>' candidate (and are // considering synthesizing a '<=>' from '==' and '<'). @@ -7318,9 +7341,11 @@ private: if ((DCK == DefaultedComparisonKind::NotEqual || DCK == DefaultedComparisonKind::Relational) && !Best->RewriteKind) { - S.Diag(Best->Function->getLocation(), - diag::note_defaulted_comparison_not_rewritten_callee) - << FD; + if (Diagnose == ExplainDeleted) { + S.Diag(Best->Function->getLocation(), + diag::note_defaulted_comparison_not_rewritten_callee) + << FD; + } return Result::deleted(); } @@ -7703,8 +7728,6 @@ private: } StmtResult visitExpandedSubobject(QualType Type, ExprPair Obj) { - UnresolvedSet<4> Fns; // FIXME: Track this. - if (Obj.first.isInvalid() || Obj.second.isInvalid()) return StmtError(); @@ -7799,23 +7822,58 @@ private: }; } -bool Sema::CheckExplicitlyDefaultedComparison(FunctionDecl *FD, +/// Perform the unqualified lookups that might be needed to form a defaulted +/// comparison function for the given operator. +static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S, + UnresolvedSetImpl &Operators, + OverloadedOperatorKind Op) { + auto Lookup = [&](OverloadedOperatorKind OO) { + Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators); + }; + + // Every defaulted operator looks up itself. + Lookup(Op); + // ... and the rewritten form of itself, if any. + if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(Op)) + Lookup(ExtraOp); + + // For 'operator<=>', we also form a 'cmp != 0' expression, and might + // synthesize a three-way comparison from '<' and '=='. + if (Op == OO_Spaceship) { + Lookup(OO_ExclaimEqual); + Lookup(OO_Less); + Lookup(OO_EqualEqual); + } +} + +bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, DefaultedComparisonKind DCK) { assert(DCK != DefaultedComparisonKind::None && "not a defaulted comparison"); + CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext()); + assert(RD && "defaulted comparison is not defaulted in a class"); + + // Perform any unqualified lookups we're going to need to default this + // function. + if (S) { + UnresolvedSet<32> Operators; + lookupOperatorsForDefaultedComparison(*this, S, Operators, + FD->getOverloadedOperator()); + FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create( + Context, Operators.pairs())); + } + // C++2a [class.compare.default]p1: // A defaulted comparison operator function for some class C shall be a // non-template function declared in the member-specification of C that is // -- a non-static const member of C having one parameter of type // const C&, or // -- a friend of C having two parameters of type const C&. - CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext()); - assert(RD && "defaulted comparison is not defaulted in a class"); - QualType ExpectedParmType = Context.getLValueReferenceType(Context.getRecordType(RD).withConst()); for (const ParmVarDecl *Param : FD->parameters()) { - if (!Context.hasSameType(Param->getType(), ExpectedParmType)) { + if (!Param->getType()->isDependentType() && + !Context.hasSameType(Param->getType(), ExpectedParmType)) { Diag(FD->getLocation(), diag::err_defaulted_comparison_param) << (int)DCK << Param->getType() << ExpectedParmType << Param->getSourceRange(); @@ -7849,6 +7907,7 @@ bool Sema::CheckExplicitlyDefaultedComparison(FunctionDecl *FD, // A [defaulted comparison other than <=>] shall have a declared return // type bool. if (DCK != DefaultedComparisonKind::ThreeWay && + !FD->getDeclaredReturnType()->isDependentType() && !Context.hasSameType(FD->getDeclaredReturnType(), Context.BoolTy)) { Diag(FD->getLocation(), diag::err_defaulted_comparison_return_type_not_bool) << (int)DCK << FD->getDeclaredReturnType() << Context.BoolTy @@ -7856,6 +7915,11 @@ bool Sema::CheckExplicitlyDefaultedComparison(FunctionDecl *FD, return true; } + // For a defaulted function in a dependent class, defer all remaining checks + // until instantiation. + if (RD->isDependentType()) + return false; + // Determine whether the function should be defined as deleted. DefaultedComparisonInfo Info = DefaultedComparisonAnalyzer(*this, RD, FD, DCK).visit(); @@ -9206,7 +9270,7 @@ void Sema::ActOnFinishCXXMemberSpecification( reinterpret_cast<Decl**>(FieldCollector->getCurFields()), FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); - CheckCompletedCXXClass(cast<CXXRecordDecl>(TagDecl)); + CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl)); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 14b443e9dac..d09a3377d2b 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1252,7 +1252,7 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, SmallVector<Decl*, 4> Fields(Class->fields()); ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(Class); + CheckCompletedCXXClass(nullptr, Class); PopFunctionScopeInfo(); } @@ -1798,7 +1798,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, SmallVector<Decl*, 4> Fields(Class->fields()); ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(Class); + CheckCompletedCXXClass(nullptr, Class); } Cleanup.mergeFrom(LambdaCleanup); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 4d54ec17b99..1451fe4bb4d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2236,7 +2236,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Finish checking fields. ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(Instantiation); + CheckCompletedCXXClass(nullptr, Instantiation); // Default arguments are parsed, if not instantiated. We can go instantiate // default arg exprs for default constructors if necessary now. Unless we're diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2ab282e05e3..fb19579cca1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2077,8 +2077,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } - if (D->isExplicitlyDefaulted()) - SemaRef.SetDeclDefaulted(Function, D->getLocation()); + if (D->isExplicitlyDefaulted()) { + if (SubstDefaultedFunction(Function, D)) + return nullptr; + } if (D->isDeleted()) SemaRef.SetDeclDeleted(Function, D->getLocation()); @@ -2357,8 +2359,10 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( SemaRef.CheckOverrideControl(Method); // If a function is defined as defaulted or deleted, mark it as such now. - if (D->isExplicitlyDefaulted()) - SemaRef.SetDeclDefaulted(Method, Method->getLocation()); + if (D->isExplicitlyDefaulted()) { + if (SubstDefaultedFunction(Method, D)) + return nullptr; + } if (D->isDeletedAsWritten()) SemaRef.SetDeclDeleted(Method, Method->getLocation()); @@ -4139,6 +4143,34 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, return false; } +bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New, + FunctionDecl *Tmpl) { + // Transfer across any unqualified lookups. + if (auto *DFI = Tmpl->getDefaultedFunctionInfo()) { + SmallVector<DeclAccessPair, 32> Lookups; + Lookups.reserve(DFI->getUnqualifiedLookups().size()); + bool AnyChanged = false; + for (DeclAccessPair DA : DFI->getUnqualifiedLookups()) { + NamedDecl *D = SemaRef.FindInstantiatedDecl(New->getLocation(), + DA.getDecl(), TemplateArgs); + if (!D) + return true; + AnyChanged |= (D != DA.getDecl()); + Lookups.push_back(DeclAccessPair::make(D, DA.getAccess())); + } + + // It's unlikely that substitution will change any declarations. Don't + // store an unnecessary copy in that case. + New->setDefaultedFunctionInfo( + AnyChanged ? FunctionDecl::DefaultedFunctionInfo::Create( + SemaRef.Context, Lookups) + : DFI); + } + + SemaRef.SetDeclDefaulted(New, Tmpl->getLocation()); + return false; +} + /// Instantiate (or find existing instantiation of) a function template with a /// given set of template arguments. /// diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 8990379069b..8b9cb967719 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -888,6 +888,19 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setHasODRHash(true); FD->setUsesFPIntrin(Record.readInt()); + if (FD->isDefaulted()) { + if (unsigned NumLookups = Record.readInt()) { + SmallVector<DeclAccessPair, 8> Lookups; + for (unsigned I = 0; I != NumLookups; ++I) { + NamedDecl *ND = Record.readDeclAs<NamedDecl>(); + AccessSpecifier AS = (AccessSpecifier)Record.readInt(); + Lookups.push_back(DeclAccessPair::make(ND, AS)); + } + FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create( + Reader.getContext(), Lookups)); + } + } + switch ((FunctionDecl::TemplatedKind)Record.readInt()) { case FunctionDecl::TK_NonTemplate: mergeRedeclarable(FD, Redecl); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index d9efc9770fd..10dfc4b841a 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -562,6 +562,18 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->getODRHash()); Record.push_back(D->usesFPIntrin()); + if (D->isDefaulted()) { + if (auto *FDI = D->getDefaultedFunctionInfo()) { + Record.push_back(FDI->getUnqualifiedLookups().size()); + for (DeclAccessPair P : FDI->getUnqualifiedLookups()) { + Record.AddDeclRef(P.getDecl()); + Record.push_back(P.getAccess()); + } + } else { + Record.push_back(0); + } + } + Record.push_back(D->getTemplatedKind()); switch (D->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: |