[cfe-commits] r60503 - in /cfe/trunk: lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp test/SemaCXX/new-delete.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Wed Dec 3 12:26:19 PST 2008
Author: cornedbee
Date: Wed Dec 3 14:26:15 2008
New Revision: 60503
URL: http://llvm.org/viewvc/llvm-project?rev=60503&view=rev
Log:
Overload resolution for the operator new function. Member version is still untested.
Modified:
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/SemaCXX/new-delete.cpp
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=60503&r1=60502&r2=60503&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Wed Dec 3 14:26:15 2008
@@ -116,7 +116,8 @@
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
: PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
SourceMgr(PP.getSourceManager()), CurContext(0), PreDeclaratorDC(0),
- CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()) {
+ CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
+ GlobalNewDeleteDeclared(false) {
// Get IdentifierInfo objects for known functions for which we
// do extra checking.
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=60503&r1=60502&r2=60503&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Dec 3 14:26:15 2008
@@ -202,6 +202,10 @@
/// The C++ "std" namespace, where the standard library resides. Cached here
/// by GetStdNamespace
NamespaceDecl *StdNamespace;
+
+ /// A flag to remember whether the implicit forms of operator new and delete
+ /// have been declared.
+ bool GlobalNewDeleteDeclared;
/// ObjCMethodList - a linked list of methods with different signatures.
struct ObjCMethodList {
@@ -831,6 +835,14 @@
ExprTy **ConstructorArgs, unsigned NumConsArgs,
SourceLocation ConstructorRParen);
bool CheckAllocatedType(QualType AllocType, const Declarator &D);
+ bool FindAllocationFunctions(SourceLocation StartLoc, bool UseGlobal,
+ QualType AllocType, bool IsArray,
+ Expr **PlaceArgs, unsigned NumPlaceArgs,
+ FunctionDecl *&OperatorNew,
+ FunctionDecl *&OperatorDelete);
+ void DeclareGlobalNewDelete();
+ void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
+ QualType Argument);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
virtual ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=60503&r1=60502&r2=60503&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Dec 3 14:26:15 2008
@@ -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 @@
}
}
- // --- 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 @@
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
Modified: cfe/trunk/test/SemaCXX/new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete.cpp?rev=60503&r1=60502&r2=60503&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/new-delete.cpp Wed Dec 3 14:26:15 2008
@@ -1,5 +1,7 @@
// RUN: clang -fsyntax-only -verify %s
+#include <stddef.h>
+
struct S // expected-note {{candidate}}
{
S(int, int, double); // expected-note {{candidate}}
@@ -8,6 +10,10 @@
};
struct T;
+void* operator new(size_t); // expected-note {{candidate}}
+void* operator new(size_t, int*); // expected-note {{candidate}}
+void* operator new(size_t, float*); // expected-note {{candidate}}
+
void good_news()
{
int *pi = new int;
@@ -43,6 +49,7 @@
(void)new int[-1]; // expected-error {{array size is negative}}
(void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'struct S'}}
(void)::S::new int; // expected-error {{expected unqualified-id}}
+ (void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}}
// Some lacking cases due to lack of sema support.
}
More information about the cfe-commits
mailing list