summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-03-03 17:28:16 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-03-03 17:28:16 +0000
commitdf90325d4c0a65ee64d2dae3ed9b5b34f7418533 (patch)
treee1a885aadfd80632f5bd70d4bd2d37e715e35a79 /lib/Sema/SemaExprCXX.cpp
parentfd035e6496665b1f1197868e21cb0a4594e8db6e (diff)
downloadFreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.zip
FreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.tar.gz
Update clang to 97654.
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp787
1 files changed, 764 insertions, 23 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 9eeda54..5f46019 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -17,13 +17,278 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Template.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
+Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
+ IdentifierInfo &II,
+ SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec &SS,
+ TypeTy *ObjectTypePtr,
+ bool EnteringContext) {
+ // Determine where to perform name lookup.
+
+ // FIXME: This area of the standard is very messy, and the current
+ // wording is rather unclear about which scopes we search for the
+ // destructor name; see core issues 399 and 555. Issue 399 in
+ // particular shows where the current description of destructor name
+ // lookup is completely out of line with existing practice, e.g.,
+ // this appears to be ill-formed:
+ //
+ // namespace N {
+ // template <typename T> struct S {
+ // ~S();
+ // };
+ // }
+ //
+ // void f(N::S<int>* s) {
+ // s->N::S<int>::~S();
+ // }
+ //
+ // See also PR6358 and PR6359.
+ QualType SearchType;
+ DeclContext *LookupCtx = 0;
+ bool isDependent = false;
+ bool LookInScope = false;
+
+ // If we have an object type, it's because we are in a
+ // pseudo-destructor-expression or a member access expression, and
+ // we know what type we're looking for.
+ if (ObjectTypePtr)
+ SearchType = GetTypeFromParser(ObjectTypePtr);
+
+ if (SS.isSet()) {
+ NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+
+ bool AlreadySearched = false;
+ bool LookAtPrefix = true;
+ if (!getLangOptions().CPlusPlus0x) {
+ // C++ [basic.lookup.qual]p6:
+ // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier,
+ // the type-names are looked up as types in the scope designated by the
+ // nested-name-specifier. In a qualified-id of the form:
+ //
+ // ::[opt] nested-name-specifier ̃ class-name
+ //
+ // where the nested-name-specifier designates a namespace scope, and in
+ // a qualified-id of the form:
+ //
+ // ::opt nested-name-specifier class-name :: ̃ class-name
+ //
+ // the class-names are looked up as types in the scope designated by
+ // the nested-name-specifier.
+ //
+ // Here, we check the first case (completely) and determine whether the
+ // code below is permitted to look at the prefix of the
+ // nested-name-specifier (as we do in C++0x).
+ DeclContext *DC = computeDeclContext(SS, EnteringContext);
+ if (DC && DC->isFileContext()) {
+ AlreadySearched = true;
+ LookupCtx = DC;
+ isDependent = false;
+ } else if (DC && isa<CXXRecordDecl>(DC))
+ LookAtPrefix = false;
+ }
+
+ // C++0x [basic.lookup.qual]p6:
+ // If a pseudo-destructor-name (5.2.4) contains a
+ // nested-name-specifier, the type-names are looked up as types
+ // in the scope designated by the nested-name-specifier. Similarly, in
+ // a qualified-id of the form:
+ //
+ // :: [opt] nested-name-specifier[opt] class-name :: ~class-name
+ //
+ // the second class-name is looked up in the same scope as the first.
+ //
+ // To implement this, we look at the prefix of the
+ // nested-name-specifier we were given, and determine the lookup
+ // context from that.
+ //
+ // We also fold in the second case from the C++03 rules quoted further
+ // above.
+ NestedNameSpecifier *Prefix = 0;
+ if (AlreadySearched) {
+ // Nothing left to do.
+ } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) {
+ CXXScopeSpec PrefixSS;
+ PrefixSS.setScopeRep(Prefix);
+ LookupCtx = computeDeclContext(PrefixSS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(PrefixSS);
+ } else if (getLangOptions().CPlusPlus0x &&
+ (LookupCtx = computeDeclContext(SS, EnteringContext))) {
+ if (!LookupCtx->isTranslationUnit())
+ LookupCtx = LookupCtx->getParent();
+ isDependent = LookupCtx && LookupCtx->isDependentContext();
+ } else if (ObjectTypePtr) {
+ LookupCtx = computeDeclContext(SearchType);
+ isDependent = SearchType->isDependentType();
+ } else {
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ isDependent = LookupCtx && LookupCtx->isDependentContext();
+ }
+
+ LookInScope = false;
+ } else if (ObjectTypePtr) {
+ // C++ [basic.lookup.classref]p3:
+ // If the unqualified-id is ~type-name, the type-name is looked up
+ // in the context of the entire postfix-expression. If the type T
+ // of the object expression is of a class type C, the type-name is
+ // also looked up in the scope of class C. At least one of the
+ // lookups shall find a name that refers to (possibly
+ // cv-qualified) T.
+ LookupCtx = computeDeclContext(SearchType);
+ isDependent = SearchType->isDependentType();
+ assert((isDependent || !SearchType->isIncompleteType()) &&
+ "Caller should have completed object type");
+
+ LookInScope = true;
+ } else {
+ // Perform lookup into the current scope (only).
+ LookInScope = true;
+ }
+
+ LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName);
+ for (unsigned Step = 0; Step != 2; ++Step) {
+ // Look for the name first in the computed lookup context (if we
+ // have one) and, if that fails to find a match, in the sope (if
+ // we're allowed to look there).
+ Found.clear();
+ if (Step == 0 && LookupCtx)
+ LookupQualifiedName(Found, LookupCtx);
+ else if (Step == 1 && LookInScope && S)
+ LookupName(Found, S);
+ else
+ continue;
+
+ // FIXME: Should we be suppressing ambiguities here?
+ if (Found.isAmbiguous())
+ return 0;
+
+ if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
+ QualType T = Context.getTypeDeclType(Type);
+ // If we found the injected-class-name of a class template, retrieve the
+ // type of that template.
+ // FIXME: We really shouldn't need to do this.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Type))
+ if (Record->isInjectedClassName())
+ if (Record->getDescribedClassTemplate())
+ T = Record->getDescribedClassTemplate()
+ ->getInjectedClassNameType(Context);
+
+ if (SearchType.isNull() || SearchType->isDependentType() ||
+ Context.hasSameUnqualifiedType(T, SearchType)) {
+ // We found our type!
+
+ return T.getAsOpaquePtr();
+ }
+ }
+
+ // If the name that we found is a class template name, and it is
+ // the same name as the template name in the last part of the
+ // nested-name-specifier (if present) or the object type, then
+ // this is the destructor for that class.
+ // FIXME: This is a workaround until we get real drafting for core
+ // issue 399, for which there isn't even an obvious direction.
+ if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) {
+ QualType MemberOfType;
+ if (SS.isSet()) {
+ if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) {
+ // Figure out the type of the context, if it has one.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx))
+ MemberOfType = Context.getTypeDeclType(Spec);
+ else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (Record->getDescribedClassTemplate())
+ MemberOfType = Record->getDescribedClassTemplate()
+ ->getInjectedClassNameType(Context);
+ else
+ MemberOfType = Context.getTypeDeclType(Record);
+ }
+ }
+ }
+ if (MemberOfType.isNull())
+ MemberOfType = SearchType;
+
+ if (MemberOfType.isNull())
+ continue;
+
+ // We're referring into a class template specialization. If the
+ // class template we found is the same as the template being
+ // specialized, we found what we are looking for.
+ if (const RecordType *Record = MemberOfType->getAs<RecordType>()) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
+ if (Spec->getSpecializedTemplate()->getCanonicalDecl() ==
+ Template->getCanonicalDecl())
+ return MemberOfType.getAsOpaquePtr();
+ }
+
+ continue;
+ }
+
+ // We're referring to an unresolved class template
+ // specialization. Determine whether we class template we found
+ // is the same as the template being specialized or, if we don't
+ // know which template is being specialized, that it at least
+ // has the same name.
+ if (const TemplateSpecializationType *SpecType
+ = MemberOfType->getAs<TemplateSpecializationType>()) {
+ TemplateName SpecName = SpecType->getTemplateName();
+
+ // The class template we found is the same template being
+ // specialized.
+ if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) {
+ if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl())
+ return MemberOfType.getAsOpaquePtr();
+
+ continue;
+ }
+
+ // The class template we found has the same name as the
+ // (dependent) template name being specialized.
+ if (DependentTemplateName *DepTemplate
+ = SpecName.getAsDependentTemplateName()) {
+ if (DepTemplate->isIdentifier() &&
+ DepTemplate->getIdentifier() == Template->getIdentifier())
+ return MemberOfType.getAsOpaquePtr();
+
+ continue;
+ }
+ }
+ }
+ }
+
+ if (isDependent) {
+ // We didn't find our type, but that's okay: it's dependent
+ // anyway.
+ NestedNameSpecifier *NNS = 0;
+ SourceRange Range;
+ if (SS.isSet()) {
+ NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ Range = SourceRange(SS.getRange().getBegin(), NameLoc);
+ } else {
+ NNS = NestedNameSpecifier::Create(Context, &II);
+ Range = SourceRange(NameLoc);
+ }
+
+ return CheckTypenameType(NNS, II, Range).getAsOpaquePtr();
+ }
+
+ if (ObjectTypePtr)
+ Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << &II;
+ else
+ Diag(NameLoc, diag::err_destructor_class_name);
+
+ return 0;
+}
+
/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
@@ -161,6 +426,18 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
: diag::err_throw_incomplete)
<< E->getSourceRange()))
return true;
+
+ // FIXME: This is just a hack to mark the copy constructor referenced.
+ // This should go away when the next FIXME is fixed.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialCopyConstructor())
+ return false;
+ CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0);
+ MarkDeclarationReferenced(ThrowLoc, CopyCtor);
}
// FIXME: Construct a temporary here.
@@ -515,6 +792,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
ConsArgs = (Expr **)ConvertedConstructorArgs.take();
}
+ // Mark the new and delete operators as referenced.
+ if (OperatorNew)
+ MarkDeclarationReferenced(StartLoc, OperatorNew);
+ if (OperatorDelete)
+ MarkDeclarationReferenced(StartLoc, OperatorDelete);
+
// FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
PlacementArgs.release();
@@ -554,6 +837,20 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
return false;
}
+/// \brief Determine whether the given function is a non-placement
+/// deallocation function.
+static bool isNonPlacementDeallocationFunction(FunctionDecl *FD) {
+ if (FD->isInvalidDecl())
+ return false;
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
+ return Method->isUsualDeallocationFunction();
+
+ return ((FD->getOverloadedOperator() == OO_Delete ||
+ FD->getOverloadedOperator() == OO_Array_Delete) &&
+ FD->getNumParams() == 1);
+}
+
/// FindAllocationFunctions - Finds the overloads of operator new and delete
/// that are appropriate for the allocation.
bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
@@ -570,7 +867,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 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.
@@ -583,12 +879,20 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
AllocArgs[0] = &Size;
std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
+ // C++ [expr.new]p8:
+ // If the allocated type is a non-array type, the allocation
+ // function’s name is operator new and the deallocation function’s
+ // name is operator delete. If the allocated type is an array
+ // type, the allocation function’s name is operator new[] and the
+ // deallocation function’s name is operator delete[].
DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
IsArray ? OO_Array_New : OO_New);
+ DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
+ IsArray ? OO_Array_Delete : OO_Delete);
+
if (AllocType->isRecordType() && !UseGlobal) {
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,
OperatorNew))
@@ -609,6 +913,110 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
if (NumPlaceArgs > 0)
std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs);
+ // C++ [expr.new]p19:
+ //
+ // If the new-expression begins with a unary :: operator, the
+ // deallocation function’s name is looked up in the global
+ // scope. Otherwise, if the allocated type is a class type T or an
+ // array thereof, the deallocation function’s name is looked up in
+ // the scope of T. If this lookup fails to find the name, or if
+ // the allocated type is not a class type or array thereof, the
+ // deallocation function’s name is looked up in the global scope.
+ LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName);
+ if (AllocType->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *RD
+ = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl());
+ LookupQualifiedName(FoundDelete, RD);
+ }
+
+ if (FoundDelete.empty()) {
+ DeclareGlobalNewDelete();
+ LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl());
+ }
+
+ FoundDelete.suppressDiagnostics();
+ llvm::SmallVector<NamedDecl *, 4> Matches;
+ if (NumPlaceArgs > 1) {
+ // C++ [expr.new]p20:
+ // A declaration of a placement deallocation function matches the
+ // declaration of a placement allocation function if it has the
+ // same number of parameters and, after parameter transformations
+ // (8.3.5), all parameter types except the first are
+ // identical. [...]
+ //
+ // To perform this comparison, we compute the function type that
+ // the deallocation function should have, and use that type both
+ // for template argument deduction and for comparison purposes.
+ QualType ExpectedFunctionType;
+ {
+ const FunctionProtoType *Proto
+ = OperatorNew->getType()->getAs<FunctionProtoType>();
+ llvm::SmallVector<QualType, 4> ArgTypes;
+ ArgTypes.push_back(Context.VoidPtrTy);
+ for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I)
+ ArgTypes.push_back(Proto->getArgType(I));
+
+ ExpectedFunctionType
+ = Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
+ ArgTypes.size(),
+ Proto->isVariadic(),
+ 0, false, false, 0, 0, false, CC_Default);
+ }
+
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ FunctionDecl *Fn = 0;
+ if (FunctionTemplateDecl *FnTmpl
+ = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
+ // Perform template argument deduction to try to match the
+ // expected function type.
+ TemplateDeductionInfo Info(Context, StartLoc);
+ if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info))
+ continue;
+ } else
+ Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
+
+ if (Context.hasSameType(Fn->getType(), ExpectedFunctionType))
+ Matches.push_back(Fn);
+ }
+ } else {
+ // C++ [expr.new]p20:
+ // [...] Any non-placement deallocation function matches a
+ // non-placement allocation function. [...]
+ for (LookupResult::iterator D = FoundDelete.begin(),
+ DEnd = FoundDelete.end();
+ D != DEnd; ++D) {
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
+ if (isNonPlacementDeallocationFunction(Fn))
+ Matches.push_back(*D);
+ }
+ }
+
+ // C++ [expr.new]p20:
+ // [...] If the lookup finds a single matching deallocation
+ // function, that function will be called; otherwise, no
+ // deallocation function will be called.
+ if (Matches.size() == 1) {
+ // FIXME: Drops access, using-declaration info!
+ OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl());
+
+ // C++0x [expr.new]p20:
+ // If the lookup finds the two-parameter form of a usual
+ // deallocation function (3.7.4.2) and that function, considered
+ // as a placement deallocation function, would have been
+ // selected as a match for the allocation function, the program
+ // is ill-formed.
+ if (NumPlaceArgs && getLangOptions().CPlusPlus0x &&
+ isNonPlacementDeallocationFunction(OperatorDelete)) {
+ Diag(StartLoc, diag::err_placement_new_non_placement_delete)
+ << SourceRange(PlaceArgs[0]->getLocStart(),
+ PlaceArgs[NumPlaceArgs - 1]->getLocEnd());
+ Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
+ << DeleteName;
+ }
+ }
+
return false;
}
@@ -802,7 +1210,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
true, false,
HasBadAllocExceptionSpec? 1 : 0,
- &BadAllocType);
+ &BadAllocType, false, CC_Default);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
@@ -1079,8 +1487,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
bool Elidable,
ImplicitConversionSequence& ICS) {
- ICS.setBad();
- ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
if (Elidable && getLangOptions().CPlusPlus0x) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
@@ -1379,6 +1786,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, ToType.getNonReferenceType(),
CastExpr::CK_NoOp,
ToType->isLValueReferenceType());
+
+ if (SCS.DeprecatedStringLiteralToCharPtr)
+ Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
+ << ToType.getNonReferenceType();
+
break;
default:
@@ -1494,6 +1906,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) {
return ICS.UserDefined.After.getToType(2);
case ImplicitConversionSequence::AmbiguousConversion:
return ICS.Ambiguous.getToType();
+
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::BadConversion:
llvm_unreachable("function not valid for ellipsis or bad conversions");
@@ -1537,7 +1950,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
return false;
}
}
- ICS.setBad();
+
// -- If E2 is an rvalue, or if the conversion above cannot be done:
// -- if E1 and E2 have class type, and the underlying class types are
// the same or one is a base class of the other:
@@ -1551,14 +1964,22 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// E1 can be converted to match E2 if the class of T2 is the
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
- if ((FRec == TRec || FDerivedFromT) && TTy.isAtLeastAsQualifiedAs(FTy)) {
- // 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,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
+ if (FRec == TRec || FDerivedFromT) {
+ if (TTy.isAtLeastAsQualifiedAs(FTy)) {
+ // 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,
+ /*SuppressUserConversions=*/false,
+ /*ForceRValue=*/false,
+ /*InOverloadResolution=*/false);
+ } else {
+ ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy);
+ }
+ } else {
+ // Can't implicitly convert FTy to a derived class TTy.
+ // TODO: more specific error for this.
+ ICS.setBad(BadConversionSequence::no_conversion, From, TTy);
}
} else {
// -- Otherwise: E1 can be converted to match E2 if E1 can be
@@ -1807,9 +2228,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// performed to bring them to a common type, whose cv-qualification
// shall match the cv-qualification of either the second or the third
// operand. The result is of the common type.
- QualType Composite = FindCompositePointerType(LHS, RHS);
- if (!Composite.isNull())
+ bool NonStandardCompositeType = false;
+ QualType Composite = FindCompositePointerType(LHS, RHS,
+ isSFINAEContext()? 0 : &NonStandardCompositeType);
+ if (!Composite.isNull()) {
+ if (NonStandardCompositeType)
+ Diag(QuestionLoc,
+ diag::ext_typecheck_cond_incompatible_operands_nonstandard)
+ << LTy << RTy << Composite
+ << LHS->getSourceRange() << RHS->getSourceRange();
+
return Composite;
+ }
// Similarly, attempt to find composite type of twp objective-c pointers.
Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
@@ -1828,7 +2258,16 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// 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) {
+///
+/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find
+/// a non-standard (but still sane) composite type to which both expressions
+/// can be converted. When such a type is chosen, \c *NonStandardCompositeType
+/// will be set true.
+QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
+ bool *NonStandardCompositeType) {
+ if (NonStandardCompositeType)
+ *NonStandardCompositeType = false;
+
assert(getLangOptions().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
@@ -1879,12 +2318,20 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
ContainingClassVector MemberOfClass;
QualType Composite1 = Context.getCanonicalType(T1),
Composite2 = Context.getCanonicalType(T2);
+ unsigned NeedConstBefore = 0;
do {
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
(Ptr2 = Composite2->getAs<PointerType>())) {
Composite1 = Ptr1->getPointeeType();
Composite2 = Ptr2->getPointeeType();
+
+ // If we're allowed to create a non-standard composite type, keep track
+ // of where we need to fill in additional 'const' qualifiers.
+ if (NonStandardCompositeType &&
+ Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+ NeedConstBefore = QualifierUnion.size();
+
QualifierUnion.push_back(
Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
@@ -1896,6 +2343,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
(MemPtr2 = Composite2->getAs<MemberPointerType>())) {
Composite1 = MemPtr1->getPointeeType();
Composite2 = MemPtr2->getPointeeType();
+
+ // If we're allowed to create a non-standard composite type, keep track
+ // of where we need to fill in additional 'const' qualifiers.
+ if (NonStandardCompositeType &&
+ Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+ NeedConstBefore = QualifierUnion.size();
+
QualifierUnion.push_back(
Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
@@ -1909,6 +2363,18 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
break;
} while (true);
+ if (NeedConstBefore && NonStandardCompositeType) {
+ // Extension: Add 'const' to qualifiers that come before the first qualifier
+ // mismatch, so that our (non-standard!) composite type meets the
+ // requirements of C++ [conv.qual]p4 bullet 3.
+ for (unsigned I = 0; I != NeedConstBefore; ++I) {
+ if ((QualifierUnion[I] & Qualifiers::Const) == 0) {
+ QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
+ *NonStandardCompositeType = true;
+ }
+ }
+ }
+
// Rewrap the composites as pointers or member pointers with the union CVRs.
ContainingClassVector::reverse_iterator MOC
= MemberOfClass.rbegin();
@@ -1947,9 +2413,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
+ bool ToC2Viable = false;
ImplicitConversionSequence E1ToC2, E2ToC2;
- E1ToC2.setBad();
- E2ToC2.setBad();
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
E1ToC2 = TryImplicitConversion(E1, Composite2,
@@ -1962,10 +2427,10 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*AllowExplicit=*/false,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
+ ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
}
bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad();
- bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
if (ToC1Viable && !ToC2Viable) {
if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
!PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
@@ -1995,7 +2460,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
QualType Ty = CE->getCallee()->getType();
if (const PointerType *PT = Ty->getAs<PointerType>())
Ty = PT->getPointeeType();
-
+ else if (const BlockPointerType *BPT = Ty->getAs<BlockPointerType>())
+ Ty = BPT->getPointeeType();
+
const FunctionType *FTy = Ty->getAs<FunctionType>();
if (FTy->getResultType()->isReferenceType())
return Owned(E);
@@ -2060,7 +2527,8 @@ FullExpr Sema::CreateFullExpr(Expr *SubExpr) {
Sema::OwningExprResult
Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
- tok::TokenKind OpKind, TypeTy *&ObjectType) {
+ tok::TokenKind OpKind, TypeTy *&ObjectType,
+ bool &MayBePseudoDestructor) {
// Since this might be a postfix expression, get rid of ParenListExprs.
Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
@@ -2068,6 +2536,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
assert(BaseExpr && "no record expansion");
QualType BaseType = BaseExpr->getType();
+ MayBePseudoDestructor = false;
if (BaseType->isDependentType()) {
// If we have a pointer to a dependent type and are using the -> operator,
// the object type is the type that the pointer points to. We might still
@@ -2077,6 +2546,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
BaseType = Ptr->getPointeeType();
ObjectType = BaseType.getAsOpaquePtr();
+ MayBePseudoDestructor = true;
return move(Base);
}
@@ -2118,7 +2588,11 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
// [...] 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.
+ //
+ // This also indicates that we should be parsing a
+ // pseudo-destructor-name.
ObjectType = 0;
+ MayBePseudoDestructor = true;
return move(Base);
}
@@ -2134,10 +2608,277 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
// 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::DiagnoseDtorReference(SourceLocation NameLoc,
+ ExprArg MemExpr) {
+ Expr *E = (Expr *) MemExpr.get();
+ SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
+ Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+ << isa<CXXPseudoDestructorExpr>(E)
+ << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+
+ return ActOnCallExpr(/*Scope*/ 0,
+ move(MemExpr),
+ /*LPLoc*/ ExpectedLParenLoc,
+ Sema::MultiExprArg(*this, 0, 0),
+ /*CommaLocs*/ 0,
+ /*RPLoc*/ ExpectedLParenLoc);
+}
+
+Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TypeSourceInfo *ScopeTypeInfo,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage Destructed,
+ bool HasTrailingLParen) {
+ TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
+
+ // C++ [expr.pseudo]p2:
+ // The left-hand side of the dot operator shall be of scalar type. The
+ // left-hand side of the arrow operator shall be of pointer to scalar type.
+ // This scalar type is the object type.
+ Expr *BaseE = (Expr *)Base.get();
+ QualType ObjectType = BaseE->getType();
+ if (OpKind == tok::arrow) {
+ if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
+ ObjectType = Ptr->getPointeeType();
+ } else if (!BaseE->isTypeDependent()) {
+ // The user wrote "p->" when she probably meant "p."; fix it.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << true
+ << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ if (isSFINAEContext())
+ return ExprError();
+
+ OpKind = tok::period;
+ }
+ }
+
+ if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
+ Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << ObjectType << BaseE->getSourceRange();
+ return ExprError();
+ }
+
+ // C++ [expr.pseudo]p2:
+ // [...] The cv-unqualified versions of the object type and of the type
+ // designated by the pseudo-destructor-name shall be the same type.
+ if (DestructedTypeInfo) {
+ QualType DestructedType = DestructedTypeInfo->getType();
+ SourceLocation DestructedTypeStart
+ = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
+ if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
+ !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << BaseE->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
+ }
+
+ // C++ [expr.pseudo]p2:
+ // [...] Furthermore, the two type-names in a pseudo-destructor-name of the
+ // form
+ //
+ // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name
+ //
+ // shall designate the same scalar type.
+ if (ScopeTypeInfo) {
+ QualType ScopeType = ScopeTypeInfo->getType();
+ if (!ScopeType->isDependentType() && !ObjectType->isDependentType() &&
+ !Context.hasSameType(ScopeType, ObjectType)) {
+
+ Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(),
+ diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << ScopeType << BaseE->getSourceRange()
+ << ScopeTypeInfo->getTypeLoc().getSourceRange();
+
+ ScopeType = QualType();
+ ScopeTypeInfo = 0;
+ }
+ }
+
+ OwningExprResult Result
+ = Owned(new (Context) CXXPseudoDestructorExpr(Context,
+ Base.takeAs<Expr>(),
+ OpKind == tok::arrow,
+ OpLoc,
+ (NestedNameSpecifier *) SS.getScopeRep(),
+ SS.getRange(),
+ ScopeTypeInfo,
+ CCLoc,
+ TildeLoc,
+ Destructed));
+
+ if (HasTrailingLParen)
+ return move(Result);
+
+ return DiagnoseDtorReference(Destructed.getLocation(), move(Result));
+}
+
+Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &FirstTypeName,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ UnqualifiedId &SecondTypeName,
+ bool HasTrailingLParen) {
+ assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+ FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
+ "Invalid first type name in pseudo-destructor");
+ assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+ SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
+ "Invalid second type name in pseudo-destructor");
+
+ Expr *BaseE = (Expr *)Base.get();
+
+ // C++ [expr.pseudo]p2:
+ // The left-hand side of the dot operator shall be of scalar type. The
+ // left-hand side of the arrow operator shall be of pointer to scalar type.
+ // This scalar type is the object type.
+ QualType ObjectType = BaseE->getType();
+ if (OpKind == tok::arrow) {
+ if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
+ ObjectType = Ptr->getPointeeType();
+ } else if (!ObjectType->isDependentType()) {
+ // The user wrote "p->" when she probably meant "p."; fix it.
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << true
+ << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ if (isSFINAEContext())
+ return ExprError();
+
+ OpKind = tok::period;
+ }
+ }
+
+ // Compute the object type that we should use for name lookup purposes. Only
+ // record types and dependent types matter.
+ void *ObjectTypePtrForLookup = 0;
+ if (!SS.isSet()) {
+ ObjectTypePtrForLookup = (void *)ObjectType->getAs<RecordType>();
+ if (!ObjectTypePtrForLookup && ObjectType->isDependentType())
+ ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr();
+ }
+
+ // Convert the name of the type being destructed (following the ~) into a
+ // type (with source-location information).
+ QualType DestructedType;
+ TypeSourceInfo *DestructedTypeInfo = 0;
+ PseudoDestructorTypeStorage Destructed;
+ if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
+ TypeTy *T = getTypeName(*SecondTypeName.Identifier,
+ SecondTypeName.StartLocation,
+ S, &SS, true, ObjectTypePtrForLookup);
+ if (!T &&
+ ((SS.isSet() && !computeDeclContext(SS, false)) ||
+ (!SS.isSet() && ObjectType->isDependentType()))) {
+ // The name of the type being destroyed is a dependent name, and we
+ // couldn't find anything useful in scope. Just store the identifier and
+ // it's location, and we'll perform (qualified) name lookup again at
+ // template instantiation time.
+ Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier,
+ SecondTypeName.StartLocation);
+ } else if (!T) {
+ Diag(SecondTypeName.StartLocation,
+ diag::err_pseudo_dtor_destructor_non_type)
+ << SecondTypeName.Identifier << ObjectType;
+ if (isSFINAEContext())
+ return ExprError();
+
+ // Recover by assuming we had the right type all along.
+ DestructedType = ObjectType;
+ } else
+ DestructedType = GetTypeFromParser(T, &DestructedTypeInfo);
+ } else {
+ // Resolve the template-id to a type.
+ TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc);
+ if (T.isInvalid() || !T.get()) {
+ // Recover by assuming we had the right type all along.
+ DestructedType = ObjectType;
+ } else
+ DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo);
+ }
+
+ // If we've performed some kind of recovery, (re-)build the type source
+ // information.
+ if (!DestructedType.isNull()) {
+ if (!DestructedTypeInfo)
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType,
+ SecondTypeName.StartLocation);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
+
+ // Convert the name of the scope type (the type prior to '::') into a type.
+ TypeSourceInfo *ScopeTypeInfo = 0;
+ QualType ScopeType;
+ if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+ FirstTypeName.Identifier) {
+ if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
+ TypeTy *T = getTypeName(*FirstTypeName.Identifier,
+ FirstTypeName.StartLocation,
+ S, &SS, false, ObjectTypePtrForLookup);
+ if (!T) {
+ Diag(FirstTypeName.StartLocation,
+ diag::err_pseudo_dtor_destructor_non_type)
+ << FirstTypeName.Identifier << ObjectType;
+
+ if (isSFINAEContext())
+ return ExprError();
+
+ // Just drop this type. It's unnecessary anyway.
+ ScopeType = QualType();
+ } else
+ ScopeType = GetTypeFromParser(T, &ScopeTypeInfo);
+ } else {
+ // Resolve the template-id to a type.
+ TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc);
+ if (T.isInvalid() || !T.get()) {
+ // Recover by dropping this type.
+ ScopeType = QualType();
+ } else
+ ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo);
+ }
+ }
+
+ if (!ScopeType.isNull() && !ScopeTypeInfo)
+ ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType,
+ FirstTypeName.StartLocation);
+
+
+ return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS,
+ ScopeTypeInfo, CCLoc, TildeLoc,
+ Destructed, HasTrailingLParen);
+}
+
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
CXXMethodDecl *Method) {
if (PerformObjectArgumentInitialization(Exp, Method))
OpenPOWER on IntegriCloud