diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 14 | ||||
-rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 7 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 10 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 12 | ||||
-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 |
8 files changed, 188 insertions, 21 deletions
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 006f69890ab..0ffb1528721 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -116,6 +116,12 @@ Stmt::child_iterator CXXNewExpr::child_end() { Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; } Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; } +// CXXPseudoDestructorExpr +Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; } +Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { + return &Base + 1; +} + // UnresolvedFunctionNameExpr Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { return child_iterator(); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index cde4cdc416a..317486cd712 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1107,6 +1107,20 @@ void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { PrintExpr(E->getArgument()); } +void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + PrintExpr(E->getBase()); + if (E->isArrow()) + OS << "->"; + else + OS << '.'; + if (E->getQualifier()) + E->getQualifier()->print(OS, Policy); + + std::string TypeS; + E->getDestroyedType().getAsStringInternal(TypeS, Policy); + OS << TypeS; +} + void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { OS << E->getName().getAsString(); } diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 19d313b4207..806eb8de81d 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -502,6 +502,13 @@ void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) { ID.AddInteger(S->getNumConstructorArgs()); } +void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitType(S->getDestroyedType()); +} + void StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) { VisitExpr(S); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 5c8dfa46690..4a8253d9cd9 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1234,6 +1234,16 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); + if (isa<CXXPseudoDestructorExpr>(E->getCallee())) { + // C++ [expr.pseudo]p1: + // The result shall only be used as the operand for the function call + // operator (), and the result of such a call has type void. The only + // effect is the evaluation of the postfix-expression before the dot or + // arrow. + EmitScalarExpr(E->getCallee()); + return RValue::get(0); + } + llvm::Value *Callee = EmitScalarExpr(E->getCallee()); return EmitCall(Callee, E->getCallee()->getType(), E->arg_begin(), E->arg_end(), TargetDecl); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 4496c538d3c..8732dc91309 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -305,7 +305,17 @@ public: CGF.EmitCXXDeleteExpr(E); return 0; } - + + Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { + // C++ [expr.pseudo]p1: + // The result shall only be used as the operand for the function call + // operator (), and the result of such a call has type void. The only + // effect is the evaluation of the postfix-expression before the dot or + // arrow. + CGF.EmitScalarExpr(E->getBase()); + return 0; + } + // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { if (CGF.getContext().getLangOptions().OverflowChecking 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. |