diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 15 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 22 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 48 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 19 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 249 | ||||
| -rw-r--r-- | clang/test/SemaCXX/pseudo-destructors.cpp | 8 | 
8 files changed, 312 insertions, 64 deletions
| diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 07b0fdedcd5..de7624756f2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2078,7 +2078,12 @@ def err_pseudo_dtor_call_with_args : Error<  def err_dtor_expr_without_call : Error<    "%select{destructor reference|pseudo-destructor expression}0 must be "    "called immediately with '()'">; - +def err_pseudo_dtor_destructor_non_type : Error< +  "%0 does not refer to a type name in pseudo-destructor expression; expected " +  "the name of type %1">; +def err_pseudo_dtor_template : Error< +  "specialization of template %0 does not refer to a scalar type in pseudo-" +  "destructor expression">;  def err_invalid_use_of_function_type : Error<    "a function type is not allowed here">;  def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 022b1c0154d..e4a9512414b 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -327,13 +327,26 @@ public:      return false;    } +  /// \brief Determine whether the given name refers to a non-type nested name +  /// specifier, e.g., the name of a namespace or namespace alias. +  /// +  /// This actual is used in the parsing of pseudo-destructor names to  +  /// distinguish a nested-name-specifier and a "type-name ::" when we +  /// see the token sequence "X :: ~". +  virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, +                                            SourceLocation IdLoc, +                                            IdentifierInfo &II, +                                            TypeTy *ObjectType) { +    return false; +  } +      /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the    /// global scope ('::').    virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,                                                     SourceLocation CCLoc) {      return 0;    } - +      /// \brief Parsed an identifier followed by '::' in a C++    /// nested-name-specifier.    /// diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 07de34dcb52..a72ab70d6cc 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -240,7 +240,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,      // If we get foo:bar, this is almost certainly a typo for foo::bar.  Recover      // and emit a fixit hint for it.      if (Next.is(tok::colon) && !ColonIsSacred) { -      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { +      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && +          !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), +                                                II, ObjectType)) {          *MayBePseudoDestructor = true;          return HasScopeSpecifier;        } @@ -261,7 +263,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,      }      if (Next.is(tok::coloncolon)) { -      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { +      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && +          !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), +                                                II, ObjectType)) {          *MayBePseudoDestructor = true;          return HasScopeSpecifier;        } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index f09fc543d18..57e527e94a6 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2178,6 +2178,20 @@ public:                                                          TypeTy *&ObjectType,                                                     bool &MayBePseudoDestructor); +  OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, +                                         ExprArg MemExpr); +   +  OwningExprResult ActOnDependentPseudoDestructorExpr(Scope *S,  +                                                      ExprArg Base, +                                                      SourceLocation OpLoc, +                                                      tok::TokenKind OpKind, +                                                      const CXXScopeSpec &SS, +                                                  UnqualifiedId &FirstTypeName, +                                                      SourceLocation CCLoc, +                                                      SourceLocation TildeLoc, +                                                  UnqualifiedId &SecondTypeName, +                                                      bool HasTrailingLParen); +      virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,                                                       SourceLocation OpLoc,                                                       tok::TokenKind OpKind, @@ -2187,7 +2201,7 @@ public:                                                       SourceLocation TildeLoc,                                                    UnqualifiedId &SecondTypeName,                                                       bool HasTrailingLParen); - +       /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is    /// non-empty, will create a new CXXExprWithTemporaries expression.    /// Otherwise, just returs the passed in expression. @@ -2215,7 +2229,11 @@ public:                                         bool MayBePseudoDestructor = false);    NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - +  virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, +                                            SourceLocation IdLoc, +                                            IdentifierInfo &II, +                                            TypeTy *ObjectType); +      CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,                                            const CXXScopeSpec &SS,                                            SourceLocation IdLoc, diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 315938d2d49..4f8a41426c0 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -332,6 +332,54 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {    return 0;  } +bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, +                                        SourceLocation IdLoc, +                                        IdentifierInfo &II, +                                        TypeTy *ObjectTypePtr) { +  QualType ObjectType = GetTypeFromParser(ObjectTypePtr); +  LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); +   +  // Determine where to perform name lookup +  DeclContext *LookupCtx = 0; +  bool isDependent = false; +  if (!ObjectType.isNull()) { +    // This nested-name-specifier occurs in a member access expression, e.g., +    // x->B::f, and we are looking into the type of the object. +    assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); +    LookupCtx = computeDeclContext(ObjectType); +    isDependent = ObjectType->isDependentType(); +  } else if (SS.isSet()) { +    // This nested-name-specifier occurs after another nested-name-specifier, +    // so long into the context associated with the prior nested-name-specifier. +    LookupCtx = computeDeclContext(SS, false); +    isDependent = isDependentScopeSpecifier(SS); +    Found.setContextRange(SS.getRange()); +  } +   +  if (LookupCtx) { +    // Perform "qualified" name lookup into the declaration context we +    // computed, which is either the type of the base of a member access +    // expression or the declaration context associated with a prior +    // nested-name-specifier. +     +    // The declaration context must be complete. +    if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) +      return false; +     +    LookupQualifiedName(Found, LookupCtx); +  } else if (isDependent) { +    return false; +  } else { +    LookupName(Found, S); +  } +  Found.suppressDiagnostics(); +   +  if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) +    return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); +   +  return false; +} +  /// \brief Build a new nested-name-specifier for "identifier::", as described  /// by ActOnCXXNestedNameSpecifier.  /// diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 24edd7204ef..c3116a3885e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3178,23 +3178,6 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,    return ExprError();  } -static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef, -                                                    SourceLocation NameLoc, -                                                    Sema::ExprArg MemExpr) { -  Expr *E = (Expr *) MemExpr.get(); -  SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc); -  SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call) -    << isa<CXXPseudoDestructorExpr>(E) -    << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); -   -  return SemaRef.ActOnCallExpr(/*Scope*/ 0, -                               move(MemExpr), -                               /*LPLoc*/ ExpectedLParenLoc, -                               Sema::MultiExprArg(SemaRef, 0, 0), -                               /*CommaLocs*/ 0, -                               /*RPLoc*/ ExpectedLParenLoc); -} -  /// The main callback when the parser finds something like  ///   expression . [nested-name-specifier] identifier  ///   expression -> [nested-name-specifier] identifier @@ -3265,7 +3248,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,          // call now.          if (!HasTrailingLParen &&              Id.getKind() == UnqualifiedId::IK_DestructorName) -          return DiagnoseDtorReference(*this, NameLoc, move(Result)); +          return DiagnoseDtorReference(NameLoc, move(Result));          return move(Result);        } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 1ea205671e7..9172956b515 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2410,31 +2410,41 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,    return move(Base);  } -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"); +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::ActOnDependentPseudoDestructorExpr(Scope *S,  +                                         ExprArg Base, +                                         SourceLocation OpLoc, +                                         tok::TokenKind OpKind, +                                         const CXXScopeSpec &SS, +                                         UnqualifiedId &FirstTypeName, +                                         SourceLocation CCLoc, +                                         SourceLocation TildeLoc, +                                         UnqualifiedId &SecondTypeName, +                                         bool HasTrailingLParen) {    Expr *BaseE = (Expr *)Base.get(); -  QualType ObjectType; -  if (BaseE->isTypeDependent()) -    ObjectType = Context.DependentTy; - +  QualType ObjectType = BaseE->getType(); +  assert(ObjectType->isDependentType()); +      // The nested-name-specifier provided by the parser, then extended    // by the "type-name ::" in the pseudo-destructor-name, if present.    CXXScopeSpec ExtendedSS = SS; - +      if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||         FirstTypeName.Identifier) {      // We have a pseudo-destructor with a "type-name ::".  @@ -2443,13 +2453,13 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,      if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {        // Resolve the identifier to a nested-name-specifier.        CXXScopeTy *FinalScope -        = ActOnCXXNestedNameSpecifier(S, SS,  -                                      FirstTypeName.StartLocation, -                                      CCLoc, -                                      *FirstTypeName.Identifier, -                                      true, -                                      ObjectType.getAsOpaquePtr(), -                                      false); +      = ActOnCXXNestedNameSpecifier(S, SS,  +                                    FirstTypeName.StartLocation, +                                    CCLoc, +                                    *FirstTypeName.Identifier, +                                    true, +                                    ObjectType.getAsOpaquePtr(), +                                    false);        if (SS.getBeginLoc().isInvalid())          ExtendedSS.setBeginLoc(FirstTypeName.StartLocation);        ExtendedSS.setEndLoc(CCLoc); @@ -2468,11 +2478,11 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,                                           TemplateId->RAngleLoc);        if (!T.isInvalid()) {          CXXScopeTy *FinalScope -          = ActOnCXXNestedNameSpecifier(S, SS, T.get(),  -                                        SourceRange(TemplateId->TemplateNameLoc, -                                                    TemplateId->RAngleLoc), -                                        CCLoc, -                                        true); +        = ActOnCXXNestedNameSpecifier(S, SS, T.get(),  +                                      SourceRange(TemplateId->TemplateNameLoc, +                                                  TemplateId->RAngleLoc), +                                      CCLoc, +                                      true);          if (SS.getBeginLoc().isInvalid())            ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc);          ExtendedSS.setEndLoc(CCLoc); @@ -2480,7 +2490,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,        }      }    } - +      // Produce a destructor name based on the second type-name (which    // follows the tilde).    TypeTy *DestructedType; @@ -2490,7 +2500,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,      bool isDependent = isDependentScopeSpecifier(ExtendedSS);      if (isDependent || computeDeclContext(ExtendedSS))        LookupSS = &ExtendedSS; - +          DestructedType = getTypeName(*SecondTypeName.Identifier,                                    SecondTypeName.StartLocation,                                   S, LookupSS, true, ObjectType.getTypePtr()); @@ -2514,13 +2524,13 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,        if (!DestructedType)          return ExprError();      } - +          if (!DestructedType) {        // FIXME: Crummy diagnostic.        Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name);        return ExprError();      } - +          EndLoc = SecondTypeName.EndLocation;    } else {      // Resolve the template-id to a type, and that to a @@ -2528,7 +2538,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,      TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;      ASTTemplateArgsPtr TemplateArgsPtr(*this,                                         TemplateId->getTemplateArgs(), -                                         TemplateId->NumArgs); +                                       TemplateId->NumArgs);      EndLoc = TemplateId->RAngleLoc;      TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),                                         TemplateId->TemplateNameLoc, @@ -2540,7 +2550,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,      DestructedType = T.get();    } - +      // Form a (possibly fake) destructor name and let the member access    // expression code deal with this.    // FIXME: Don't do this! It's totally broken! @@ -2548,6 +2558,169 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,    Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc);    return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS,                                  Destructor, DeclPtrTy(), HasTrailingLParen); +   +} + +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(); +  if (BaseE->isTypeDependent()) +    return ActOnDependentPseudoDestructorExpr(S, move(Base), OpLoc, OpKind, +                                              SS, FirstTypeName, CCLoc,  +                                              TildeLoc, SecondTypeName, +                                              HasTrailingLParen); +   +  // 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 { +      // 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->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. +  QualType DestructedType; +  TypeSourceInfo *DestructedTypeInfo = 0; +  if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { +    TypeTy *T = getTypeName(*SecondTypeName.Identifier,  +                            SecondTypeName.StartLocation, +                            S, &SS); +    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); +       +      if (!DestructedType->isDependentType() && +          !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { +        // The types mismatch. Recover by assuming we had the right type +        // all along. +        Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch) +          << ObjectType << DestructedType << BaseE->getSourceRange(); +         +        DestructedType = ObjectType; +        DestructedTypeInfo = 0; +      } +    } +  } else { +    // FIXME: C++0x template aliases would allow a template-id here. For now, +    // just diagnose this as an error. +    TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; +    Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template) +      << TemplateId->Name << ObjectType +      << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); +    if (isSFINAEContext()) +      return ExprError(); +     +    // Recover by assuming we had the right type all along. +    DestructedType = ObjectType; +  } +   +  // 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.   +  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); +      if (!T) { +        Diag(FirstTypeName.StartLocation,  +             diag::err_pseudo_dtor_destructor_non_type) +          << FirstTypeName.Identifier << ObjectType; +        if (isSFINAEContext()) +          return ExprError();         +      } else { +        // FIXME: Drops source-location information. +        ScopeType = GetTypeFromParser(T); +         +        if (!ScopeType->isDependentType() && +            !Context.hasSameUnqualifiedType(DestructedType, ScopeType)) { +          // The types mismatch. Recover by assuming we don't have a scoping  +          // type. +          Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch) +            << ObjectType << ScopeType << BaseE->getSourceRange(); +           +          ScopeType = QualType(); +        } +      } +    } else { +      // FIXME: C++0x template aliases would allow a template-id here. For now, +      // just diagnose this as an error. +      TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; +      Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template) +        << TemplateId->Name << ObjectType +        << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); +      if (isSFINAEContext()) +        return ExprError(); +       +      // Recover by assuming we have no scoping type. +      DestructedType = ObjectType; +    } +  } +   +  // FIXME: Drops the scope type. +  OwningExprResult Result +    = Owned(new (Context) CXXPseudoDestructorExpr(Context,  +                                                  Base.takeAs<Expr>(), +                                                  OpKind == tok::arrow, +                                                  OpLoc, +                                       (NestedNameSpecifier *) SS.getScopeRep(), +                                                  SS.getRange(), +                                                  DestructedType, +                                                 SecondTypeName.StartLocation)); +  if (HasTrailingLParen) +    return move(Result); +   +  return DiagnoseDtorReference(SecondTypeName.StartLocation, move(Result));  }  CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,  diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp index de9ca2d3003..472e5b42fb2 100644 --- a/clang/test/SemaCXX/pseudo-destructors.cpp +++ b/clang/test/SemaCXX/pseudo-destructors.cpp @@ -11,6 +11,7 @@ void g();  namespace N {    typedef Foo Wibble; +  typedef int OtherInteger;  }  void f(A* a, Foo *f, int *i, double *d) { @@ -35,8 +36,11 @@ void f(A* a, Foo *f, int *i, double *d) {    i->~Integer();    i->Integer::~Integer(); - -  i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('double') in pseudo-destructor expression}} +  i->N::~OtherInteger(); +  i->N::OtherInteger::~OtherInteger(); +  i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}} +  i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}} +  i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}  }  typedef int Integer; | 

