aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2008-12-03 20:26:15 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2008-12-03 20:26:15 +0000
commitb5a57a69e5fdac6dd9a92be717e279486c4a0128 (patch)
tree90da5a96e3705fcd76ce7761d4502c2d9c068fb6 /lib/Sema/SemaExprCXX.cpp
parentcd25c13ade3afa829c87ca1ed0ed0d379f426251 (diff)
Overload resolution for the operator new function. Member version is still untested.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60503 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp244
1 files changed, 234 insertions, 10 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index bfc367dd58..1cecb5dc70 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
using namespace clang;
/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function
@@ -235,19 +236,13 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- // --- Choosing an allocation function ---
- // C++ 5.3.4p8 - 14 & 18
- // 1) If UseGlobal is true, only look in the global scope. Else, also look
- // in the scope of the allocated class.
- // 2) If an array size is given, look for operator new[], else look for
- // operator new.
- // 3) The first argument is always size_t. Append the arguments from the
- // placement form.
- // FIXME: Find the correct overload of operator new.
- // FIXME: Also find the corresponding overload of operator delete.
FunctionDecl *OperatorNew = 0;
FunctionDecl *OperatorDelete = 0;
Expr **PlaceArgs = (Expr**)PlacementArgs;
+ if (FindAllocationFunctions(StartLoc, UseGlobal, AllocType, ArraySize,
+ PlaceArgs, NumPlaceArgs, OperatorNew,
+ OperatorDelete))
+ return true;
bool Init = ConstructorLParen.isValid();
// --- Choosing a constructor ---
@@ -355,6 +350,235 @@ bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D)
return false;
}
+/// FindAllocationFunctions - Finds the overloads of operator new and delete
+/// that are appropriate for the allocation.
+bool Sema::FindAllocationFunctions(SourceLocation StartLoc, bool UseGlobal,
+ QualType AllocType, bool IsArray,
+ Expr **PlaceArgs, unsigned NumPlaceArgs,
+ FunctionDecl *&OperatorNew,
+ FunctionDecl *&OperatorDelete)
+{
+ // --- Choosing an allocation function ---
+ // C++ 5.3.4p8 - 14 & 18
+ // 1) If UseGlobal is true, only look in the global scope. Else, also look
+ // in the scope of the allocated class.
+ // 2) If an array size is given, look for operator new[], else look for
+ // operator new.
+ // 3) The first argument is always size_t. Append the arguments from the
+ // placement form.
+ // FIXME: Also find the appropriate delete operator.
+
+ llvm::SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs);
+ // We don't care about the actual value of this argument.
+ // FIXME: Should the Sema create the expression and embed it in the syntax
+ // tree? Or should the consumer just recalculate the value?
+ AllocArgs[0] = new IntegerLiteral(llvm::APInt::getNullValue(
+ Context.Target.getPointerWidth(0)),
+ Context.getSizeType(),
+ SourceLocation());
+ std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
+
+ DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
+ IsArray ? OO_Array_New : OO_New);
+ if (AllocType->isRecordType() && !UseGlobal) {
+ OverloadCandidateSet MemberNewCandidates;
+ const CXXRecordType *Record = cast<CXXRecordType>(
+ AllocType->getAsRecordType());
+ IdentifierResolver::iterator I =
+ IdResolver.begin(NewName, Record->getDecl(), /*LookInParentCtx=*/false);
+ NamedDecl *Decl = (I == IdResolver.end()) ? 0 : *I;
+ // Member operator new is implicitly treated as static, so don't use
+ // AddMemberCandidate.
+ if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(Decl))
+ AddOverloadCandidate(Method, &AllocArgs[0], AllocArgs.size(),
+ MemberNewCandidates,
+ /*SuppressUserConversions=*/false);
+ else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast_or_null<OverloadedFunctionDecl>(Decl)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*F))
+ AddOverloadCandidate(Method, &AllocArgs[0], AllocArgs.size(),
+ MemberNewCandidates,
+ /*SuppressUserConversions=*/false);
+ }
+ }
+
+ // Do the resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(MemberNewCandidates, Best)) {
+ case OR_Success: {
+ // Got one!
+ FunctionDecl *FnDecl = Best->Function;
+ // The first argument is size_t, and the first parameter must be size_t,
+ // too.
+ for (unsigned i = 1; i < AllocArgs.size(); ++i) {
+ // FIXME: Passing word to diagnostic.
+ // This might modify the argument expression, so pass the one in
+ // PlaceArgs.
+ if (PerformCopyInitialization(PlaceArgs[i-1],
+ FnDecl->getParamDecl(i)->getType(),
+ "passing"))
+ return true;
+ }
+ OperatorNew = FnDecl;
+ break;
+ }
+
+ case OR_No_Viable_Function:
+ // No viable function; look something up in the global scope instead.
+ break;
+
+ case OR_Ambiguous:
+ // FIXME: Bad location information.
+ Diag(StartLoc, diag::err_ovl_ambiguous_oper) << NewName;
+ PrintOverloadCandidates(MemberNewCandidates, /*OnlyViable=*/true);
+ return true;
+ }
+ }
+ if (!OperatorNew) {
+ // Didn't find a member overload. Look for a global one.
+ DeclareGlobalNewDelete();
+ OverloadCandidateSet GlobalNewCandidates;
+ IdentifierResolver::iterator I =
+ IdResolver.begin(NewName, Context.getTranslationUnitDecl(),
+ /*LookInParentCtx=*/false);
+ NamedDecl *Decl = (I == IdResolver.end()) ? 0 : *I;
+ if (FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Decl))
+ AddOverloadCandidate(Fn, &AllocArgs[0], AllocArgs.size(),
+ GlobalNewCandidates,
+ /*SuppressUserConversions=*/false);
+ else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast_or_null<OverloadedFunctionDecl>(Decl)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*F))
+ AddOverloadCandidate(Fn, &AllocArgs[0], AllocArgs.size(),
+ GlobalNewCandidates,
+ /*SuppressUserConversions=*/false);
+ }
+ }
+
+ // Do the resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(GlobalNewCandidates, Best)) {
+ case OR_Success: {
+ // Got one!
+ FunctionDecl *FnDecl = Best->Function;
+ // The first argument is size_t, and the first parameter must be size_t,
+ // too. This is checked on declaration and can be assumed.
+ for (unsigned i = 1; i < AllocArgs.size(); ++i) {
+ // FIXME: Passing word to diagnostic.
+ // This might modify the argument expression, so pass the one in
+ // PlaceArgs.
+ if (PerformCopyInitialization(PlaceArgs[i-1],
+ FnDecl->getParamDecl(i)->getType(),
+ "passing"))
+ return true;
+ }
+ OperatorNew = FnDecl;
+ break;
+ }
+
+ case OR_No_Viable_Function:
+ // FIXME: Bad location information.
+ Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << NewName << (unsigned)GlobalNewCandidates.size();
+ PrintOverloadCandidates(GlobalNewCandidates, /*OnlyViable=*/false);
+ return true;
+
+ case OR_Ambiguous:
+ // FIXME: Bad location information.
+ Diag(StartLoc, diag::err_ovl_ambiguous_oper) << NewName;
+ PrintOverloadCandidates(GlobalNewCandidates, /*OnlyViable=*/true);
+ return true;
+ }
+ }
+
+ AllocArgs[0]->Destroy(Context);
+ return false;
+}
+
+/// DeclareGlobalNewDelete - Declare the global forms of operator new and
+/// delete. These are:
+/// @code
+/// void* operator new(std::size_t) throw(std::bad_alloc);
+/// void* operator new[](std::size_t) throw(std::bad_alloc);
+/// void operator delete(void *) throw();
+/// void operator delete[](void *) throw();
+/// @endcode
+/// Note that the placement and nothrow forms of new are *not* implicitly
+/// declared. Their use requires including \<new\>.
+void Sema::DeclareGlobalNewDelete()
+{
+ if (GlobalNewDeleteDeclared)
+ return;
+ GlobalNewDeleteDeclared = true;
+
+ QualType VoidPtr = Context.getPointerType(Context.VoidTy);
+ QualType SizeT = Context.getSizeType();
+
+ // FIXME: Exception specifications are not added.
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_New),
+ VoidPtr, SizeT);
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Array_New),
+ VoidPtr, SizeT);
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete),
+ Context.VoidTy, VoidPtr);
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete),
+ Context.VoidTy, VoidPtr);
+}
+
+/// DeclareGlobalAllocationFunction - Declares a single implicit global
+/// allocation function if it doesn't already exist.
+void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
+ QualType Return, QualType Argument)
+{
+ DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
+
+ // Check if this function is already declared.
+ IdentifierResolver::iterator I = IdResolver.begin(Name, GlobalCtx,
+ /*CheckParent=*/false);
+
+ if (I != IdResolver.end()) {
+ NamedDecl *Decl = *I;
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(Decl)) {
+ // The return type fits. This is checked when the function is declared.
+ if (Fn->getNumParams() == 1 &&
+ Context.getCanonicalType(Fn->getParamDecl(0)->getType()) == Argument)
+ return;
+ } else if(OverloadedFunctionDecl *Ovl =
+ dyn_cast<OverloadedFunctionDecl>(Decl)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if ((*F)->getNumParams() == 1 &&
+ Context.getCanonicalType((*F)->getParamDecl(0)->getType())
+ == Argument)
+ return;
+ }
+ }
+ }
+
+ QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
+ FunctionDecl *Alloc =
+ FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
+ FnType, FunctionDecl::None, false, 0,
+ SourceLocation());
+ Alloc->setImplicit();
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
+ 0, Argument, VarDecl::None, 0, 0);
+ Alloc->setParams(&Param, 1);
+
+ PushOnScopeChains(Alloc, TUScope);
+}
+
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
/// @code ::delete ptr; @endcode
/// or