summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
commit9092c3e0fa01f3139b016d05d267a89e3b07747a (patch)
tree137ebebcae16fb0ce7ab4af456992bbd8d22fced /lib/Sema/SemaExprCXX.cpp
parent4981926bf654fe5a2c3893f24ca44106b217e71e (diff)
downloadFreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.zip
FreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.tar.gz
Update clang to r84119.
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp1129
1 files changed, 837 insertions, 292 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7afa594..5f111c8 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -11,13 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "SemaInherit.h"
#include "Sema.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Parse/DeclSpec.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
@@ -31,9 +32,10 @@ Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
TypeTy *Ty, bool HasTrailingLParen,
const CXXScopeSpec &SS,
bool isAddressOfOperand) {
- QualType ConvType = QualType::getFromOpaquePtr(Ty);
- QualType ConvTypeCanon = Context.getCanonicalType(ConvType);
- DeclarationName ConvName
+ //FIXME: Preserve type source info.
+ QualType ConvType = GetTypeFromParser(Ty);
+ CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName
= Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
&SS, isAddressOfOperand);
@@ -59,12 +61,17 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
- NamespaceDecl *StdNs = GetStdNamespace();
- if (!StdNs)
+ if (!StdNamespace)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
-
+
+ if (isType)
+ // FIXME: Preserve type source info.
+ TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr();
+
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
- Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName);
+ LookupResult R;
+ LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName);
+ Decl *TypeInfoDecl = R.getAsSingleDecl(Context);
RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
if (!TypeInfoRecordDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
@@ -73,29 +80,29 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (!isType) {
// C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] [the] expression is an unevaluated
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] [the] expression is an unevaluated
// operand.
-
+
// FIXME: if the type of the expression is a class type, the class
// shall be completely defined.
bool isUnevaluatedOperand = true;
Expr *E = static_cast<Expr *>(TyOrExpr);
if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) {
QualType T = E->getType();
- if (const RecordType *RecordT = T->getAsRecordType()) {
+ if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
if (RecordD->isPolymorphic())
isUnevaluatedOperand = false;
}
}
-
+
// If this is an unevaluated operand, clear out the set of declaration
// references we have been computing.
if (isUnevaluatedOperand)
PotentiallyReferencedDeclStack.back().clear();
}
-
+
return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
TypeInfoType.withConst(),
SourceRange(OpLoc, RParenLoc)));
@@ -136,15 +143,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// to an incomplete type other than (cv) void the program is ill-formed.
QualType Ty = E->getType();
int isPointer = 0;
- if (const PointerType* Ptr = Ty->getAsPointerType()) {
+ if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
Ty = Ptr->getPointeeType();
isPointer = 1;
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
- isPointer ? diag::err_throw_incomplete_ptr
- : diag::err_throw_incomplete,
- E->getSourceRange(), SourceRange(), QualType()))
+ PDiag(isPointer ? diag::err_throw_incomplete_ptr
+ : diag::err_throw_incomplete)
+ << E->getSourceRange()))
return true;
}
@@ -179,7 +186,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(TypeRep && "Missing type!");
- QualType Ty = QualType::getFromOpaquePtr(TypeRep);
+ // FIXME: Preserve type source info.
+ QualType Ty = GetTypeFromParser(TypeRep);
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TypeRange.getBegin();
@@ -188,14 +196,27 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
if (Ty->isDependentType() ||
CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
exprs.release();
-
- return Owned(CXXUnresolvedConstructExpr::Create(Context,
- TypeRange.getBegin(), Ty,
+
+ return Owned(CXXUnresolvedConstructExpr::Create(Context,
+ TypeRange.getBegin(), Ty,
LParenLoc,
Exprs, NumExprs,
RParenLoc));
}
+ if (Ty->isArrayType())
+ return ExprError(Diag(TyBeginLoc,
+ diag::err_value_init_for_array_type) << FullRange);
+ if (!Ty->isVoidType() &&
+ RequireCompleteType(TyBeginLoc, Ty,
+ PDiag(diag::err_invalid_incomplete_type_use)
+ << FullRange))
+ return ExprError();
+
+ if (RequireNonAbstractType(TyBeginLoc, Ty,
+ diag::err_allocation_of_abstract_type))
+ return ExprError();
+
// C++ [expr.type.conv]p1:
// If the expression list is a single expression, the type conversion
@@ -203,36 +224,54 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
// corresponding cast expression.
//
if (NumExprs == 1) {
- if (CheckCastTypes(TypeRange, Ty, Exprs[0]))
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXMethodDecl *Method = 0;
+ if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method,
+ /*FunctionalStyle=*/true))
return ExprError();
+
exprs.release();
+ if (Method) {
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(),
+ Kind, Method, Owned(Exprs[0]));
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ Exprs[0] = CastArg.takeAs<Expr>();
+ }
+
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
- Ty, TyBeginLoc, Exprs[0],
- RParenLoc));
+ Ty, TyBeginLoc, Kind,
+ Exprs[0], RParenLoc));
}
- if (const RecordType *RT = Ty->getAsRecordType()) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
- // FIXME: We should always create a CXXTemporaryObjectExpr here unless
- // both the ctor and dtor are trivial.
- if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) {
+ if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
+ !Record->hasTrivialDestructor()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Ty, Exprs, NumExprs,
+ = PerformInitializationByConstructor(Ty, move(exprs),
TypeRange.getBegin(),
SourceRange(TypeRange.getBegin(),
RParenLoc),
DeclarationName(),
- IK_Direct);
+ IK_Direct,
+ ConstructorArgs);
if (!Constructor)
return ExprError();
- exprs.release();
- Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor,
- Ty, TyBeginLoc, Exprs,
- NumExprs, RParenLoc);
- return MaybeBindToTemporary(E);
+ OwningExprResult Result =
+ BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc,
+ move_arg(ConstructorArgs), RParenLoc);
+ if (Result.isInvalid())
+ return ExprError();
+
+ return MaybeBindToTemporary(Result.takeAs<Expr>());
}
// Fall through to value-initialize an object of class type that
@@ -255,18 +294,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
// complete object type or the (possibly cv-qualified) void type, creates an
// rvalue of the specified type, which is value-initialized.
//
- if (Ty->isArrayType())
- return ExprError(Diag(TyBeginLoc,
- diag::err_value_init_for_array_type) << FullRange);
- if (!Ty->isDependentType() && !Ty->isVoidType() &&
- RequireCompleteType(TyBeginLoc, Ty,
- diag::err_invalid_incomplete_type_use, FullRange))
- return ExprError();
-
- if (RequireNonAbstractType(TyBeginLoc, Ty,
- diag::err_allocation_of_abstract_type))
- return ExprError();
-
exprs.release();
return Owned(new (Context) CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc));
}
@@ -283,8 +310,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementRParen, bool ParenTypeId,
Declarator &D, SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen)
-{
+ SourceLocation ConstructorRParen) {
Expr *ArraySize = 0;
unsigned Skip = 0;
// If the specified type is an array, unwrap it and save the expression.
@@ -301,29 +327,37 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
Skip = 1;
}
- QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip);
- if (D.isInvalidType())
- return ExprError();
-
// Every dimension shall be of constant size.
- unsigned i = 1;
- QualType ElementType = AllocType;
- while (const ArrayType *Array = Context.getAsArrayType(ElementType)) {
- if (!Array->isConstantArrayType()) {
- Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst)
- << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange();
- return ExprError();
+ if (D.getNumTypeObjects() > 0 &&
+ D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
+ for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) {
+ if (D.getTypeObject(I).Kind != DeclaratorChunk::Array)
+ break;
+
+ DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
+ if (Expr *NumElts = (Expr *)Array.NumElts) {
+ if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() &&
+ !NumElts->isIntegerConstantExpr(Context)) {
+ Diag(D.getTypeObject(I).Loc, diag::err_new_array_nonconst)
+ << NumElts->getSourceRange();
+ return ExprError();
+ }
+ }
}
- ElementType = Array->getElementType();
- ++i;
}
+
+ //FIXME: Store DeclaratorInfo in CXXNew expression.
+ DeclaratorInfo *DInfo = 0;
+ QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip);
+ if (D.isInvalidType())
+ return ExprError();
- return BuildCXXNew(StartLoc, UseGlobal,
+ return BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ move(PlacementArgs),
PlacementRParen,
ParenTypeId,
- AllocType,
+ AllocType,
D.getSourceRange().getBegin(),
D.getSourceRange(),
Owned(ArraySize),
@@ -332,12 +366,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
ConstructorRParen);
}
-Sema::OwningExprResult
+Sema::OwningExprResult
Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- bool ParenTypeId,
+ bool ParenTypeId,
QualType AllocType,
SourceLocation TypeLoc,
SourceRange TypeRange,
@@ -369,12 +403,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
llvm::APSInt Value;
if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
if (Value < llvm::APSInt(
- llvm::APInt::getNullValue(Value.getBitWidth()), false))
+ llvm::APInt::getNullValue(Value.getBitWidth()),
+ Value.isUnsigned()))
return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
diag::err_typecheck_negative_array_size)
<< ArraySize->getSourceRange());
}
}
+
+ ImpCastExprToType(ArraySize, Context.getSizeType());
}
FunctionDecl *OperatorNew = 0;
@@ -413,17 +450,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
unsigned NumConsArgs = ConstructorArgs.size();
if (AllocType->isDependentType()) {
// Skip all the checks.
- }
- else if ((RT = AllocType->getAsRecordType()) &&
- !AllocType->isAggregateType()) {
+ } else if ((RT = AllocType->getAs<RecordType>()) &&
+ !AllocType->isAggregateType()) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+
Constructor = PerformInitializationByConstructor(
- AllocType, ConsArgs, NumConsArgs,
+ AllocType, move(ConstructorArgs),
TypeLoc,
SourceRange(TypeLoc, ConstructorRParen),
RT->getDecl()->getDeclName(),
- NumConsArgs != 0 ? IK_Direct : IK_Default);
+ NumConsArgs != 0 ? IK_Direct : IK_Default,
+ ConvertedConstructorArgs);
if (!Constructor)
return ExprError();
+
+ // Take the converted constructor arguments and use them for the new
+ // expression.
+ NumConsArgs = ConvertedConstructorArgs.size();
+ ConsArgs = (Expr **)ConvertedConstructorArgs.take();
} else {
if (!Init) {
// FIXME: Check that no subpart is const.
@@ -454,15 +498,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs,
NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init,
ConsArgs, NumConsArgs, OperatorDelete, ResultType,
- StartLoc, Init ? ConstructorRParen : SourceLocation()));
+ StartLoc, Init ? ConstructorRParen : SourceLocation()));
}
/// CheckAllocatedType - Checks that a type is suitable as the allocated type
/// in a new-expression.
/// dimension off and stores the size expression in ArraySize.
bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
- SourceRange R)
-{
+ SourceRange R) {
// C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
// abstract class type or array thereof.
if (AllocType->isFunctionType())
@@ -473,8 +516,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
<< AllocType << 1 << R;
else if (!AllocType->isDependentType() &&
RequireCompleteType(Loc, AllocType,
- diag::err_new_incomplete_type,
- R))
+ PDiag(diag::err_new_incomplete_type)
+ << R))
return true;
else if (RequireNonAbstractType(Loc, AllocType,
diag::err_allocation_of_abstract_type))
@@ -490,8 +533,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool IsArray, Expr **PlaceArgs,
unsigned NumPlaceArgs,
FunctionDecl *&OperatorNew,
- FunctionDecl *&OperatorDelete)
-{
+ 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
@@ -506,17 +548,18 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 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 (Context) IntegerLiteral(llvm::APInt::getNullValue(
- Context.Target.getPointerWidth(0)),
- Context.getSizeType(),
- SourceLocation());
+ IntegerLiteral Size(llvm::APInt::getNullValue(
+ Context.Target.getPointerWidth(0)),
+ Context.getSizeType(),
+ SourceLocation());
+ AllocArgs[0] = &Size;
std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
IsArray ? OO_Array_New : OO_New);
if (AllocType->isRecordType() && !UseGlobal) {
- CXXRecordDecl *Record
- = cast<CXXRecordDecl>(AllocType->getAsRecordType()->getDecl());
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
// FIXME: We fail to find inherited overloads.
if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
AllocArgs.size(), Record, /*AllowMissing=*/true,
@@ -537,10 +580,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// copy them back.
if (NumPlaceArgs > 0)
std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs);
-
- // FIXME: This is leaked on error. But so much is currently in Sema that it's
- // easier to clean it in one go.
- AllocArgs[0]->Destroy(Context);
+
return false;
}
@@ -549,24 +589,30 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, Expr** Args,
unsigned NumArgs, DeclContext *Ctx,
- bool AllowMissing, FunctionDecl *&Operator)
-{
- DeclContext::lookup_iterator Alloc, AllocEnd;
- llvm::tie(Alloc, AllocEnd) = Ctx->lookup(Name);
- if (Alloc == AllocEnd) {
+ bool AllowMissing, FunctionDecl *&Operator) {
+ LookupResult R;
+ LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName);
+ if (R.empty()) {
if (AllowMissing)
return false;
return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
}
+ // FIXME: handle ambiguity
+
OverloadCandidateSet Candidates;
- for (; Alloc != AllocEnd; ++Alloc) {
+ for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
+ Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
// static, so don't use AddMemberCandidate.
- if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc))
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) {
AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
/*SuppressUserConversions=*/false);
+ continue;
+ }
+
+ // FIXME: Handle function templates
}
// Do the resolution.
@@ -578,7 +624,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
- for (unsigned i = 1; i < NumArgs; ++i) {
+ for (unsigned i = 0; i < NumArgs; ++i) {
// FIXME: Passing word to diagnostic.
if (PerformCopyInitialization(Args[i],
FnDecl->getParamDecl(i)->getType(),
@@ -623,16 +669,52 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
/// @endcode
/// Note that the placement and nothrow forms of new are *not* implicitly
/// declared. Their use requires including \<new\>.
-void Sema::DeclareGlobalNewDelete()
-{
+void Sema::DeclareGlobalNewDelete() {
if (GlobalNewDeleteDeclared)
return;
+
+ // C++ [basic.std.dynamic]p2:
+ // [...] The following allocation and deallocation functions (18.4) are
+ // implicitly declared in global scope in each translation unit of a
+ // program
+ //
+ // 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();
+ //
+ // These implicit declarations introduce only the function names operator
+ // new, operator new[], operator delete, operator delete[].
+ //
+ // Here, we need to refer to std::bad_alloc, so we will implicitly declare
+ // "std" or "bad_alloc" as necessary to form the exception specification.
+ // However, we do not make these implicit declarations visible to name
+ // lookup.
+ if (!StdNamespace) {
+ // The "std" namespace has not yet been defined, so build one implicitly.
+ StdNamespace = NamespaceDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
+ &PP.getIdentifierTable().get("std"));
+ StdNamespace->setImplicit(true);
+ }
+
+ if (!StdBadAlloc) {
+ // The "std::bad_alloc" class has not yet been declared, so build it
+ // implicitly.
+ StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class,
+ StdNamespace,
+ SourceLocation(),
+ &PP.getIdentifierTable().get("bad_alloc"),
+ SourceLocation(), 0);
+ StdBadAlloc->setImplicit(true);
+ }
+
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);
@@ -650,8 +732,7 @@ void Sema::DeclareGlobalNewDelete()
/// DeclareGlobalAllocationFunction - Declares a single implicit global
/// allocation function if it doesn't already exist.
void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
- QualType Return, QualType Argument)
-{
+ QualType Return, QualType Argument) {
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
// Check if this function is already declared.
@@ -667,14 +748,26 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
}
}
- QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
+ QualType BadAllocType;
+ bool HasBadAllocExceptionSpec
+ = (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New);
+ if (HasBadAllocExceptionSpec) {
+ assert(StdBadAlloc && "Must have std::bad_alloc declared");
+ BadAllocType = Context.getTypeDeclType(StdBadAlloc);
+ }
+
+ QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
+ true, false,
+ HasBadAllocExceptionSpec? 1 : 0,
+ &BadAllocType);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
- FnType, FunctionDecl::None, false, true,
- SourceLocation());
+ FnType, /*DInfo=*/0, FunctionDecl::None, false, true);
Alloc->setImplicit();
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- 0, Argument, VarDecl::None, 0);
+ 0, Argument, /*DInfo=*/0,
+ VarDecl::None, 0);
Alloc->setParams(Context, &Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
@@ -689,43 +782,131 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
/// @code delete [] ptr; @endcode
Action::OwningExprResult
Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
- bool ArrayForm, ExprArg Operand)
-{
- // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type
- // having a single conversion function to a pointer type. The result has
- // type void."
+ bool ArrayForm, ExprArg Operand) {
+ // C++ [expr.delete]p1:
+ // The operand shall have a pointer type, or a class type having a single
+ // conversion function to a pointer type. The result has type void.
+ //
// DR599 amends "pointer type" to "pointer to object type" in both cases.
+ FunctionDecl *OperatorDelete = 0;
+
Expr *Ex = (Expr *)Operand.get();
if (!Ex->isTypeDependent()) {
QualType Type = Ex->getType();
- if (Type->isRecordType()) {
- // FIXME: Find that one conversion function and amend the type.
+ if (const RecordType *Record = Type->getAs<RecordType>()) {
+ llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ OverloadedFunctionDecl *Conversions =
+ RD->getVisibleConversionFunctions();
+
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Conversions->function_begin(),
+ FuncEnd = Conversions->function_end();
+ Func != FuncEnd; ++Func) {
+ // Skip over templated conversion functions; they aren't considered.
+ if (isa<FunctionTemplateDecl>(*Func))
+ continue;
+
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+
+ QualType ConvType = Conv->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ if (ConvPtrType->getPointeeType()->isObjectType())
+ ObjectPtrConversions.push_back(Conv);
+ }
+ if (ObjectPtrConversions.size() == 1) {
+ // We have a single conversion to a pointer-to-object type. Perform
+ // that conversion.
+ Operand.release();
+ if (!PerformImplicitConversion(Ex,
+ ObjectPtrConversions.front()->getConversionType(),
+ "converting")) {
+ Operand = Owned(Ex);
+ Type = Ex->getType();
+ }
+ }
+ else if (ObjectPtrConversions.size() > 1) {
+ Diag(StartLoc, diag::err_ambiguous_delete_operand)
+ << Type << Ex->getSourceRange();
+ for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
+ CXXConversionDecl *Conv = ObjectPtrConversions[i];
+ Diag(Conv->getLocation(), diag::err_ovl_candidate);
+ }
+ return ExprError();
+ }
}
if (!Type->isPointerType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
- QualType Pointee = Type->getAsPointerType()->getPointeeType();
+ QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
if (Pointee->isFunctionType() || Pointee->isVoidType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex->getSourceRange());
else if (!Pointee->isDependentType() &&
- RequireCompleteType(StartLoc, Pointee,
- diag::warn_delete_incomplete,
- Ex->getSourceRange()))
+ RequireCompleteType(StartLoc, Pointee,
+ PDiag(diag::warn_delete_incomplete)
+ << Ex->getSourceRange()))
return ExprError();
- // FIXME: Look up the correct operator delete overload and pass a pointer
- // along.
+ // C++ [expr.delete]p2:
+ // [Note: a pointer to a const type can be the operand of a
+ // delete-expression; it is not necessary to cast away the constness
+ // (5.2.11) of the pointer expression before it is used as the operand
+ // of the delete-expression. ]
+ ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy),
+ CastExpr::CK_NoOp);
+
+ // Update the operand.
+ Operand.take();
+ Operand = ExprArg(*this, Ex);
+
+ DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
+ ArrayForm ? OO_Array_Delete : OO_Delete);
+
+ if (Pointee->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl());
+
+ // Try to find operator delete/operator delete[] in class scope.
+ LookupResult Found;
+ LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName);
+ // FIXME: Diagnose ambiguity properly
+ assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled");
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F) {
+ if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
+ if (Delete->isUsualDeallocationFunction()) {
+ OperatorDelete = Delete;
+ break;
+ }
+ }
+
+ if (!Record->hasTrivialDestructor())
+ if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context))
+ MarkDeclarationReferenced(StartLoc,
+ const_cast<CXXDestructorDecl*>(Dtor));
+ }
+
+ if (!OperatorDelete) {
+ // Didn't find a member overload. Look for a global one.
+ DeclareGlobalNewDelete();
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
+ &Ex, 1, TUDecl, /*AllowMissing=*/false,
+ OperatorDelete))
+ return ExprError();
+ }
+
// FIXME: Check access and ambiguity of operator delete and destructor.
}
Operand.release();
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
- 0, Ex, StartLoc));
+ OperatorDelete, Ex, StartLoc));
}
@@ -747,8 +928,11 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class of condition decl.");
- QualType Ty = GetTypeForDeclarator(D, S);
-
+ // FIXME: Store DeclaratorInfo in the expression.
+ DeclaratorInfo *DInfo = 0;
+ TagDecl *OwnedTag = 0;
+ QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag);
+
if (Ty->isFunctionType()) { // The declarator shall not specify a function...
// We exit without creating a CXXConditionDeclExpr because a FunctionDecl
// would be created and CXXConditionDeclExpr wants a VarDecl.
@@ -757,18 +941,9 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
} else if (Ty->isArrayType()) { // ...or an array.
Diag(StartLoc, diag::err_invalid_use_of_array_type)
<< SourceRange(StartLoc, EqualLoc);
- } else if (const RecordType *RT = Ty->getAsRecordType()) {
- RecordDecl *RD = RT->getDecl();
- // The type-specifier-seq shall not declare a new class...
- if (RD->isDefinition() &&
- (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD))))
- Diag(RD->getLocation(), diag::err_type_defined_in_condition);
- } else if (const EnumType *ET = Ty->getAsEnumType()) {
- EnumDecl *ED = ET->getDecl();
- // ...or enumeration.
- if (ED->isDefinition() &&
- (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED))))
- Diag(ED->getLocation(), diag::err_type_defined_in_condition);
+ } else if (OwnedTag && OwnedTag->isDefinition()) {
+ // The type-specifier-seq shall not declare a new class or enumeration.
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition);
}
DeclPtrTy Dcl = ActOnDeclarator(S, D);
@@ -801,7 +976,7 @@ bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
/// conversion from a string literal to a pointer to non-const char or
/// non-const wchar_t (for narrow and wide string literals,
/// respectively).
-bool
+bool
Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
// Look inside the implicit cast, if it exists.
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From))
@@ -812,12 +987,12 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
// string literal can be converted to an rvalue of type "pointer
// to wchar_t" (C++ 4.2p2).
if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From))
- if (const PointerType *ToPtrType = ToType->getAsPointerType())
- if (const BuiltinType *ToPointeeType
- = ToPtrType->getPointeeType()->getAsBuiltinType()) {
+ if (const PointerType *ToPtrType = ToType->getAs<PointerType>())
+ if (const BuiltinType *ToPointeeType
+ = ToPtrType->getPointeeType()->getAs<BuiltinType>()) {
// This conversion is considered only when there is an
// explicit appropriate pointer target type (C++ 4.2p2).
- if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 &&
+ if (!ToPtrType->getPointeeType().hasQualifiers() &&
((StrLit->isWide() && ToPointeeType->isWideCharType()) ||
(!StrLit->isWide() &&
(ToPointeeType->getKind() == BuiltinType::Char_U ||
@@ -839,16 +1014,31 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const char *Flavor, bool AllowExplicit,
- bool Elidable)
-{
+ bool Elidable) {
ImplicitConversionSequence ICS;
+ return PerformImplicitConversion(From, ToType, Flavor, AllowExplicit,
+ Elidable, ICS);
+}
+
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor, bool AllowExplicit,
+ bool Elidable,
+ ImplicitConversionSequence& ICS) {
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
if (Elidable && getLangOptions().CPlusPlus0x) {
- ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false,
- AllowExplicit, /*ForceRValue*/true);
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*ForceRValue=*/true,
+ /*InOverloadResolution=*/false);
}
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
- ICS = TryImplicitConversion(From, ToType, false, AllowExplicit);
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
return PerformImplicitConversion(From, ToType, ICS, Flavor);
}
@@ -869,13 +1059,48 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return true;
break;
- case ImplicitConversionSequence::UserDefinedConversion:
- // FIXME: This is, of course, wrong. We'll need to actually call the
- // constructor or conversion operator, and then cope with the standard
- // conversions.
- ImpCastExprToType(From, ToType.getNonReferenceType(),
- ToType->isLValueReferenceType());
- return false;
+ case ImplicitConversionSequence::UserDefinedConversion: {
+
+ FunctionDecl *FD = ICS.UserDefined.ConversionFunction;
+ CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+ QualType BeforeToType;
+ if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) {
+ CastKind = CastExpr::CK_UserDefinedConversion;
+
+ // If the user-defined conversion is specified by a conversion function,
+ // the initial standard conversion sequence converts the source type to
+ // the implicit object parameter of the conversion function.
+ BeforeToType = Context.getTagDeclType(Conv->getParent());
+ } else if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(FD)) {
+ CastKind = CastExpr::CK_ConstructorConversion;
+
+ // If the user-defined conversion is specified by a constructor, the
+ // initial standard conversion sequence converts the source type to the
+ // type required by the argument of the constructor
+ BeforeToType = Ctor->getParamDecl(0)->getType();
+ }
+ else
+ assert(0 && "Unknown conversion function kind!");
+
+ if (PerformImplicitConversion(From, BeforeToType,
+ ICS.UserDefined.Before, "converting"))
+ return true;
+
+ OwningExprResult CastArg
+ = BuildCXXCastArgument(From->getLocStart(),
+ ToType.getNonReferenceType(),
+ CastKind, cast<CXXMethodDecl>(FD),
+ Owned(From));
+
+ if (CastArg.isInvalid())
+ return true;
+
+ From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
+ CastKind, CastArg.takeAs<Expr>(),
+ ToType->isLValueReferenceType());
+ return false;
+ }
case ImplicitConversionSequence::EllipsisConversion:
assert(false && "Cannot perform an ellipsis conversion");
@@ -895,7 +1120,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/// otherwise. The expression From is replaced with the converted
/// expression. Flavor is the context in which we're performing this
/// conversion, for use in error messages.
-bool
+bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
const char *Flavor) {
@@ -908,10 +1133,31 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
if (SCS.CopyConstructor) {
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
-
- // FIXME: Keep track of whether the copy constructor is elidable or not.
- From = CXXConstructExpr::Create(Context, ToType,
- SCS.CopyConstructor, false, &From, 1);
+ if (SCS.Second == ICK_Derived_To_Base) {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor),
+ MultiExprArg(*this, (void **)&From, 1),
+ /*FIXME:ConstructLoc*/SourceLocation(),
+ ConstructorArgs))
+ return true;
+ OwningExprResult FromResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ move_arg(ConstructorArgs));
+ if (FromResult.isInvalid())
+ return true;
+ From = FromResult.takeAs<Expr>();
+ return false;
+ }
+ OwningExprResult FromResult =
+ BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ MultiExprArg(*this, (void**)&From, 1));
+
+ if (FromResult.isInvalid())
+ return true;
+
+ From = FromResult.takeAs<Expr>();
return false;
}
@@ -924,7 +1170,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- ImpCastExprToType(From, FromType);
+ ImpCastExprToType(From, FromType, CastExpr::CK_ArrayToPointerDecay);
break;
case ICK_Function_To_Pointer:
@@ -940,7 +1186,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
FromType = From->getType();
}
FromType = Context.getPointerType(FromType);
- ImpCastExprToType(From, FromType);
+ ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
break;
default:
@@ -951,7 +1197,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// Perform the second implicit conversion
switch (SCS.Second) {
case ICK_Identity:
- // Nothing to do.
+ // If both sides are functions (or pointers/references to them), there could
+ // be incompatible exception declarations.
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+ // Nothing else to do.
break;
case ICK_Integral_Promotion:
@@ -968,26 +1218,32 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, FromType);
break;
- case ICK_Pointer_Conversion:
+ case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC) {
// Diagnose incompatible Objective-C conversions
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Flavor
<< From->getSourceRange();
}
- if (CheckPointerConversion(From, ToType))
+
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckPointerConversion(From, ToType, Kind))
return true;
- ImpCastExprToType(From, ToType);
+ ImpCastExprToType(From, ToType, Kind);
break;
-
- case ICK_Pointer_Member:
- if (CheckMemberPointerConversion(From, ToType))
+ }
+
+ case ICK_Pointer_Member: {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckMemberPointerConversion(From, ToType, Kind))
return true;
- ImpCastExprToType(From, ToType);
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
+ ImpCastExprToType(From, ToType, Kind);
break;
-
+ }
case ICK_Boolean_Conversion:
FromType = Context.BoolTy;
ImpCastExprToType(From, FromType);
@@ -1006,7 +1262,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Qualification:
// FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
// references.
- ImpCastExprToType(From, ToType.getNonReferenceType(),
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ CastExpr::CK_Unknown,
ToType->isLValueReferenceType());
break;
@@ -1023,34 +1280,38 @@ Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
SourceLocation LParen,
TypeTy *Ty,
SourceLocation RParen) {
- // FIXME: Some of the type traits have requirements. Interestingly, only the
- // __is_base_of requirement is explicitly stated to be diagnosed. Indeed, G++
- // accepts __is_pod(Incomplete) without complaints, and claims that the type
- // is indeed a POD.
+ QualType T = GetTypeFromParser(Ty);
+
+ // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
+ // all traits except __is_class, __is_enum and __is_union require a the type
+ // to be complete.
+ if (OTT != UTT_IsClass && OTT != UTT_IsEnum && OTT != UTT_IsUnion) {
+ if (RequireCompleteType(KWLoc, T,
+ diag::err_incomplete_type_used_in_type_trait_expr))
+ return ExprError();
+ }
// There is no point in eagerly computing the value. The traits are designed
// to be used from type trait templates, so Ty will be a template parameter
// 99% of the time.
- return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT,
- QualType::getFromOpaquePtr(Ty),
- RParen, Context.BoolTy));
+ return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, T,
+ RParen, Context.BoolTy));
}
QualType Sema::CheckPointerToMemberOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) {
const char *OpSpelling = isIndirect ? "->*" : ".*";
// C++ 5.5p2
// The binary operator .* [p3: ->*] binds its second operand, which shall
// be of type "pointer to member of T" (where T is a completely-defined
// class type) [...]
QualType RType = rex->getType();
- const MemberPointerType *MemPtr = RType->getAsMemberPointerType();
+ const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>();
if (!MemPtr) {
Diag(Loc, diag::err_bad_memptr_rhs)
<< OpSpelling << RType << rex->getSourceRange();
return QualType();
- }
+ }
QualType Class(MemPtr->getClass(), 0);
@@ -1060,7 +1321,7 @@ QualType Sema::CheckPointerToMemberOperands(
// such a class]
QualType LType = lex->getType();
if (isIndirect) {
- if (const PointerType *Ptr = LType->getAsPointerType())
+ if (const PointerType *Ptr = LType->getAs<PointerType>())
LType = Ptr->getPointeeType().getNonReferenceType();
else {
Diag(Loc, diag::err_bad_memptr_lhs)
@@ -1071,8 +1332,8 @@ QualType Sema::CheckPointerToMemberOperands(
if (Context.getCanonicalType(Class).getUnqualifiedType() !=
Context.getCanonicalType(LType).getUnqualifiedType()) {
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/false);
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
// FIXME: Would it be useful to print full ambiguity paths, or is that
// overkill?
if (!IsDerivedFrom(LType, Class, Paths) ||
@@ -1096,10 +1357,7 @@ QualType Sema::CheckPointerToMemberOperands(
// argument.
// We probably need a "MemberFunctionClosureType" or something like that.
QualType Result = MemPtr->getPointeeType();
- if (LType.isConstQualified())
- Result.addConst();
- if (LType.isVolatileQualified())
- Result.addVolatile();
+ Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers());
return Result;
}
@@ -1124,8 +1382,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) {
/// conversion.
static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
SourceLocation QuestionLoc,
- ImplicitConversionSequence &ICS)
-{
+ ImplicitConversionSequence &ICS) {
// C++0x 5.16p3
// The process for determining whether an operand expression E1 of type T1
// can be converted to match an operand expression E2 of type T2 is defined
@@ -1137,7 +1394,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// conversion the reference must bind directly to E1.
if (!Self.CheckReferenceInit(From,
Self.Context.getLValueReferenceType(To->getType()),
- &ICS))
+ To->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ &ICS))
{
assert((ICS.ConversionKind ==
ImplicitConversionSequence::StandardConversion ||
@@ -1157,8 +1418,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// the same or one is a base class of the other:
QualType FTy = From->getType();
QualType TTy = To->getType();
- const RecordType *FRec = FTy->getAsRecordType();
- const RecordType *TRec = TTy->getAsRecordType();
+ const RecordType *FRec = FTy->getAs<RecordType>();
+ const RecordType *TRec = TTy->getAs<RecordType>();
bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
if (FRec && TRec && (FRec == TRec ||
FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
@@ -1169,7 +1430,10 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// Could still fail if there's no copy constructor.
// FIXME: Is this a hard error then, or just a conversion failure? The
// standard doesn't say.
- ICS = Self.TryCopyInitialization(From, TTy);
+ ICS = Self.TryCopyInitialization(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
} else {
// -- Otherwise: E1 can be converted to match E2 if E1 can be
@@ -1178,12 +1442,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// First find the decayed type.
if (TTy->isFunctionType())
TTy = Self.Context.getPointerType(TTy);
- else if(TTy->isArrayType())
+ else if (TTy->isArrayType())
TTy = Self.Context.getArrayDecayedType(TTy);
// Now try the implicit conversion.
// FIXME: This doesn't detect ambiguities.
- ICS = Self.TryImplicitConversion(From, TTy);
+ ICS = Self.TryImplicitConversion(From, TTy,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
return false;
}
@@ -1239,8 +1507,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// second part of a standard conversion is ICK_DerivedToBase. This function
/// handles the reference binding specially.
static bool ConvertForConditional(Sema &Self, Expr *&E,
- const ImplicitConversionSequence &ICS)
-{
+ const ImplicitConversionSequence &ICS) {
if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
ICS.Standard.ReferenceBinding) {
assert(ICS.Standard.DirectBinding &&
@@ -1248,14 +1515,22 @@ static bool ConvertForConditional(Sema &Self, Expr *&E,
// FIXME: CheckReferenceInit should be able to reuse the ICS instead of
// redoing all the work.
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)));
+ TargetType(ICS)),
+ /*FIXME:*/E->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
}
if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
ICS.UserDefined.After.ReferenceBinding) {
assert(ICS.UserDefined.After.DirectBinding &&
"TryClassUnification should never generate indirect ref bindings");
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)));
+ TargetType(ICS)),
+ /*FIXME:*/E->getLocStart(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false);
}
if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
return true;
@@ -1412,27 +1687,48 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// containing class, and second-level cv-ness.
// cv-ness is not a union, but must match one of the two operands. (Which,
// frankly, is stupid.)
- const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType();
- const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType();
- if (LMemPtr && RHS->isNullPointerConstant(Context)) {
+ const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>();
+ const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>();
+ if (LMemPtr &&
+ RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(RHS, LTy);
return LTy;
}
- if (RMemPtr && LHS->isNullPointerConstant(Context)) {
+ if (RMemPtr &&
+ LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(LHS, RTy);
return RTy;
}
if (LMemPtr && RMemPtr) {
QualType LPointee = LMemPtr->getPointeeType();
QualType RPointee = RMemPtr->getPointeeType();
+
+ QualifierCollector LPQuals, RPQuals;
+ const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee));
+ const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee));
+
// First, we check that the unqualified pointee type is the same. If it's
// not, there's no conversion that will unify the two pointers.
- if (Context.getCanonicalType(LPointee).getUnqualifiedType() ==
- Context.getCanonicalType(RPointee).getUnqualifiedType()) {
- // Second, we take the greater of the two cv qualifications. If neither
+ if (LPCan == RPCan) {
+
+ // Second, we take the greater of the two qualifications. If neither
// is greater than the other, the conversion is not possible.
- unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers();
- if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){
+
+ Qualifiers MergedQuals = LPQuals + RPQuals;
+
+ bool CompatibleQuals = true;
+ if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() &&
+ MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers())
+ CompatibleQuals = false;
+ else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace())
+ // FIXME:
+ // C99 6.5.15 as modified by TR 18037:
+ // If the second and third operands are pointers into different
+ // address spaces, the address spaces must overlap.
+ CompatibleQuals = false;
+ // FIXME: GC qualifiers?
+
+ if (CompatibleQuals) {
// Third, we check if either of the container classes is derived from
// the other.
QualType LContainer(LMemPtr->getClass(), 0);
@@ -1450,8 +1746,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// The type 'Q Pointee (MoreDerived::*)' is the common type.
// We don't use ImpCastExprToType here because this could still fail
// for ambiguous or inaccessible conversions.
- QualType Common = Context.getMemberPointerType(
- LPointee.getQualifiedType(Q), MoreDerived.getTypePtr());
+ LPointee = Context.getQualifiedType(LPointee, MergedQuals);
+ QualType Common
+ = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr());
if (PerformImplicitConversion(LHS, Common, "converting"))
return QualType();
if (PerformImplicitConversion(RHS, Common, "converting"))
@@ -1470,30 +1767,37 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// \brief Find a merged pointer type and convert the two expressions to it.
///
-/// This finds the composite pointer type for @p E1 and @p E2 according to
-/// C++0x 5.9p2. It converts both expressions to this type and returns it.
+/// This finds the composite pointer type (or member pointer type) for @p E1
+/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this
+/// type and returns it.
/// It does not emit diagnostics.
QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
assert(getLangOptions().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
- if(!T1->isPointerType() && !T2->isPointerType())
- return QualType();
+
+ if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+ !T2->isPointerType() && !T2->isMemberPointerType())
+ return QualType();
+
+ // FIXME: Do we need to work on the canonical types?
// C++0x 5.9p2
// Pointer conversions and qualification conversions are performed on
// pointer operands to bring them to their composite pointer type. If
// one operand is a null pointer constant, the composite pointer type is
// the type of the other operand.
- if (E1->isNullPointerConstant(Context)) {
+ if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(E1, T2);
return T2;
}
- if (E2->isNullPointerConstant(Context)) {
+ if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(E2, T1);
return T1;
}
- // Now both have to be pointers.
- if(!T1->isPointerType() || !T2->isPointerType())
+
+ // Now both have to be pointers or member pointers.
+ if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+ !T2->isPointerType() && !T2->isMemberPointerType())
return QualType();
// Otherwise, of one of the operands has type "pointer to cv1 void," then
@@ -1506,32 +1810,93 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
// What we do here is, we build the two possible composite types, and try the
// conversions in both directions. If only one works, or if the two composite
// types are the same, we have succeeded.
+ // FIXME: extended qualifiers?
llvm::SmallVector<unsigned, 4> QualifierUnion;
+ llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
QualType Composite1 = T1, Composite2 = T2;
- const PointerType *Ptr1, *Ptr2;
- while ((Ptr1 = Composite1->getAsPointerType()) &&
- (Ptr2 = Composite2->getAsPointerType())) {
- Composite1 = Ptr1->getPointeeType();
- Composite2 = Ptr2->getPointeeType();
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- }
- // Rewrap the composites as pointers with the union CVRs.
- for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(),
- E = QualifierUnion.end(); I != E; ++I) {
- Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I));
- Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I));
+ do {
+ const PointerType *Ptr1, *Ptr2;
+ if ((Ptr1 = Composite1->getAs<PointerType>()) &&
+ (Ptr2 = Composite2->getAs<PointerType>())) {
+ Composite1 = Ptr1->getPointeeType();
+ Composite2 = Ptr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
+ continue;
+ }
+
+ const MemberPointerType *MemPtr1, *MemPtr2;
+ if ((MemPtr1 = Composite1->getAs<MemberPointerType>()) &&
+ (MemPtr2 = Composite2->getAs<MemberPointerType>())) {
+ Composite1 = MemPtr1->getPointeeType();
+ Composite2 = MemPtr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
+ MemPtr2->getClass()));
+ continue;
+ }
+
+ // FIXME: block pointer types?
+
+ // Cannot unwrap any more types.
+ break;
+ } while (true);
+
+ // Rewrap the composites as pointers or member pointers with the union CVRs.
+ llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC
+ = MemberOfClass.begin();
+ for (llvm::SmallVector<unsigned, 4>::iterator
+ I = QualifierUnion.begin(),
+ E = QualifierUnion.end();
+ I != E; (void)++I, ++MOC) {
+ Qualifiers Quals = Qualifiers::fromCVRMask(*I);
+ if (MOC->first && MOC->second) {
+ // Rebuild member pointer type
+ Composite1 = Context.getMemberPointerType(
+ Context.getQualifiedType(Composite1, Quals),
+ MOC->first);
+ Composite2 = Context.getMemberPointerType(
+ Context.getQualifiedType(Composite2, Quals),
+ MOC->second);
+ } else {
+ // Rebuild pointer type
+ Composite1
+ = Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
+ Composite2
+ = Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
+ }
}
- ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1);
- ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1);
+ ImplicitConversionSequence E1ToC1 =
+ TryImplicitConversion(E1, Composite1,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ ImplicitConversionSequence E2ToC1 =
+ TryImplicitConversion(E2, Composite1,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+
ImplicitConversionSequence E1ToC2, E2ToC2;
E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
- E1ToC2 = TryImplicitConversion(E1, Composite2);
- E2ToC2 = TryImplicitConversion(E2, Composite2);
+ E1ToC2 = TryImplicitConversion(E1, Composite2,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ E2ToC2 = TryImplicitConversion(E2, Composite2,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
}
bool ToC1Viable = E1ToC1.ConversionKind !=
@@ -1556,84 +1921,264 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
}
Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
- const RecordType *RT = E->getType()->getAsRecordType();
+ if (!Context.getLangOptions().CPlusPlus)
+ return Owned(E);
+
+ const RecordType *RT = E->getType()->getAs<RecordType>();
if (!RT)
return Owned(E);
-
+
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialDestructor())
return Owned(E);
-
- CXXTemporary *Temp = CXXTemporary::Create(Context,
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ QualType Ty = CE->getCallee()->getType();
+ if (const PointerType *PT = Ty->getAs<PointerType>())
+ Ty = PT->getPointeeType();
+
+ const FunctionType *FTy = Ty->getAs<FunctionType>();
+ if (FTy->getResultType()->isReferenceType())
+ return Owned(E);
+ }
+ CXXTemporary *Temp = CXXTemporary::Create(Context,
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
- MarkDestructorReferenced(E->getExprLoc(), E->getType());
+ if (CXXDestructorDecl *Destructor =
+ const_cast<CXXDestructorDecl*>(RD->getDestructor(Context)))
+ MarkDeclarationReferenced(E->getExprLoc(), Destructor);
// FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
-// FIXME: This doesn't handle casts yet.
-Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) {
- const RecordType *RT = E->getType()->getAsRecordType();
- if (!RT)
- return E;
-
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDestructor())
- return E;
-
- /// The expr passed in must be a CXXExprWithTemporaries.
- CXXExprWithTemporaries *TempExpr = dyn_cast<CXXExprWithTemporaries>(E);
- if (!TempExpr)
- return E;
-
- Expr *SubExpr = TempExpr->getSubExpr();
- if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) {
- assert(BE->getTemporary() ==
- TempExpr->getTemporary(TempExpr->getNumTemporaries() - 1) &&
- "Found temporary is not last in list!");
-
- Expr *BindSubExpr = BE->getSubExpr();
- BE->setSubExpr(0);
-
- if (TempExpr->getNumTemporaries() == 1) {
- // There's just one temporary left, so we don't need the TempExpr node.
- TempExpr->Destroy(Context);
- return BindSubExpr;
- } else {
- TempExpr->removeLastTemporary();
- TempExpr->setSubExpr(BindSubExpr);
- BE->Destroy(Context);
- }
-
- return E;
- }
-
- // FIXME: We might need to handle other expressions here.
- return E;
-}
-
-Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
+Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
bool ShouldDestroyTemps) {
assert(SubExpr && "sub expression can't be null!");
-
+
if (ExprTemporaries.empty())
return SubExpr;
-
+
Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr,
- &ExprTemporaries[0],
+ &ExprTemporaries[0],
ExprTemporaries.size(),
ShouldDestroyTemps);
ExprTemporaries.clear();
-
+
return E;
}
+Sema::OwningExprResult
+Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, TypeTy *&ObjectType) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
+ Expr *BaseExpr = (Expr*)Base.get();
+ assert(BaseExpr && "no record expansion");
+
+ QualType BaseType = BaseExpr->getType();
+ if (BaseType->isDependentType()) {
+ // FIXME: member of the current instantiation
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+ }
+
+ // C++ [over.match.oper]p8:
+ // [...] When operator->returns, the operator-> is applied to the value
+ // returned, with the original second operand.
+ if (OpKind == tok::arrow) {
+ // The set of types we've considered so far.
+ llvm::SmallPtrSet<CanQualType,8> CTypes;
+ llvm::SmallVector<SourceLocation, 8> Locations;
+ CTypes.insert(Context.getCanonicalType(BaseType));
+
+ while (BaseType->isRecordType()) {
+ Base = BuildOverloadedArrowExpr(S, move(Base), OpLoc);
+ BaseExpr = (Expr*)Base.get();
+ if (BaseExpr == NULL)
+ return ExprError();
+ if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(BaseExpr))
+ Locations.push_back(OpCall->getDirectCallee()->getLocation());
+ BaseType = BaseExpr->getType();
+ CanQualType CBaseType = Context.getCanonicalType(BaseType);
+ if (!CTypes.insert(CBaseType)) {
+ Diag(OpLoc, diag::err_operator_arrow_circular);
+ for (unsigned i = 0; i < Locations.size(); i++)
+ Diag(Locations[i], diag::note_declared_at);
+ return ExprError();
+ }
+ }
+ }
+
+ if (BaseType->isPointerType())
+ BaseType = BaseType->getPointeeType();
+
+ // We could end up with various non-record types here, such as extended
+ // vector types or Objective-C interfaces. Just return early and let
+ // ActOnMemberReferenceExpr do the work.
+ if (!BaseType->isRecordType()) {
+ // C++ [basic.lookup.classref]p2:
+ // [...] If the type of the object expression is of pointer to scalar
+ // type, the unqualified-id is looked up in the context of the complete
+ // postfix-expression.
+ ObjectType = 0;
+ return move(Base);
+ }
+
+ // C++ [basic.lookup.classref]p2:
+ // If the id-expression in a class member access (5.2.5) is an
+ // unqualified-id, and the type of the object expres- sion is of a class
+ // type C (or of pointer to a class type C), the unqualified-id is looked
+ // up in the scope of class C. [...]
+ ObjectType = BaseType.getAsOpaquePtr();
+ return move(Base);
+}
+
+Sema::OwningExprResult
+Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ IdentifierInfo *ClassName,
+ const CXXScopeSpec &SS,
+ bool HasTrailingLParen) {
+ if (SS.isInvalid())
+ return ExprError();
+
+ QualType BaseType;
+ if (isUnknownSpecialization(SS))
+ BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ ClassName);
+ else {
+ TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS);
+ if (!BaseTy) {
+ Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << ClassName;
+ return ExprError();
+ }
+
+ BaseType = GetTypeFromParser(BaseTy);
+ }
+
+ CanQualType CanBaseType = Context.getCanonicalType(BaseType);
+ DeclarationName DtorName =
+ Context.DeclarationNames.getCXXDestructorName(CanBaseType);
+
+ OwningExprResult Result
+ = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ DtorName, DeclPtrTy(), &SS);
+ if (Result.isInvalid() || HasTrailingLParen)
+ return move(Result);
+
+ // The only way a reference to a destructor can be used is to
+ // immediately call them. Since the next token is not a '(', produce a
+ // diagnostic and build the call now.
+ Expr *E = (Expr *)Result.get();
+ SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd());
+ Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+ << isa<CXXPseudoDestructorExpr>(E)
+ << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+
+ return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
+ MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
+}
+
+Sema::OwningExprResult
+Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ OverloadedOperatorKind OverOpKind,
+ const CXXScopeSpec *SS) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OverOpKind);
+
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ Name, DeclPtrTy(), SS);
+}
+
+Sema::OwningExprResult
+Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation ClassNameLoc,
+ TypeTy *Ty,
+ const CXXScopeSpec *SS) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ //FIXME: Preserve type source info.
+ QualType ConvType = GetTypeFromParser(Ty);
+ CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName =
+ Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
+
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
+ ConvName, DeclPtrTy(), SS);
+}
+
+CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
+ CXXMethodDecl *Method) {
+ MemberExpr *ME =
+ new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method,
+ SourceLocation(), Method->getType());
+ QualType ResultType;
+ if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method))
+ ResultType = Conv->getConversionType().getNonReferenceType();
+ else
+ ResultType = Method->getResultType().getNonReferenceType();
+
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, ME, 0, 0,
+ ResultType,
+ SourceLocation());
+ return CE;
+}
+
+Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ ExprArg Arg) {
+ Expr *From = Arg.takeAs<Expr>();
+
+ switch (Kind) {
+ default: assert(0 && "Unhandled cast kind!");
+ case CastExpr::CK_ConstructorConversion: {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+
+ if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ MultiExprArg(*this, (void **)&From, 1),
+ CastLoc, ConstructorArgs))
+ return ExprError();
+
+ return BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ move_arg(ConstructorArgs));
+ }
+
+ case CastExpr::CK_UserDefinedConversion: {
+ assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
+
+ // Cast to base if needed.
+ if (PerformObjectArgumentInitialization(From, Method))
+ return ExprError();
+
+ // Create an implicit call expr that calls it.
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method);
+ return Owned(CE);
+ }
+ }
+}
+
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
- FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
+ FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr,
/*ShouldDestroyTemps=*/true);
+
return Owned(FullExpr);
}
OpenPOWER on IntegriCloud