diff options
author | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2011-06-10 03:50:41 +0000 |
---|---|---|
committer | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2011-06-10 03:50:41 +0000 |
commit | b320e0c322fb71d6235ebca9ec22940a97bdcdc7 (patch) | |
tree | d1331c8a3646728c1207fdbf7705b0bbde7abea4 /lib/Sema/SemaLookup.cpp | |
parent | bbf34c024398e7bae825686dcff4c3b901ec9f89 (diff) |
Implement caching of default constructors on the resolution table. This
isn't yet used for the less controlled environments of initialization.
Also a few random text fixups.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132833 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 125 |
1 files changed, 123 insertions, 2 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index f7726d99c8..b730408b91 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2186,12 +2186,133 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, return Result; } - llvm_unreachable("haven't implemented this for non-destructors yet"); + // Prepare for overload resolution. Here we construct a synthetic argument + // if necessary and make sure that implicit functions are declared. + CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D)); + DeclarationName Name; + Expr *Arg = 0; + unsigned NumArgs; + + if (SM == CXXDefaultConstructor) { + Name = Context.DeclarationNames.getCXXConstructorName(CanTy); + NumArgs = 0; + if (D->needsImplicitDefaultConstructor()) + DeclareImplicitDefaultConstructor(D); + } else { + if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { + Name = Context.DeclarationNames.getCXXConstructorName(CanTy); + if (!D->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(D); + // TODO: Move constructors + } else { + Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + if (!D->hasDeclaredCopyAssignment()) + DeclareImplicitCopyAssignment(D); + // TODO: Move assignment + } + + QualType ArgType = CanTy; + if (ConstArg) + ArgType.addConst(); + if (VolatileArg) + ArgType.addVolatile(); + + // This isn't /really/ specified by the standard, but it's implied + // we should be working from an RValue in the case of move to ensure + // that we prefer to bind to rvalue references, and an LValue in the + // case of copy to ensure we don't bind to rvalue references. + // Possibly an XValue is actually correct in the case of move, but + // there is no semantic difference for class types in this restricted + // case. + ExprValueKind VK; + if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + VK = VK_LValue; + else + VK = VK_RValue; + + NumArgs = 1; + Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK); + } + + // Create the object argument + QualType ThisTy = CanTy; + if (ConstThis) + ThisTy.addConst(); + if (VolatileThis) + ThisTy.addVolatile(); + Expr::Classification ObjectClassification = + (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy, + RValueThis ? VK_RValue : VK_LValue))-> + Classify(Context); + + // Now we perform lookup on the name we computed earlier and do overload + // resolution. Lookup is only performed directly into the class since there + // will always be a (possibly implicit) declaration to shadow any others. + OverloadCandidateSet OCS((SourceLocation())); + DeclContext::lookup_iterator I, E; + Result->setConstParamMatch(false); + + llvm::tie(I, E) = D->lookup(Name); + assert((I != E) && + "lookup for a constructor or assignment operator was empty"); + for ( ; I != E; ++I) { + if ((*I)->isInvalidDecl()) + continue; + + if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) { + AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs, + OCS, true); + + // Here we're looking for a const parameter to speed up creation of + // implicit copy methods. + if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) || + (SM == CXXCopyConstructor && + cast<CXXConstructorDecl>(M)->isCopyConstructor())) { + QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0); + if (ArgType->getPointeeType().isConstQualified()) + Result->setConstParamMatch(true); + } + } else { + FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I); + AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), + 0, &Arg, NumArgs, OCS, true); + } + } + + OverloadCandidateSet::iterator Best; + switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) { + case OR_Success: + Result->setMethod(cast<CXXMethodDecl>(Best->Function)); + Result->setSuccess(true); + break; + + case OR_Deleted: + Result->setMethod(cast<CXXMethodDecl>(Best->Function)); + Result->setSuccess(false); + break; + + case OR_Ambiguous: + case OR_No_Viable_Function: + Result->setMethod(0); + Result->setSuccess(false); + break; + } + + return Result; +} + +/// \brief Look up the default constructor for the given class. +CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, + false, false); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); } /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { - // If the copy constructor has not yet been declared, do so now. + // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Context, Class)) { if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); |