diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 62 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 67 |
3 files changed, 140 insertions, 20 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 720217a9103..58d6a0dbac7 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1998,7 +1998,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); Expr *BaseExpr = Base.takeAs<Expr>(); - assert(BaseExpr && "no record expression"); + assert(BaseExpr && "no base expression"); // Perform default conversions. DefaultFunctionArrayConversion(BaseExpr); @@ -2230,6 +2230,47 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, << MemberName << int(OpKind == tok::arrow)); } + // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring + // into a record type was handled above, any destructor we see here is a + // pseudo-destructor. + if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) { + // 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. + if (!BaseType->isScalarType()) + return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) + << BaseType << BaseExpr->getSourceRange()); + + // [...] The type designated by the pseudo-destructor-name shall be the + // same as the object type. + if (!MemberName.getCXXNameType()->isDependentType() && + !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType())) + return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch) + << BaseType << MemberName.getCXXNameType() + << BaseExpr->getSourceRange() << SourceRange(MemberLoc)); + + // [...] 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. + // + // FIXME: DPG can't see any way to trigger this particular clause, so it + // isn't checked here. + + // FIXME: We've lost the precise spelling of the type by going through + // DeclarationName. Can we do better? + return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, + OpKind == tok::arrow, + OpLoc, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), + MemberName.getCXXNameType(), + MemberLoc)); + } + // Handle properties on ObjC 'Class' types. if (OpKind == tok::period && BaseType->isObjCClassType()) { // Also must look for a getter name which uses property syntax. @@ -2684,6 +2725,25 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, DeclarationName UnqualifiedName; if (getLangOptions().CPlusPlus) { + // If this is a pseudo-destructor expression, build the call immediately. + if (isa<CXXPseudoDestructorExpr>(Fn)) { + if (NumArgs > 0) { + // Pseudo-destructor calls should not have any arguments. + Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args) + << CodeModificationHint::CreateRemoval( + SourceRange(Args[0]->getLocStart(), + Args[NumArgs-1]->getLocEnd())); + + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + + NumArgs = 0; + } + + return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy, + RParenLoc)); + } + // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. // FIXME: Will need to cache the results of name lookup (including ADL) in diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c62159d001d..4d49f87a9a8 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1821,26 +1821,19 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, if (SS && SS->isInvalid()) return ExprError(); - Expr *BaseExpr = (Expr *)Base.get(); - - if (BaseExpr->isTypeDependent() || - (SS && isDependentScopeSpecifier(*SS))) { - // FIXME: Return an unresolved ref expr. - return ExprError(); - } - - TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, SS); - if (!BaseTy) { - Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << ClassName; - return ExprError(); - } + QualType BaseType; + if (SS && 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(); + } - QualType BaseType = GetTypeFromParser(BaseTy); - if (!BaseType->isRecordType()) { - Diag(ClassNameLoc, diag::err_type_in_pseudo_dtor_not_a_class_type) - << BaseType; - return ExprError(); + BaseType = GetTypeFromParser(BaseTy); } CanQualType CanBaseType = Context.getCanonicalType(BaseType); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 2faaa44daf9..22e01ab5814 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -783,6 +783,36 @@ public: return getSema().ActOnParenExpr(LParen, RParen, move(SubExpr)); } + /// \brief Build a new pseudo-destructor expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base, + SourceLocation OperatorLoc, + bool isArrow, + SourceLocation DestroyedTypeLoc, + QualType DestroyedType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange) { + CXXScopeSpec SS; + if (Qualifier) { + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + } + + DeclarationName Name + = SemaRef.Context.DeclarationNames.getCXXDestructorName( + SemaRef.Context.getCanonicalType(DestroyedType)); + + return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), + OperatorLoc, + isArrow? tok::arrow : tok::period, + DestroyedTypeLoc, + Name, + Sema::DeclPtrTy::make((Decl *)0), + &SS); + } + /// \brief Build a new unary operator expression. /// /// By default, performs semantic analysis to build the new expression. @@ -3814,6 +3844,43 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { template<typename Derived> Sema::OwningExprResult +TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( + CXXPseudoDestructorExpr *E) { + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + NestedNameSpecifier *Qualifier + = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (E->getQualifier() && !Qualifier) + return SemaRef.ExprError(); + + QualType DestroyedType; + { + TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName()); + DestroyedType = getDerived().TransformType(E->getDestroyedType()); + if (DestroyedType.isNull()) + return SemaRef.ExprError(); + } + + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase() && + Qualifier == E->getQualifier() && + DestroyedType == E->getDestroyedType()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXPseudoDestructorExpr(move(Base), + E->getOperatorLoc(), + E->isArrow(), + E->getDestroyedTypeLoc(), + DestroyedType, + Qualifier, + E->getQualifierRange()); +} + +template<typename Derived> +Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr( UnresolvedFunctionNameExpr *E) { // There is no transformation we can apply to an unresolved function name. |