From 180abc3db9ae3b4fc63cd65b15697e6ffcc8a657 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sun, 17 Jul 2011 15:40:56 +0000 Subject: Vendor import of clang trunk r135360: http://llvm.org/svn/llvm-project/cfe/trunk@135360 --- lib/Sema/SemaExpr.cpp | 2797 ++++++++++++++----------------------------------- 1 file changed, 791 insertions(+), 2006 deletions(-) (limited to 'lib/Sema/SemaExpr.cpp') diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0549e9499560..5efc36559d97 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -87,7 +87,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (FunctionDecl *FD = dyn_cast(D)) { if (FD->isDeleted()) { Diag(Loc, diag::err_deleted_function_use); - Diag(D->getLocation(), diag::note_unavailable_here) << true; + Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true; return true; } } @@ -104,17 +104,20 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, break; case AR_Unavailable: - if (Message.empty()) { - if (!UnknownObjCClass) - Diag(Loc, diag::err_unavailable) << D->getDeclName(); - else - Diag(Loc, diag::warn_unavailable_fwdclass_message) - << D->getDeclName(); + if (cast(CurContext)->getAvailability() != AR_Unavailable) { + if (Message.empty()) { + if (!UnknownObjCClass) + Diag(Loc, diag::err_unavailable) << D->getDeclName(); + else + Diag(Loc, diag::warn_unavailable_fwdclass_message) + << D->getDeclName(); + } + else + Diag(Loc, diag::err_unavailable_message) + << D->getDeclName() << Message; + Diag(D->getLocation(), diag::note_unavailable_here) + << isa(D) << false; } - else - Diag(Loc, diag::err_unavailable_message) - << D->getDeclName() << Message; - Diag(D->getLocation(), diag::note_unavailable_here) << 0; break; } @@ -437,8 +440,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { /// will warn if the resulting type is not a POD type, and rejects ObjC /// interfaces passed by value. ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, - FunctionDecl *FDecl) { - ExprResult ExprRes = DefaultArgumentPromotion(E); + FunctionDecl *FDecl) { + ExprResult ExprRes = CheckPlaceholderExpr(E); + if (ExprRes.isInvalid()) + return ExprError(); + + ExprRes = DefaultArgumentPromotion(E); if (ExprRes.isInvalid()) return ExprError(); E = ExprRes.take(); @@ -456,7 +463,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, << E->getType() << CT)) return ExprError(); - if (!E->getType()->isPODType()) { + if (!E->getType().isPODType(Context)) { // C++0x [expr.call]p7: // Passing a potentially-evaluated argument of class type (Clause 9) // having a non-trivial copy constructor, a non-trivial move constructor, @@ -471,6 +478,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, TrivialEnough = true; } } + + if (!TrivialEnough && + getLangOptions().ObjCAutoRefCount && + E->getType()->isObjCLifetimeType()) + TrivialEnough = true; if (TrivialEnough) { // Nothing to diagnose. This is okay. @@ -1004,7 +1016,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { // Pass &StringTokLocs[0], StringTokLocs.size() to factory! return Owned(StringLiteral::Create(Context, Literal.GetString(), - Literal.GetStringLength(), Literal.AnyWide, Literal.Pascal, StrTy, &StringTokLocs[0], StringTokLocs.size())); @@ -1271,125 +1282,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, return Owned(E); } -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - const CXXScopeSpec &SS, FieldDecl *Field, - DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo); - -ExprResult -Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, - SourceLocation loc, - IndirectFieldDecl *indirectField, - Expr *baseObjectExpr, - SourceLocation opLoc) { - // First, build the expression that refers to the base object. - - bool baseObjectIsPointer = false; - Qualifiers baseQuals; - - // Case 1: the base of the indirect field is not a field. - VarDecl *baseVariable = indirectField->getVarDecl(); - CXXScopeSpec EmptySS; - if (baseVariable) { - assert(baseVariable->getType()->isRecordType()); - - // In principle we could have a member access expression that - // accesses an anonymous struct/union that's a static member of - // the base object's class. However, under the current standard, - // static data members cannot be anonymous structs or unions. - // Supporting this is as easy as building a MemberExpr here. - assert(!baseObjectExpr && "anonymous struct/union is static data member?"); - - DeclarationNameInfo baseNameInfo(DeclarationName(), loc); - - ExprResult result = - BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); - if (result.isInvalid()) return ExprError(); - - baseObjectExpr = result.take(); - baseObjectIsPointer = false; - baseQuals = baseObjectExpr->getType().getQualifiers(); - - // Case 2: the base of the indirect field is a field and the user - // wrote a member expression. - } else if (baseObjectExpr) { - // The caller provided the base object expression. Determine - // whether its a pointer and whether it adds any qualifiers to the - // anonymous struct/union fields we're looking into. - QualType objectType = baseObjectExpr->getType(); - - if (const PointerType *ptr = objectType->getAs()) { - baseObjectIsPointer = true; - objectType = ptr->getPointeeType(); - } else { - baseObjectIsPointer = false; - } - baseQuals = objectType.getQualifiers(); - - // Case 3: the base of the indirect field is a field and we should - // build an implicit member access. - } else { - // We've found a member of an anonymous struct/union that is - // inside a non-anonymous struct/union, so in a well-formed - // program our base object expression is "this". - QualType ThisTy = getAndCaptureCurrentThisType(); - if (ThisTy.isNull()) { - Diag(loc, diag::err_invalid_member_use_in_static_method) - << indirectField->getDeclName(); - return ExprError(); - } - - // Our base object expression is "this". - baseObjectExpr = - new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); - baseObjectIsPointer = true; - baseQuals = ThisTy->castAs()->getPointeeType().getQualifiers(); - } - - // Build the implicit member references to the field of the - // anonymous struct/union. - Expr *result = baseObjectExpr; - IndirectFieldDecl::chain_iterator - FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); - - // Build the first member access in the chain with full information. - if (!baseVariable) { - FieldDecl *field = cast(*FI); - - // FIXME: use the real found-decl info! - DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); - - // Make a nameInfo that properly uses the anonymous name. - DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - - result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, - EmptySS, field, foundDecl, - memberNameInfo).take(); - baseObjectIsPointer = false; - - // FIXME: check qualified member access - } - - // In all cases, we should now skip the first declaration in the chain. - ++FI; - - while (FI != FEnd) { - FieldDecl *field = cast(*FI++); - - // FIXME: these are somewhat meaningless - DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); - - result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, - (FI == FEnd? SS : EmptySS), field, - foundDecl, memberNameInfo) - .take(); - } - - return Owned(result); -} - /// Decomposes the given name into a DeclarationNameInfo, its location, and /// possibly a list of template arguments. /// @@ -1399,215 +1291,30 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, /// This actually loses a lot of source location information for /// non-standard name kinds; we should consider preserving that in /// some way. -static void DecomposeUnqualifiedId(Sema &SemaRef, - const UnqualifiedId &Id, - TemplateArgumentListInfo &Buffer, - DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *&TemplateArgs) { +void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs) { if (Id.getKind() == UnqualifiedId::IK_TemplateId) { Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(SemaRef, + ASTTemplateArgsPtr TemplateArgsPtr(*this, Id.TemplateId->getTemplateArgs(), Id.TemplateId->NumArgs); - SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer); + translateTemplateArguments(TemplateArgsPtr, Buffer); TemplateArgsPtr.release(); TemplateName TName = Id.TemplateId->Template.get(); SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc; - NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc); + NameInfo = Context.getNameForTemplate(TName, TNameLoc); TemplateArgs = &Buffer; } else { - NameInfo = SemaRef.GetNameFromUnqualifiedId(Id); + NameInfo = GetNameFromUnqualifiedId(Id); TemplateArgs = 0; } } -/// Determines if the given class is provably not derived from all of -/// the prospective base classes. -static bool IsProvablyNotDerivedFrom(Sema &SemaRef, - CXXRecordDecl *Record, - const llvm::SmallPtrSet &Bases) { - if (Bases.count(Record->getCanonicalDecl())) - return false; - - RecordDecl *RD = Record->getDefinition(); - if (!RD) return false; - Record = cast(RD); - - for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), - E = Record->bases_end(); I != E; ++I) { - CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); - CanQual BaseRT = BaseT->getAs(); - if (!BaseRT) return false; - - CXXRecordDecl *BaseRecord = cast(BaseRT->getDecl()); - if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) - return false; - } - - return true; -} - -enum IMAKind { - /// The reference is definitely not an instance member access. - IMA_Static, - - /// The reference may be an implicit instance member access. - IMA_Mixed, - - /// The reference may be to an instance member, but it is invalid if - /// so, because the context is not an instance method. - IMA_Mixed_StaticContext, - - /// The reference may be to an instance member, but it is invalid if - /// so, because the context is from an unrelated class. - IMA_Mixed_Unrelated, - - /// The reference is definitely an implicit instance member access. - IMA_Instance, - - /// The reference may be to an unresolved using declaration. - IMA_Unresolved, - - /// The reference may be to an unresolved using declaration and the - /// context is not an instance method. - IMA_Unresolved_StaticContext, - - /// All possible referrents are instance members and the current - /// context is not an instance method. - IMA_Error_StaticContext, - - /// All possible referrents are instance members of an unrelated - /// class. - IMA_Error_Unrelated -}; - -/// The given lookup names class member(s) and is not being used for -/// an address-of-member expression. Classify the type of access -/// according to whether it's possible that this reference names an -/// instance member. This is best-effort; it is okay to -/// conservatively answer "yes", in which case some errors will simply -/// not be caught until template-instantiation. -static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, - Scope *CurScope, - const LookupResult &R) { - assert(!R.empty() && (*R.begin())->isCXXClassMember()); - - DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); - - bool isStaticContext = - (!isa(DC) || - cast(DC)->isStatic()); - - // C++0x [expr.prim]p4: - // Otherwise, if a member-declarator declares a non-static data member - // of a class X, the expression this is a prvalue of type "pointer to X" - // within the optional brace-or-equal-initializer. - if (CurScope->getFlags() & Scope::ThisScope) - isStaticContext = false; - - if (R.isUnresolvableResult()) - return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; - - // Collect all the declaring classes of instance members we find. - bool hasNonInstance = false; - bool hasField = false; - llvm::SmallPtrSet Classes; - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = *I; - - if (D->isCXXInstanceMember()) { - if (dyn_cast(D)) - hasField = true; - - CXXRecordDecl *R = cast(D->getDeclContext()); - Classes.insert(R->getCanonicalDecl()); - } - else - hasNonInstance = true; - } - - // If we didn't find any instance members, it can't be an implicit - // member reference. - if (Classes.empty()) - return IMA_Static; - - // If the current context is not an instance method, it can't be - // an implicit member reference. - if (isStaticContext) { - if (hasNonInstance) - return IMA_Mixed_StaticContext; - - if (SemaRef.getLangOptions().CPlusPlus0x && hasField) { - // C++0x [expr.prim.general]p10: - // An id-expression that denotes a non-static data member or non-static - // member function of a class can only be used: - // (...) - // - if that id-expression denotes a non-static data member and it appears in an unevaluated operand. - const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back(); - bool isUnevaluatedExpression = record.Context == Sema::Unevaluated; - if (isUnevaluatedExpression) - return IMA_Mixed_StaticContext; - } - - return IMA_Error_StaticContext; - } - - CXXRecordDecl *contextClass; - if (CXXMethodDecl *MD = dyn_cast(DC)) - contextClass = MD->getParent()->getCanonicalDecl(); - else - contextClass = cast(DC); - - // [class.mfct.non-static]p3: - // ...is used in the body of a non-static member function of class X, - // if name lookup (3.4.1) resolves the name in the id-expression to a - // non-static non-type member of some class C [...] - // ...if C is not X or a base class of X, the class member access expression - // is ill-formed. - if (R.getNamingClass() && - contextClass != R.getNamingClass()->getCanonicalDecl() && - contextClass->isProvablyNotDerivedFrom(R.getNamingClass())) - return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); - - // If we can prove that the current context is unrelated to all the - // declaring classes, it can't be an implicit member reference (in - // which case it's an error if any of those members are selected). - if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes)) - return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); - - return (hasNonInstance ? IMA_Mixed : IMA_Instance); -} - -/// Diagnose a reference to a field with no object available. -static void DiagnoseInstanceReference(Sema &SemaRef, - const CXXScopeSpec &SS, - NamedDecl *rep, - const DeclarationNameInfo &nameInfo) { - SourceLocation Loc = nameInfo.getLoc(); - SourceRange Range(Loc); - if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); - - if (isa(rep) || isa(rep)) { - if (CXXMethodDecl *MD = dyn_cast(SemaRef.CurContext)) { - if (MD->isStatic()) { - // "invalid use of member 'x' in static member function" - SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) - << Range << nameInfo.getName(); - return; - } - } - - SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) - << nameInfo.getName() << Range; - return; - } - - SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; -} - /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found @@ -1690,39 +1397,43 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, } // We didn't find anything, so try to correct for a typo. - DeclarationName Corrected; - if (S && (Corrected = CorrectTypo(R, S, &SS, 0, false, CTC))) { - if (!R.empty()) { - if (isa(*R.begin()) || isa(*R.begin())) { + TypoCorrection Corrected; + if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), + S, &SS, NULL, false, CTC))) { + std::string CorrectedStr(Corrected.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); + R.setLookupName(Corrected.getCorrection()); + + if (NamedDecl *ND = Corrected.getCorrectionDecl()) { + R.addDecl(ND); + if (isa(ND) || isa(ND)) { if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - if (NamedDecl *ND = R.getAsSingle()) + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); + if (ND) Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); + << CorrectedQuotedStr; // Tell the callee to try to recover. return false; } - if (isa(*R.begin()) || isa(*R.begin())) { + if (isa(ND) || isa(ND)) { // FIXME: If we ended up with a typo for a type name or // Objective-C class name, we're in trouble because the parser // is in the wrong place to recover. Suggest the typo // correction, but don't make it a fix-it since we're not going // to recover well anyway. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); + Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr; else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange(); // Don't try to recover; it won't work. @@ -1732,15 +1443,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // FIXME: We found a keyword. Suggest it, but don't provide a fix-it // because we aren't able to recover. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected; + Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr; else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << Corrected + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange(); return true; } - R.clear(); } + R.clear(); // Emit a special diagnostic for failed member lookups. // FIXME: computing the declaration context might fail here (?) @@ -1856,7 +1567,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // Decompose the UnqualifiedId into the following data. DeclarationNameInfo NameInfo; const TemplateArgumentListInfo *TemplateArgs; - DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs); + DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); DeclarationName Name = NameInfo.getName(); IdentifierInfo *II = Name.getAsIdentifierInfo(); @@ -1892,7 +1603,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool IvarLookupFollowUp = false; // Perform the required lookup. - LookupResult R(*this, NameInfo, LookupOrdinaryName); + LookupResult R(*this, NameInfo, + (Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam) + ? LookupObjCImplicitSelfParam : LookupOrdinaryName); if (TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the @@ -2032,38 +1745,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S, return BuildDeclarationNameExpr(SS, R, ADL); } -/// Builds an expression which might be an implicit member expression. -ExprResult -Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { - case IMA_Instance: - return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); - - case IMA_Mixed: - case IMA_Mixed_Unrelated: - case IMA_Unresolved: - return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); - - case IMA_Static: - case IMA_Mixed_StaticContext: - case IMA_Unresolved_StaticContext: - if (TemplateArgs) - return BuildTemplateIdExpr(SS, R, false, *TemplateArgs); - return BuildDeclarationNameExpr(SS, R, false); - - case IMA_Error_StaticContext: - case IMA_Error_Unrelated: - DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), - R.getLookupNameInfo()); - return ExprError(); - } - - llvm_unreachable("unexpected instance member access kind"); - return ExprError(); -} - /// BuildQualifiedDeclarationNameExpr - Build a C++ qualified /// declaration name, generally during template instantiation. /// There's a large number of things which don't need to be done along @@ -2155,6 +1836,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo &II = Context.Idents.get("self"); UnqualifiedId SelfName; SelfName.setIdentifier(&II, SourceLocation()); + SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam); CXXScopeSpec SelfScopeSpec; ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, SelfName, false, false); @@ -2166,27 +1848,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, return ExprError(); MarkDeclarationReferenced(Loc, IV); - Expr *base = SelfExpr.take(); - base = base->IgnoreParenImpCasts(); - if (const DeclRefExpr *DE = dyn_cast(base)) { - const NamedDecl *ND = DE->getDecl(); - if (!isa(ND)) { - // relax the rule such that it is allowed to have a shadow 'self' - // where stand-alone ivar can be found in this 'self' object. - // This is to match gcc's behavior. - ObjCInterfaceDecl *selfIFace = 0; - if (const ObjCObjectPointerType *OPT = - base->getType()->getAsObjCInterfacePointerType()) - selfIFace = OPT->getInterfaceDecl(); - if (!selfIFace || - !selfIFace->lookupInstanceVariable(IV->getIdentifier())) { - Diag(Loc, diag::error_implicit_ivar_access) - << IV->getDeclName(); - Diag(ND->getLocation(), diag::note_declared_at); - return ExprError(); - } - } - } return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), Loc, SelfExpr.take(), true, true)); @@ -2385,120 +2046,6 @@ Sema::PerformObjectMemberConversion(Expr *From, VK, &BasePath); } -/// \brief Build a MemberExpr AST node. -static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, - const CXXScopeSpec &SS, ValueDecl *Member, - DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo, - QualType Ty, - ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = 0) { - return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C), - Member, FoundDecl, MemberNameInfo, - TemplateArgs, Ty, VK, OK); -} - -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - const CXXScopeSpec &SS, FieldDecl *Field, - DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo) { - // x.a is an l-value if 'a' has a reference type. Otherwise: - // x.a is an l-value/x-value/pr-value if the base is (and note - // that *x is always an l-value), except that if the base isn't - // an ordinary object then we must have an rvalue. - ExprValueKind VK = VK_LValue; - ExprObjectKind OK = OK_Ordinary; - if (!IsArrow) { - if (BaseExpr->getObjectKind() == OK_Ordinary) - VK = BaseExpr->getValueKind(); - else - VK = VK_RValue; - } - if (VK != VK_RValue && Field->isBitField()) - OK = OK_BitField; - - // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = Field->getType(); - if (const ReferenceType *Ref = MemberType->getAs()) { - MemberType = Ref->getPointeeType(); - VK = VK_LValue; - } else { - QualType BaseType = BaseExpr->getType(); - if (IsArrow) BaseType = BaseType->getAs()->getPointeeType(); - - Qualifiers BaseQuals = BaseType.getQualifiers(); - - // GC attributes are never picked up by members. - BaseQuals.removeObjCGCAttr(); - - // CVR attributes from the base are picked up by members, - // except that 'mutable' members don't pick up 'const'. - if (Field->isMutable()) BaseQuals.removeConst(); - - Qualifiers MemberQuals - = S.Context.getCanonicalType(MemberType).getQualifiers(); - - // TR 18037 does not allow fields to be declared with address spaces. - assert(!MemberQuals.hasAddressSpace()); - - Qualifiers Combined = BaseQuals + MemberQuals; - if (Combined != MemberQuals) - MemberType = S.Context.getQualifiedType(MemberType, Combined); - } - - S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field); - ExprResult Base = - S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field); - if (Base.isInvalid()) - return ExprError(); - return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS, - Field, FoundDecl, MemberNameInfo, - MemberType, VK, OK)); -} - -/// Builds an implicit member access expression. The current context -/// is known to be an instance method, and the given unqualified lookup -/// set is known to contain only instance members, at least one of which -/// is from an appropriate type. -ExprResult -Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - bool IsKnownInstance) { - assert(!R.empty() && !R.isAmbiguous()); - - SourceLocation loc = R.getNameLoc(); - - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - // FIXME: template-ids inside anonymous structs? - if (IndirectFieldDecl *FD = R.getAsSingle()) - return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD); - - // If this is known to be an instance access, go ahead and build an - // implicit 'this' expression now. - // 'this' expression now. - QualType ThisTy = getAndCaptureCurrentThisType(); - assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); - - Expr *baseExpr = 0; // null signifies implicit access - if (IsKnownInstance) { - SourceLocation Loc = R.getNameLoc(); - if (SS.getRange().isValid()) - Loc = SS.getRange().getBegin(); - baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); - } - - return BuildMemberReferenceExpr(baseExpr, ThisTy, - /*OpLoc*/ SourceLocation(), - /*IsArrow*/ true, - SS, - /*FirstQualifierInScope*/ 0, - R, TemplateArgs); -} - bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen) { @@ -3160,6 +2707,20 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, Op->getSourceRange(), ExprKind)) return true; + if (ExprKind == UETT_SizeOf) { + if (DeclRefExpr *DeclRef = dyn_cast(Op->IgnoreParens())) { + if (ParmVarDecl *PVD = dyn_cast(DeclRef->getFoundDecl())) { + QualType OType = PVD->getOriginalType(); + QualType Type = PVD->getType(); + if (Type->isPointerType() && OType->isArrayType()) { + Diag(Op->getExprLoc(), diag::warn_sizeof_array_param) + << Type << OType; + Diag(PVD->getLocation(), diag::note_declared_at); + } + } + } + } + return false; } @@ -3274,6 +2835,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind) { + ExprResult PE = CheckPlaceholderExpr(E); + if (PE.isInvalid()) + return ExprError(); + + E = PE.get(); + // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { @@ -3285,10 +2852,6 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, } else if (E->getBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; - } else if (E->getType()->isPlaceholderType()) { - ExprResult PE = CheckPlaceholderExpr(E); - if (PE.isInvalid()) return ExprError(); - return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind); } else { isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); } @@ -3372,19 +2935,6 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, return BuildUnaryOp(S, OpLoc, Opc, Input); } -/// Expressions of certain arbitrary types are forbidden by C from -/// having l-value type. These are: -/// - 'void', but not qualified void -/// - function types -/// -/// The exact rule here is C99 6.3.2.1: -/// An lvalue is an expression with an object type or an incomplete -/// type other than void. -static bool IsCForbiddenLValueType(ASTContext &C, QualType T) { - return ((T->isVoidType() && !T.hasQualifiers()) || - T->isFunctionType()); -} - ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -3528,1127 +3078,30 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) { // GNU extension: subscripting on pointer to void - Diag(LLoc, diag::ext_gnu_void_ptr) + Diag(LLoc, diag::ext_gnu_subscript_void_type) << BaseExpr->getSourceRange(); // C forbids expressions of unqualified void type from being l-values. // See IsCForbiddenLValueType. if (!ResultType.hasQualifiers()) VK = VK_RValue; - } else if (!ResultType->isDependentType() && - RequireCompleteType(LLoc, ResultType, - PDiag(diag::err_subscript_incomplete_type) - << BaseExpr->getSourceRange())) - return ExprError(); - - // Diagnose bad cases where we step over interface counts. - if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(LLoc, diag::err_subscript_nonfragile_interface) - << ResultType << BaseExpr->getSourceRange(); - return ExprError(); - } - - assert(VK == VK_RValue || LangOpts.CPlusPlus || - !IsCForbiddenLValueType(Context, ResultType)); - - return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, - ResultType, VK, OK, RLoc)); -} - -/// Check an ext-vector component access expression. -/// -/// VK should be set in advance to the value kind of the base -/// expression. -static QualType -CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, - SourceLocation OpLoc, const IdentifierInfo *CompName, - SourceLocation CompLoc) { - // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, - // see FIXME there. - // - // FIXME: This logic can be greatly simplified by splitting it along - // halving/not halving and reworking the component checking. - const ExtVectorType *vecType = baseType->getAs(); - - // The vector accessor can't exceed the number of elements. - const char *compStr = CompName->getNameStart(); - - // This flag determines whether or not the component is one of the four - // special names that indicate a subset of exactly half the elements are - // to be selected. - bool HalvingSwizzle = false; - - // This flag determines whether or not CompName has an 's' char prefix, - // indicating that it is a string of hex values to be used as vector indices. - bool HexSwizzle = *compStr == 's' || *compStr == 'S'; - - bool HasRepeated = false; - bool HasIndex[16] = {}; - - int Idx; - - // Check that we've found one of the special components, or that the component - // names must come from the same set. - if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || - !strcmp(compStr, "even") || !strcmp(compStr, "odd")) { - HalvingSwizzle = true; - } else if (!HexSwizzle && - (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { - do { - if (HasIndex[Idx]) HasRepeated = true; - HasIndex[Idx] = true; - compStr++; - } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1); - } else { - if (HexSwizzle) compStr++; - while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) { - if (HasIndex[Idx]) HasRepeated = true; - HasIndex[Idx] = true; - compStr++; - } - } - - if (!HalvingSwizzle && *compStr) { - // We didn't get to the end of the string. This means the component names - // didn't come from the same set *or* we encountered an illegal name. - S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) - << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); - return QualType(); - } - - // Ensure no component accessor exceeds the width of the vector type it - // operates on. - if (!HalvingSwizzle) { - compStr = CompName->getNameStart(); - - if (HexSwizzle) - compStr++; - - while (*compStr) { - if (!vecType->isAccessorWithinNumElements(*compStr++)) { - S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) - << baseType << SourceRange(CompLoc); - return QualType(); - } - } - } - - // The component accessor looks fine - now we need to compute the actual type. - // The vector type is implied by the component accessor. For example, - // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. - // vec4.s0 is a float, vec4.s23 is a vec3, etc. - // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. - unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2 - : CompName->getLength(); - if (HexSwizzle) - CompSize--; - - if (CompSize == 1) - return vecType->getElementType(); - - if (HasRepeated) VK = VK_RValue; - - QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); - // Now look up the TypeDefDecl from the vector type. Without this, - // diagostics look bad. We want extended vector types to appear built-in. - for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { - if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) - return S.Context.getTypedefType(S.ExtVectorDecls[i]); - } - return VT; // should never get here (a typedef type should always be found). -} - -static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, - IdentifierInfo *Member, - const Selector &Sel, - ASTContext &Context) { - if (Member) - if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) - return PD; - if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) - return OMD; - - for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), - E = PDecl->protocol_end(); I != E; ++I) { - if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, - Context)) - return D; - } - return 0; -} - -static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, - IdentifierInfo *Member, - const Selector &Sel, - ASTContext &Context) { - // Check protocols on qualified interfaces. - Decl *GDecl = 0; - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - if (Member) - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - GDecl = PD; - break; - } - // Also must look for a getter or setter name which uses property syntax. - if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) { - GDecl = OMD; - break; - } - } - if (!GDecl) { - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - // Search in the protocol-qualifier list of current protocol. - GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, - Context); - if (GDecl) - return GDecl; - } - } - return GDecl; -} - -ExprResult -Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, - bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs) { - // Even in dependent contexts, try to diagnose base expressions with - // obviously wrong types, e.g.: - // - // T* t; - // t.f; - // - // In Obj-C++, however, the above expression is valid, since it could be - // accessing the 'f' property if T is an Obj-C interface. The extra check - // allows this, while still reporting an error if T is a struct pointer. - if (!IsArrow) { - const PointerType *PT = BaseType->getAs(); - if (PT && (!getLangOptions().ObjC1 || - PT->getPointeeType()->isRecordType())) { - assert(BaseExpr && "cannot happen with implicit member accesses"); - Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union) - << BaseType << BaseExpr->getSourceRange(); - return ExprError(); - } - } - - assert(BaseType->isDependentType() || - NameInfo.getName().isDependentName() || - isDependentScopeSpecifier(SS)); - - // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr - // must have pointer type, and the accessed type is the pointee. - return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, - IsArrow, OpLoc, - SS.getWithLocInContext(Context), - FirstQualifierInScope, - NameInfo, TemplateArgs)); -} - -/// We know that the given qualified member reference points only to -/// declarations which do not belong to the static type of the base -/// expression. Diagnose the problem. -static void DiagnoseQualifiedMemberReference(Sema &SemaRef, - Expr *BaseExpr, - QualType BaseType, - const CXXScopeSpec &SS, - NamedDecl *rep, - const DeclarationNameInfo &nameInfo) { - // If this is an implicit member access, use a different set of - // diagnostics. - if (!BaseExpr) - return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); - - SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) - << SS.getRange() << rep << BaseType; -} - -// Check whether the declarations we found through a nested-name -// specifier in a member expression are actually members of the base -// type. The restriction here is: -// -// C++ [expr.ref]p2: -// ... In these cases, the id-expression shall name a -// member of the class or of one of its base classes. -// -// So it's perfectly legitimate for the nested-name specifier to name -// an unrelated class, and for us to find an overload set including -// decls from classes which are not superclasses, as long as the decl -// we actually pick through overload resolution is from a superclass. -bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, - QualType BaseType, - const CXXScopeSpec &SS, - const LookupResult &R) { - const RecordType *BaseRT = BaseType->getAs(); - if (!BaseRT) { - // We can't check this yet because the base type is still - // dependent. - assert(BaseType->isDependentType()); - return false; - } - CXXRecordDecl *BaseRecord = cast(BaseRT->getDecl()); - - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - // If this is an implicit member reference and we find a - // non-instance member, it's not an error. - if (!BaseExpr && !(*I)->isCXXInstanceMember()) - return false; - - // Note that we use the DC of the decl, not the underlying decl. - DeclContext *DC = (*I)->getDeclContext(); - while (DC->isTransparentContext()) - DC = DC->getParent(); - - if (!DC->isRecord()) - continue; - - llvm::SmallPtrSet MemberRecord; - MemberRecord.insert(cast(DC)->getCanonicalDecl()); - - if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) - return false; - } - - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, - R.getRepresentativeDecl(), - R.getLookupNameInfo()); - return true; -} - -static bool -LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - SourceRange BaseRange, const RecordType *RTy, - SourceLocation OpLoc, CXXScopeSpec &SS, - bool HasTemplateArgs) { - RecordDecl *RDecl = RTy->getDecl(); - if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), - SemaRef.PDiag(diag::err_typecheck_incomplete_tag) - << BaseRange)) - return true; - - if (HasTemplateArgs) { - // LookupTemplateName doesn't expect these both to exist simultaneously. - QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); - - bool MOUS; - SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS); - return false; - } - - DeclContext *DC = RDecl; - if (SS.isSet()) { - // If the member name was a qualified-id, look into the - // nested-name-specifier. - DC = SemaRef.computeDeclContext(SS, false); - - if (SemaRef.RequireCompleteDeclContext(SS, DC)) { - SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) - << SS.getRange() << DC; - return true; - } - - assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - - if (!isa(DC)) { - SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) - << DC << SS.getRange(); - return true; - } - } - - // The record definition is complete, now look up the member. - SemaRef.LookupQualifiedName(R, DC); - - if (!R.empty()) - return false; - - // We didn't find anything with the given name, so try to correct - // for typos. - DeclarationName Name = R.getLookupName(); - if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) && - !R.empty() && - (isa(*R.begin()) || isa(*R.begin()))) { - SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << DC << R.getLookupName() << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - if (NamedDecl *ND = R.getAsSingle()) - SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); - return false; - } else { - R.clear(); - R.setLookupName(Name); - } - - return false; -} - -ExprResult -Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, - SourceLocation OpLoc, bool IsArrow, - CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs) { - if (BaseType->isDependentType() || - (SS.isSet() && isDependentScopeSpecifier(SS))) - return ActOnDependentMemberExpr(Base, BaseType, - IsArrow, OpLoc, - SS, FirstQualifierInScope, - NameInfo, TemplateArgs); - - LookupResult R(*this, NameInfo, LookupMemberName); - - // Implicit member accesses. - if (!Base) { - QualType RecordTy = BaseType; - if (IsArrow) RecordTy = RecordTy->getAs()->getPointeeType(); - if (LookupMemberExprInRecord(*this, R, SourceRange(), - RecordTy->getAs(), - OpLoc, SS, TemplateArgs != 0)) - return ExprError(); - - // Explicit member accesses. - } else { - ExprResult BaseResult = Owned(Base); - ExprResult Result = - LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, - SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0); - - if (BaseResult.isInvalid()) - return ExprError(); - Base = BaseResult.take(); - - if (Result.isInvalid()) { - Owned(Base); - return ExprError(); - } - - if (Result.get()) - return move(Result); - - // LookupMemberExpr can modify Base, and thus change BaseType - BaseType = Base->getType(); - } - - return BuildMemberReferenceExpr(Base, BaseType, - OpLoc, IsArrow, SS, FirstQualifierInScope, - R, TemplateArgs); -} - -ExprResult -Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, - SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - bool SuppressQualifierCheck) { - QualType BaseType = BaseExprType; - if (IsArrow) { - assert(BaseType->isPointerType()); - BaseType = BaseType->getAs()->getPointeeType(); - } - R.setBaseObjectType(BaseType); - - const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); - DeclarationName MemberName = MemberNameInfo.getName(); - SourceLocation MemberLoc = MemberNameInfo.getLoc(); - - if (R.isAmbiguous()) - return ExprError(); - - if (R.empty()) { - // Rederive where we looked up. - DeclContext *DC = (SS.isSet() - ? computeDeclContext(SS, false) - : BaseType->getAs()->getDecl()); - - Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC - << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); - return ExprError(); - } - - // Diagnose lookups that find only declarations from a non-base - // type. This is possible for either qualified lookups (which may - // have been qualified with an unrelated type) or implicit member - // expressions (which were found with unqualified lookup and thus - // may have come from an enclosing scope). Note that it's okay for - // lookup to find declarations from a non-base type as long as those - // aren't the ones picked by overload resolution. - if ((SS.isSet() || !BaseExpr || - (isa(BaseExpr) && - cast(BaseExpr)->isImplicit())) && - !SuppressQualifierCheck && - CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) - return ExprError(); - - // Construct an unresolved result if we in fact got an unresolved - // result. - if (R.isOverloadedResult() || R.isUnresolvableResult()) { - // Suppress any lookup-related diagnostics; we'll do these when we - // pick a member. - R.suppressDiagnostics(); - - UnresolvedMemberExpr *MemExpr - = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(), - BaseExpr, BaseExprType, - IsArrow, OpLoc, - SS.getWithLocInContext(Context), - MemberNameInfo, - TemplateArgs, R.begin(), R.end()); - - return Owned(MemExpr); - } - - assert(R.isSingleResult()); - DeclAccessPair FoundDecl = R.begin().getPair(); - NamedDecl *MemberDecl = R.getFoundDecl(); - - // FIXME: diagnose the presence of template arguments now. - - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (MemberDecl->isInvalidDecl()) - return ExprError(); - - // Handle the implicit-member-access case. - if (!BaseExpr) { - // If this is not an instance member, convert to a non-member access. - if (!MemberDecl->isCXXInstanceMember()) - return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); - - SourceLocation Loc = R.getNameLoc(); - if (SS.getRange().isValid()) - Loc = SS.getRange().getBegin(); - BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); - } - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast(MemberDecl)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && !SS.isSet()) - ShouldCheckUse = false; - } - - // Check the use of this member. - if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) { - Owned(BaseExpr); - return ExprError(); - } - - // Perform a property load on the base regardless of whether we - // actually need it for the declaration. - if (BaseExpr->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(BaseExpr); - if (Result.isInvalid()) - return ExprError(); - BaseExpr = Result.take(); - } - - if (FieldDecl *FD = dyn_cast(MemberDecl)) - return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, - SS, FD, FoundDecl, MemberNameInfo); - - if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, - BaseExpr, OpLoc); - - if (VarDecl *Var = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, Var); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, FoundDecl, MemberNameInfo, - Var->getType().getNonReferenceType(), - VK_LValue, OK_Ordinary)); - } - - if (CXXMethodDecl *MemberFn = dyn_cast(MemberDecl)) { - ExprValueKind valueKind; - QualType type; - if (MemberFn->isInstance()) { - valueKind = VK_RValue; - type = Context.BoundMemberTy; - } else { - valueKind = VK_LValue; - type = MemberFn->getType(); - } - - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, FoundDecl, MemberNameInfo, - type, valueKind, OK_Ordinary)); - } - assert(!isa(MemberDecl) && "member function not C++ method?"); - - if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Enum, FoundDecl, MemberNameInfo, - Enum->getType(), VK_RValue, OK_Ordinary)); - } - - Owned(BaseExpr); - - // We found something that we didn't expect. Complain. - if (isa(MemberDecl)) - Diag(MemberLoc, diag::err_typecheck_member_reference_type) - << MemberName << BaseType << int(IsArrow); - else - Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) - << MemberName << BaseType << int(IsArrow); - - Diag(MemberDecl->getLocation(), diag::note_member_declared_here) - << MemberName; - R.suppressDiagnostics(); - return ExprError(); -} - -/// Given that normal member access failed on the given expression, -/// and given that the expression's type involves builtin-id or -/// builtin-Class, decide whether substituting in the redefinition -/// types would be profitable. The redefinition type is whatever -/// this translation unit tried to typedef to id/Class; we store -/// it to the side and then re-use it in places like this. -static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { - const ObjCObjectPointerType *opty - = base.get()->getType()->getAs(); - if (!opty) return false; - - const ObjCObjectType *ty = opty->getObjectType(); - - QualType redef; - if (ty->isObjCId()) { - redef = S.Context.ObjCIdRedefinitionType; - } else if (ty->isObjCClass()) { - redef = S.Context.ObjCClassRedefinitionType; - } else { - return false; - } - - // Do the substitution as long as the redefinition type isn't just a - // possibly-qualified pointer to builtin-id or builtin-Class again. - opty = redef->getAs(); - if (opty && !opty->getObjectType()->getInterface() != 0) - return false; - - base = S.ImpCastExprToType(base.take(), redef, CK_BitCast); - return true; -} - -/// Look up the given member of the given non-type-dependent -/// expression. This can return in one of two ways: -/// * If it returns a sentinel null-but-valid result, the caller will -/// assume that lookup was performed and the results written into -/// the provided structure. It will take over from there. -/// * Otherwise, the returned expression will be produced in place of -/// an ordinary member expression. -/// -/// The ObjCImpDecl bit is a gross hack that will need to be properly -/// fixed for ObjC++. -ExprResult -Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, - bool &IsArrow, SourceLocation OpLoc, - CXXScopeSpec &SS, - Decl *ObjCImpDecl, bool HasTemplateArgs) { - assert(BaseExpr.get() && "no base expression"); - - // Perform default conversions. - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - - if (IsArrow) { - BaseExpr = DefaultLvalueConversion(BaseExpr.take()); - if (BaseExpr.isInvalid()) - return ExprError(); - } - - QualType BaseType = BaseExpr.get()->getType(); - assert(!BaseType->isDependentType()); - - DeclarationName MemberName = R.getLookupName(); - SourceLocation MemberLoc = R.getNameLoc(); - - // For later type-checking purposes, turn arrow accesses into dot - // accesses. The only access type we support that doesn't follow - // the C equivalence "a->b === (*a).b" is ObjC property accesses, - // and those never use arrows, so this is unaffected. - if (IsArrow) { - if (const PointerType *Ptr = BaseType->getAs()) - BaseType = Ptr->getPointeeType(); - else if (const ObjCObjectPointerType *Ptr - = BaseType->getAs()) - BaseType = Ptr->getPointeeType(); - else if (BaseType->isRecordType()) { - // Recover from arrow accesses to records, e.g.: - // struct MyRecord foo; - // foo->bar - // This is actually well-formed in C++ if MyRecord has an - // overloaded operator->, but that should have been dealt with - // by now. - Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "."); - IsArrow = false; - } else if (BaseType == Context.BoundMemberTy) { - goto fail; - } else { - Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr.get()->getSourceRange(); - return ExprError(); - } - } - - // Handle field access to simple records. - if (const RecordType *RTy = BaseType->getAs()) { - if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(), - RTy, OpLoc, SS, HasTemplateArgs)) - return ExprError(); - - // Returning valid-but-null is how we indicate to the caller that - // the lookup result was filled in. - return Owned((Expr*) 0); - } - - // Handle ivar access to Objective-C objects. - if (const ObjCObjectType *OTy = BaseType->getAs()) { - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - // There are three cases for the base type: - // - builtin id (qualified or unqualified) - // - builtin Class (qualified or unqualified) - // - an interface - ObjCInterfaceDecl *IDecl = OTy->getInterface(); - if (!IDecl) { - // There's an implicit 'isa' ivar on all objects. - // But we only actually find it this way on objects of type 'id', - // apparently. - if (OTy->isObjCId() && Member->isStr("isa")) - return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, - Context.getObjCClassType())); - - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - goto fail; - } - - ObjCInterfaceDecl *ClassDeclared; - ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); - - if (!IV) { - // Attempt to correct for typos in ivar names. - LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), - LookupMemberName); - if (CorrectTypo(Res, 0, 0, IDecl, false, - IsArrow ? CTC_ObjCIvarLookup - : CTC_ObjCPropertyLookup) && - (IV = Res.getAsSingle())) { - Diag(R.getNameLoc(), - diag::err_typecheck_member_reference_ivar_suggest) - << IDecl->getDeclName() << MemberName << IV->getDeclName() - << FixItHint::CreateReplacement(R.getNameLoc(), - IV->getNameAsString()); - Diag(IV->getLocation(), diag::note_previous_decl) - << IV->getDeclName(); - } else { - Res.clear(); - Res.setLookupName(Member); - - Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) - << IDecl->getDeclName() << MemberName - << BaseExpr.get()->getSourceRange(); - return ExprError(); - } - } - - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (IV->isInvalidDecl()) - return ExprError(); - - // Check whether we can reference this field. - if (DiagnoseUseOfDecl(IV, MemberLoc)) - return ExprError(); - if (IV->getAccessControl() != ObjCIvarDecl::Public && - IV->getAccessControl() != ObjCIvarDecl::Package) { - ObjCInterfaceDecl *ClassOfMethodDecl = 0; - if (ObjCMethodDecl *MD = getCurMethodDecl()) - ClassOfMethodDecl = MD->getClassInterface(); - else if (ObjCImpDecl && getCurFunctionDecl()) { - // Case of a c-function declared inside an objc implementation. - // FIXME: For a c-style function nested inside an objc implementation - // class, there is no implementation context available, so we pass - // down the context as argument to this routine. Ideally, this context - // need be passed down in the AST node and somehow calculated from the - // AST for a function decl. - if (ObjCImplementationDecl *IMPD = - dyn_cast(ObjCImpDecl)) - ClassOfMethodDecl = IMPD->getClassInterface(); - else if (ObjCCategoryImplDecl* CatImplClass = - dyn_cast(ObjCImpDecl)) - ClassOfMethodDecl = CatImplClass->getClassInterface(); - } - - if (IV->getAccessControl() == ObjCIvarDecl::Private) { - if (ClassDeclared != IDecl || - ClassOfMethodDecl != ClassDeclared) - Diag(MemberLoc, diag::error_private_ivar_access) - << IV->getDeclName(); - } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) - // @protected - Diag(MemberLoc, diag::error_protected_ivar_access) - << IV->getDeclName(); - } - - return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr.take(), - IsArrow)); - } - - // Objective-C property access. - const ObjCObjectPointerType *OPT; - if (!IsArrow && (OPT = BaseType->getAs())) { - // This actually uses the base as an r-value. - BaseExpr = DefaultLvalueConversion(BaseExpr.take()); - if (BaseExpr.isInvalid()) - return ExprError(); - - assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType())); - - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - const ObjCObjectType *OT = OPT->getObjectType(); - - // id, with and without qualifiers. - if (OT->isObjCId()) { - // Check protocols on qualified interfaces. - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) { - if (ObjCPropertyDecl *PD = dyn_cast(PMDecl)) { - // Check the use of this declaration - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - QualType T = PD->getType(); - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - T = getMessageSendResultType(BaseType, Getter, false, false); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, T, - VK_LValue, - OK_ObjCProperty, - MemberLoc, - BaseExpr.take())); - } - - if (ObjCMethodDecl *OMD = dyn_cast(PMDecl)) { - // Check the use of this method. - if (DiagnoseUseOfDecl(OMD, MemberLoc)) - return ExprError(); - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); - ObjCMethodDecl *SMD = 0; - if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, - SetterSel, Context)) - SMD = dyn_cast(SDecl); - QualType PType = getMessageSendResultType(BaseType, OMD, false, - false); - - ExprValueKind VK = VK_LValue; - if (!getLangOptions().CPlusPlus && - IsCForbiddenLValueType(Context, PType)) - VK = VK_RValue; - ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); - - return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType, - VK, OK, - MemberLoc, BaseExpr.take())); - } - } - // Use of id.member can only be for a property reference. Do not - // use the 'id' redefinition in this case. - if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); - } - - // 'Class', unqualified only. - if (OT->isObjCClass()) { - // Only works in a method declaration (??!). - ObjCMethodDecl *MD = getCurMethodDecl(); - if (!MD) { - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - - goto fail; - } - - // Also must look for a getter name which uses property syntax. - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - ObjCMethodDecl *Getter; - if ((Getter = IFace->lookupClassMethod(Sel))) { - // Check the use of this method. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } else - Getter = IFace->lookupPrivateMethod(Sel, false); - // If we found a getter then this may be a valid dot-reference, we - // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); - ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = IFace->lookupPrivateMethod(SetterSel, false); - } - // Look through local category implementations associated with the class. - if (!Setter) - Setter = IFace->getCategoryClassMethod(SetterSel); - - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); - - if (Getter || Setter) { - QualType PType; - - ExprValueKind VK = VK_LValue; - if (Getter) { - PType = getMessageSendResultType(QualType(OT, 0), Getter, true, - false); - if (!getLangOptions().CPlusPlus && - IsCForbiddenLValueType(Context, PType)) - VK = VK_RValue; - } else { - // Get the expression type from Setter's incoming parameter. - PType = (*(Setter->param_end() -1))->getType(); - } - ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); - - // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, - PType, VK, OK, - MemberLoc, BaseExpr.take())); - } - - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); - } - - // Normal property access. - return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc, - SourceLocation(), QualType(), false); - } - - // Handle 'field access' to vectors, such as 'V.xx'. - if (BaseType->isExtVectorType()) { - // FIXME: this expr should store IsArrow. - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind()); - QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, - Member, MemberLoc); - if (ret.isNull()) - return ExprError(); - - return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(), - *Member, MemberLoc)); - } - - // Adjust builtin-sel to the appropriate redefinition type if that's - // not just a pointer to builtin-sel again. - if (IsArrow && - BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && - !Context.ObjCSelRedefinitionType->isObjCSelType()) { - BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType, - CK_BitCast); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - - // Failure cases. - fail: - - // Recover from dot accesses to pointers, e.g.: - // type *foo; - // foo.bar - // This is actually well-formed in two cases: - // - 'type' is an Objective C type - // - 'bar' is a pseudo-destructor name which happens to refer to - // the appropriate pointer type - if (const PointerType *Ptr = BaseType->getAs()) { - if (!IsArrow && Ptr->getPointeeType()->isRecordType() && - MemberName.getNameKind() != DeclarationName::CXXDestructorName) { - Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "->"); - - // Recurse as an -> access. - IsArrow = true; - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - } - - // If the user is trying to apply -> or . to a function name, it's probably - // because they forgot parentheses to call that function. - QualType ZeroArgCallTy; - UnresolvedSet<4> Overloads; - if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { - if (ZeroArgCallTy.isNull()) { - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); - UnresolvedSet<2> PlausibleOverloads; - for (OverloadExpr::decls_iterator It = Overloads.begin(), - DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { - const FunctionDecl *OverloadDecl = cast(*It); - QualType OverloadResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && OverloadResultTy->isRecordType()) || - (IsArrow && OverloadResultTy->isPointerType() && - OverloadResultTy->getPointeeType()->isRecordType())) - PlausibleOverloads.addDecl(It.getDecl()); - } - NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); - return ExprError(); - } - if ((!IsArrow && ZeroArgCallTy->isRecordType()) || - (IsArrow && ZeroArgCallTy->isPointerType() && - ZeroArgCallTy->getPointeeType()->isRecordType())) { - // At this point, we know BaseExpr looks like it's potentially callable - // with 0 arguments, and that it returns something of a reasonable type, - // so we can emit a fixit and carry on pretending that BaseExpr was - // actually a CallExpr. - SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() - << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - // FIXME: Try this before emitting the fixit, and suppress diagnostics - // while doing so. - ExprResult NewBase = - ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc.getFileLocWithOffset(1)); - if (NewBase.isInvalid()) - return ExprError(); - BaseExpr = NewBase; - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - } - - Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) - << BaseType << BaseExpr.get()->getSourceRange(); - - return ExprError(); -} - -/// The main callback when the parser finds something like -/// expression . [nested-name-specifier] identifier -/// expression -> [nested-name-specifier] identifier -/// where 'identifier' encompasses a fairly broad spectrum of -/// possibilities, including destructor and operator references. -/// -/// \param OpKind either tok::arrow or tok::period -/// \param HasTrailingLParen whether the next token is '(', which -/// is used to diagnose mis-uses of special members that can -/// only be called -/// \param ObjCImpDecl the current ObjC @implementation decl; -/// this is an ugly hack around the fact that ObjC @implementations -/// aren't properly put in the context chain -ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - CXXScopeSpec &SS, - UnqualifiedId &Id, - Decl *ObjCImpDecl, - bool HasTrailingLParen) { - if (SS.isSet() && SS.isInvalid()) - return ExprError(); - - // Warn about the explicit constructor calls Microsoft extension. - if (getLangOptions().Microsoft && - Id.getKind() == UnqualifiedId::IK_ConstructorName) - Diag(Id.getSourceRange().getBegin(), - diag::ext_ms_explicit_constructor_call); - - TemplateArgumentListInfo TemplateArgsBuffer; - - // Decompose the name into its component parts. - DeclarationNameInfo NameInfo; - const TemplateArgumentListInfo *TemplateArgs; - DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, - NameInfo, TemplateArgs); - - DeclarationName Name = NameInfo.getName(); - bool IsArrow = (OpKind == tok::arrow); - - NamedDecl *FirstQualifierInScope - = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S, - static_cast(SS.getScopeRep()))); - - // This is a postfix expression, so get rid of ParenListExprs. - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); - if (Result.isInvalid()) return ExprError(); - Base = Result.take(); - - if (Base->getType()->isDependentType() || Name.isDependentName() || - isDependentScopeSpecifier(SS)) { - Result = ActOnDependentMemberExpr(Base, Base->getType(), - IsArrow, OpLoc, - SS, FirstQualifierInScope, - NameInfo, TemplateArgs); - } else { - LookupResult R(*this, NameInfo, LookupMemberName); - ExprResult BaseResult = Owned(Base); - Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, - SS, ObjCImpDecl, TemplateArgs != 0); - if (BaseResult.isInvalid()) - return ExprError(); - Base = BaseResult.take(); - - if (Result.isInvalid()) { - Owned(Base); - return ExprError(); - } - - if (Result.get()) { - // The only way a reference to a destructor can be used is to - // immediately call it, which falls into this case. If the - // next token is not a '(', produce a diagnostic and build the - // call now. - if (!HasTrailingLParen && - Id.getKind() == UnqualifiedId::IK_DestructorName) - return DiagnoseDtorReference(NameInfo.getLoc(), Result.get()); - - return move(Result); - } + } else if (!ResultType->isDependentType() && + RequireCompleteType(LLoc, ResultType, + PDiag(diag::err_subscript_incomplete_type) + << BaseExpr->getSourceRange())) + return ExprError(); - Result = BuildMemberReferenceExpr(Base, Base->getType(), - OpLoc, IsArrow, SS, FirstQualifierInScope, - R, TemplateArgs); + // Diagnose bad cases where we step over interface counts. + if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { + Diag(LLoc, diag::err_subscript_nonfragile_interface) + << ResultType << BaseExpr->getSourceRange(); + return ExprError(); } - return move(Result); + assert(VK == VK_RValue || LangOpts.CPlusPlus || + !ResultType.isCForbiddenLValueType()); + + return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, + ResultType, VK, OK, RLoc)); } ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, @@ -4716,6 +3169,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(), const_cast(Temporary->getDestructor())); ExprTemporaries.push_back(Temporary); + ExprNeedsCleanups = true; } // We already type-checked the argument, so we know it works. @@ -4834,7 +3288,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, InitializedEntity Entity = Param? InitializedEntity::InitializeParameter(Context, Param) - : InitializedEntity::InitializeParameter(Context, ProtoArgType); + : InitializedEntity::InitializeParameter(Context, ProtoArgType, + Proto->isArgConsumed(i)); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Owned(Arg)); @@ -5157,7 +3612,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (Proto && i < Proto->getNumArgs()) { InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - Proto->getArgType(i)); + Proto->getArgType(i), + Proto->isArgConsumed(i)); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Owned(Arg)); @@ -5248,8 +3704,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, InitializedEntity Entity = InitializedEntity::InitializeTemporary(literalType); InitializationKind Kind - = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), - /*IsCStyleCast=*/true); + = InitializationKind::CreateCStyleCast(LParenLoc, + SourceRange(LParenLoc, RParenLoc)); InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, &literalExpr, 1), @@ -5267,8 +3723,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, // In C, compound literals are l-values for some reason. ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue; - return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, - VK, literalExpr, isFileScope)); + return MaybeBindToTemporary( + new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, + VK, literalExpr, isFileScope)); } ExprResult @@ -5426,14 +3883,15 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { } /// CheckCastTypes - Check type constraints for casting between types. -ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, - Expr *castExpr, CastKind& Kind, ExprValueKind &VK, +ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR, + QualType castType, Expr *castExpr, + CastKind& Kind, ExprValueKind &VK, CXXCastPath &BasePath, bool FunctionalStyle) { if (castExpr->getType() == Context.UnknownAnyTy) return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath); if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(SourceRange(TyR.getBegin(), + return CXXCheckCStyleCast(SourceRange(CastStartLoc, castExpr->getLocEnd()), castType, VK, castExpr, Kind, BasePath, FunctionalStyle); @@ -5551,8 +4009,8 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, // If either type is a pointer, the other type has to be either an // integer or a pointer. + QualType castExprType = castExpr->getType(); if (!castType->isArithmeticType()) { - QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType(Context) && castExprType->isArithmeticType()) { Diag(castExpr->getLocStart(), @@ -5568,6 +4026,36 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, } } + if (getLangOptions().ObjCAutoRefCount) { + // Diagnose problems with Objective-C casts involving lifetime qualifiers. + CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()), + castType, castExpr, CCK_CStyleCast); + + if (const PointerType *CastPtr = castType->getAs()) { + if (const PointerType *ExprPtr = castExprType->getAs()) { + Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers(); + Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers(); + if (CastPtr->getPointeeType()->isObjCLifetimeType() && + ExprPtr->getPointeeType()->isObjCLifetimeType() && + !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) { + Diag(castExpr->getLocStart(), + diag::err_typecheck_incompatible_ownership) + << castExprType << castType << AA_Casting + << castExpr->getSourceRange(); + + return ExprError(); + } + } + } + else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) { + Diag(castExpr->getLocStart(), + diag::err_arc_convesion_of_weak_unavailable) << 1 + << castExprType << castType + << castExpr->getSourceRange(); + return ExprError(); + } + } + castExprRes = Owned(castExpr); Kind = PrepareScalarCast(*this, castExprRes, castType); if (castExprRes.isInvalid()) @@ -5638,20 +4126,57 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, } ExprResult -Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty, +Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *castExpr) { - assert((Ty != 0) && (castExpr != 0) && + assert(!D.isInvalidType() && (castExpr != 0) && "ActOnCastExpr(): missing type or expr"); - TypeSourceInfo *castTInfo; - QualType castType = GetTypeFromParser(Ty, &castTInfo); - if (!castTInfo) - castTInfo = Context.getTrivialTypeSourceInfo(castType); + TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType()); + if (D.isInvalidType()) + return ExprError(); + + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + QualType castType = castTInfo->getType(); + Ty = CreateParsedType(castType, castTInfo); + + bool isVectorLiteral = false; + + // Check for an altivec or OpenCL literal, + // i.e. all the elements are integer constants. + ParenExpr *PE = dyn_cast(castExpr); + ParenListExpr *PLE = dyn_cast(castExpr); + if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) { + if (PLE && PLE->getNumExprs() == 0) { + Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer); + return ExprError(); + } + if (PE || PLE->getNumExprs() == 1) { + Expr *E = (PE ? PE->getSubExpr() : PLE->getExpr(0)); + if (!E->getType()->isVectorType()) + isVectorLiteral = true; + } + else + isVectorLiteral = true; + } + + // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' + // then handle it as such. + if (isVectorLiteral) + return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo); // If the Expr being casted is a ParenListExpr, handle it specially. - if (isa(castExpr)) - return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, castExpr, - castTInfo); + // This is not an AltiVec-style cast, so turn the ParenListExpr into a + // sequence of BinOp comma operators. + if (isa(castExpr)) { + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr); + if (Result.isInvalid()) return ExprError(); + castExpr = Result.take(); + } return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr); } @@ -5663,8 +4188,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, ExprValueKind VK = VK_RValue; CXXCastPath BasePath; ExprResult CastResult = - CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, - Kind, VK, BasePath); + CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(), + castExpr, Kind, VK, BasePath); if (CastResult.isInvalid()) return ExprError(); castExpr = CastResult.take(); @@ -5675,6 +4200,80 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, LParenLoc, RParenLoc)); } +ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, + SourceLocation RParenLoc, Expr *E, + TypeSourceInfo *TInfo) { + assert((isa(E) || isa(E)) && + "Expected paren or paren list expression"); + + Expr **exprs; + unsigned numExprs; + Expr *subExpr; + if (ParenListExpr *PE = dyn_cast(E)) { + exprs = PE->getExprs(); + numExprs = PE->getNumExprs(); + } else { + subExpr = cast(E)->getSubExpr(); + exprs = &subExpr; + numExprs = 1; + } + + QualType Ty = TInfo->getType(); + assert(Ty->isVectorType() && "Expected vector type"); + + llvm::SmallVector initExprs; + const VectorType *VTy = Ty->getAs(); + unsigned numElems = Ty->getAs()->getNumElements(); + + // '(...)' form of vector initialization in AltiVec: the number of + // initializers must be one or must match the size of the vector. + // If a single value is specified in the initializer then it will be + // replicated to all the components of the vector + if (VTy->getVectorKind() == VectorType::AltiVecVector) { + // The number of initializers must be one or must match the size of the + // vector. If a single value is specified in the initializer then it will + // be replicated to all the components of the vector + if (numExprs == 1) { + QualType ElemTy = Ty->getAs()->getElementType(); + ExprResult Literal = Owned(exprs[0]); + Literal = ImpCastExprToType(Literal.take(), ElemTy, + PrepareScalarCast(*this, Literal, ElemTy)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); + } + else if (numExprs < numElems) { + Diag(E->getExprLoc(), + diag::err_incorrect_number_of_vector_initializers); + return ExprError(); + } + else + for (unsigned i = 0, e = numExprs; i != e; ++i) + initExprs.push_back(exprs[i]); + } + else { + // For OpenCL, when the number of initializers is a single value, + // it will be replicated to all components of the vector. + if (getLangOptions().OpenCL && + VTy->getVectorKind() == VectorType::GenericVector && + numExprs == 1) { + QualType ElemTy = Ty->getAs()->getElementType(); + ExprResult Literal = Owned(exprs[0]); + Literal = ImpCastExprToType(Literal.take(), ElemTy, + PrepareScalarCast(*this, Literal, ElemTy)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); + } + + for (unsigned i = 0, e = numExprs; i != e; ++i) + initExprs.push_back(exprs[i]); + } + // FIXME: This means that pretty-printing the final AST will produce curly + // braces instead of the original commas. + InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc, + &initExprs[0], + initExprs.size(), RParenLoc); + initE->setType(Ty); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE); +} + /// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence /// of comma binary operators. ExprResult @@ -5694,91 +4293,18 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get()); } -ExprResult -Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, - SourceLocation RParenLoc, Expr *Op, - TypeSourceInfo *TInfo) { - ParenListExpr *PE = cast(Op); - QualType Ty = TInfo->getType(); - bool isVectorLiteral = false; - - // Check for an altivec or OpenCL literal, - // i.e. all the elements are integer constants. - if (getLangOptions().AltiVec && Ty->isVectorType()) { - if (PE->getNumExprs() == 0) { - Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer); - return ExprError(); - } - if (PE->getNumExprs() == 1) { - if (!PE->getExpr(0)->getType()->isVectorType()) - isVectorLiteral = true; - } - else - isVectorLiteral = true; - } - - // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' - // then handle it as such. - if (isVectorLiteral) { - llvm::SmallVector initExprs; - // '(...)' form of vector initialization in AltiVec: the number of - // initializers must be one or must match the size of the vector. - // If a single value is specified in the initializer then it will be - // replicated to all the components of the vector - if (Ty->getAs()->getVectorKind() == - VectorType::AltiVecVector) { - unsigned numElems = Ty->getAs()->getNumElements(); - // The number of initializers must be one or must match the size of the - // vector. If a single value is specified in the initializer then it will - // be replicated to all the components of the vector - if (PE->getNumExprs() == 1) { - QualType ElemTy = Ty->getAs()->getElementType(); - ExprResult Literal = Owned(PE->getExpr(0)); - Literal = ImpCastExprToType(Literal.take(), ElemTy, - PrepareScalarCast(*this, Literal, ElemTy)); - return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); - } - else if (PE->getNumExprs() < numElems) { - Diag(PE->getExprLoc(), - diag::err_incorrect_number_of_vector_initializers); - return ExprError(); - } - else - for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) - initExprs.push_back(PE->getExpr(i)); - } - else - for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) - initExprs.push_back(PE->getExpr(i)); - - // FIXME: This means that pretty-printing the final AST will produce curly - // braces instead of the original commas. - InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc, - &initExprs[0], - initExprs.size(), RParenLoc); - E->setType(Ty); - return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, E); - } else { - // This is not an AltiVec-style cast, so turn the ParenListExpr into a - // sequence of BinOp comma operators. - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Op); - if (Result.isInvalid()) return ExprError(); - return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Result.take()); - } -} - ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val, - ParsedType TypeOfCast) { + MultiExprArg Val) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast(Val.release()); assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); Expr *expr; - if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast)) + if (nexprs == 1) expr = new (Context) ParenExpr(L, R, exprs[0]); else - expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); + expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R, + exprs[nexprs-1]->getType()); return Owned(expr); } @@ -5876,7 +4402,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // Now check the two expressions. if (LHSTy->isVectorType() || RHSTy->isVectorType()) - return CheckVectorOperands(QuestionLoc, LHS, RHS); + return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false); // OpenCL: If the condition is a vector, and both operands are scalar, // attempt to implicity convert them to the vector type to act like the @@ -6203,43 +4729,21 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, return QualType(); } -/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps +/// SuggestParentheses - Emit a note with a fixit hint that wraps /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, - const PartialDiagnostic &PD, - const PartialDiagnostic &FirstNote, - SourceRange FirstParenRange, - const PartialDiagnostic &SecondNote, - SourceRange SecondParenRange) { - Self.Diag(Loc, PD); - - if (!FirstNote.getDiagID()) - return; - - SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); - if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just return. - return; - } - - Self.Diag(Loc, FirstNote) - << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - - if (!SecondNote.getDiagID()) - return; - - EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); - if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just dig the - // warning/error and return. - Self.Diag(Loc, SecondNote); - return; + const PartialDiagnostic &Note, + SourceRange ParenRange) { + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); + if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() && + EndLoc.isValid()) { + Self.Diag(Loc, Note) + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + } else { + // We can't display the parentheses, so just show the bare note. + Self.Diag(Loc, Note) << ParenRange; } - - Self.Diag(Loc, SecondNote) - << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); } static bool IsArithmeticOp(BinaryOperatorKind Opc) { @@ -6312,13 +4816,13 @@ static bool ExprLooksBoolean(Expr *E) { /// "int x = a + someBinaryCondition ? 1 : 2". static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc, - Expr *cond, - Expr *lhs, - Expr *rhs) { + Expr *Condition, + Expr *LHS, + Expr *RHS) { BinaryOperatorKind CondOpcode; Expr *CondRHS; - if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS)) + if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS)) return; if (!ExprLooksBoolean(CondRHS)) return; @@ -6326,25 +4830,18 @@ static void DiagnoseConditionalPrecedence(Sema &Self, // The condition is an arithmetic binary expression, with a right- // hand side that looks boolean, so warn. - PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional) - << cond->getSourceRange() - << BinaryOperator::getOpcodeStr(CondOpcode); - - PartialDiagnostic FirstNote = - Self.PDiag(diag::note_precedence_conditional_silence) + Self.Diag(OpLoc, diag::warn_precedence_conditional) + << Condition->getSourceRange() << BinaryOperator::getOpcodeStr(CondOpcode); - SourceRange FirstParenRange(cond->getLocStart(), - cond->getLocEnd()); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_conditional_silence) + << BinaryOperator::getOpcodeStr(CondOpcode), + SourceRange(Condition->getLocStart(), Condition->getLocEnd())); - PartialDiagnostic SecondNote = - Self.PDiag(diag::note_precedence_conditional_first); - - SourceRange SecondParenRange(CondRHS->getLocStart(), - rhs->getLocEnd()); - - SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange, - SecondNote, SecondParenRange); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_conditional_first), + SourceRange(CondRHS->getLocStart(), RHS->getLocEnd())); } /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null @@ -6427,17 +4924,31 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { // qualifiers of the type *pointed to* by the right; Qualifiers lq; + // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay. + if (lhq.getObjCLifetime() != rhq.getObjCLifetime() && + lhq.compatiblyIncludesObjCLifetime(rhq)) { + // Ignore lifetime for further calculation. + lhq.removeObjCLifetime(); + rhq.removeObjCLifetime(); + } + if (!lhq.compatiblyIncludes(rhq)) { // Treat address-space mismatches as fatal. TODO: address subspaces if (lhq.getAddressSpace() != rhq.getAddressSpace()) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; - // It's okay to add or remove GC qualifiers when converting to + // It's okay to add or remove GC or lifetime qualifiers when converting to // and from void*. - else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr()) + else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime() + .compatiblyIncludes( + rhq.withoutObjCGCAttr().withoutObjCGLifetime()) && (lhptee->isVoidType() || rhptee->isVoidType())) ; // keep old + // Treat lifetime mismatches as fatal. + else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) + ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + // For GCC compatibility, other qualifier mismatches are treated // as still compatible in C. else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; @@ -6614,6 +5125,7 @@ Sema::AssignConvertType Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, CastKind &Kind) { QualType rhsType = rhs.get()->getType(); + QualType origLhsType = lhsType; // Get canonical types. We're not formatting these types, just comparing // them. @@ -6768,7 +5280,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // A* -> B* if (rhsType->isObjCObjectPointerType()) { Kind = CK_BitCast; - return checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + Sema::AssignConvertType result = + checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + if (getLangOptions().ObjCAutoRefCount && + result == Compatible && + !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType)) + result = IncompatibleObjCWeakRef; + return result; } // int or null -> A* @@ -6936,8 +5454,12 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { AA_Assigning); if (Res.isInvalid()) return Incompatible; + Sema::AssignConvertType result = Compatible; + if (getLangOptions().ObjCAutoRefCount && + !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType())) + result = IncompatibleObjCWeakRef; rExpr = move(Res); - return Compatible; + return result; } // FIXME: Currently, we fall through and treat C++ classes like C @@ -6989,7 +5511,8 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult & return QualType(); } -QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) { +QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex, + SourceLocation Loc, bool isCompAssign) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhsType = @@ -7001,42 +5524,33 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu if (lhsType == rhsType) return lhsType; - // Handle the case of a vector & extvector type of the same size and element - // type. It would be nice if we only had one vector type someday. - if (getLangOptions().LaxVectorConversions) { - if (const VectorType *LV = lhsType->getAs()) { - if (const VectorType *RV = rhsType->getAs()) { - if (LV->getElementType() == RV->getElementType() && - LV->getNumElements() == RV->getNumElements()) { - if (lhsType->isExtVectorType()) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; - } - - lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); - return rhsType; - } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){ - // If we are allowing lax vector conversions, and LHS and RHS are both - // vectors, the total size only needs to be the same. This is a - // bitcast; no bits are changed but the result type is different. - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; - } - } - } - } - // Handle the case of equivalent AltiVec and GCC vector types if (lhsType->isVectorType() && rhsType->isVectorType() && Context.areCompatibleVectorTypes(lhsType, rhsType)) { - lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); + if (lhsType->isExtVectorType()) { + rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); + return lhsType; + } + + if (!isCompAssign) + lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); return rhsType; } + if (getLangOptions().LaxVectorConversions && + Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) { + // If we are allowing lax vector conversions, and LHS and RHS are both + // vectors, the total size only needs to be the same. This is a + // bitcast; no bits are changed but the result type is different. + // FIXME: Should we really be allowing this? + rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); + return lhsType; + } + // Canonicalize the ExtVector to the LHS, remember if we swapped so we can // swap back (so that we don't reverse the inputs to a subtract, for instance. bool swapped = false; - if (rhsType->isExtVectorType()) { + if (rhsType->isExtVectorType() && !isCompAssign) { swapped = true; std::swap(rex, lex); std::swap(rhsType, lhsType); @@ -7069,6 +5583,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu } // Vectors of different size or scalar and non-ext-vector are errors. + if (swapped) std::swap(rex, lex); Diag(Loc, diag::err_typecheck_vector_not_convertable) << lex.get()->getType() << rex.get()->getType() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); @@ -7078,7 +5593,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu QualType Sema::CheckMultiplyDivideOperands( ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); if (lex.isInvalid() || rex.isInvalid()) @@ -7102,7 +5617,7 @@ QualType Sema::CheckRemainderOperands( if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { if (lex.get()->getType()->hasIntegerRepresentation() && rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); return InvalidOperands(Loc, lex, rex); } @@ -7121,10 +5636,149 @@ QualType Sema::CheckRemainderOperands( return compType; } +/// \brief Diagnose invalid arithmetic on two void pointers. +static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS) { + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_void_type + : diag::ext_gnu_void_ptr) + << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange(); +} + +/// \brief Diagnose invalid arithmetic on a void pointer. +static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, + Expr *Pointer) { + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_void_type + : diag::ext_gnu_void_ptr) + << 0 /* one pointer */ << Pointer->getSourceRange(); +} + +/// \brief Diagnose invalid arithmetic on two function pointers. +static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS) { + assert(LHS->getType()->isAnyPointerType()); + assert(RHS->getType()->isAnyPointerType()); + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_function_type + : diag::ext_gnu_ptr_func_arith) + << 1 /* two pointers */ << LHS->getType()->getPointeeType() + // We only show the second type if it differs from the first. + << (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(), + RHS->getType()) + << RHS->getType()->getPointeeType() + << LHS->getSourceRange() << RHS->getSourceRange(); +} + +/// \brief Diagnose invalid arithmetic on a function pointer. +static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, + Expr *Pointer) { + assert(Pointer->getType()->isAnyPointerType()); + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_function_type + : diag::ext_gnu_ptr_func_arith) + << 0 /* one pointer */ << Pointer->getType()->getPointeeType() + << 0 /* one pointer, so only one type */ + << Pointer->getSourceRange(); +} + +/// \brief Check the validity of an arithmetic pointer operand. +/// +/// If the operand has pointer type, this code will check for pointer types +/// which are invalid in arithmetic operations. These will be diagnosed +/// appropriately, including whether or not the use is supported as an +/// extension. +/// +/// \returns True when the operand is valid to use (even if as an extension). +static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, + Expr *Operand) { + if (!Operand->getType()->isAnyPointerType()) return true; + + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (PointeeTy->isVoidType()) { + diagnoseArithmeticOnVoidPointer(S, Loc, Operand); + return !S.getLangOptions().CPlusPlus; + } + if (PointeeTy->isFunctionType()) { + diagnoseArithmeticOnFunctionPointer(S, Loc, Operand); + return !S.getLangOptions().CPlusPlus; + } + + if ((Operand->getType()->isPointerType() && + !Operand->getType()->isDependentType()) || + Operand->getType()->isObjCObjectPointerType()) { + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (S.RequireCompleteType( + Loc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PointeeTy << Operand->getSourceRange())) + return false; + } + + return true; +} + +/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer +/// operands. +/// +/// This routine will diagnose any invalid arithmetic on pointer operands much +/// like \see checkArithmeticOpPointerOperand. However, it has special logic +/// for emitting a single diagnostic even for operations where both LHS and RHS +/// are (potentially problematic) pointers. +/// +/// \returns True when the operand is valid to use (even if as an extension). +static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS) { + bool isLHSPointer = LHS->getType()->isAnyPointerType(); + bool isRHSPointer = RHS->getType()->isAnyPointerType(); + if (!isLHSPointer && !isRHSPointer) return true; + + QualType LHSPointeeTy, RHSPointeeTy; + if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType(); + if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType(); + + // Check for arithmetic on pointers to incomplete types. + bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType(); + bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType(); + if (isLHSVoidPtr || isRHSVoidPtr) { + if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS); + else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS); + else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS); + + return !S.getLangOptions().CPlusPlus; + } + + bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType(); + bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType(); + if (isLHSFuncPtr || isRHSFuncPtr) { + if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS); + else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS); + else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS); + + return !S.getLangOptions().CPlusPlus; + } + + Expr *Operands[] = { LHS, RHS }; + for (unsigned i = 0; i < 2; ++i) { + Expr *Operand = Operands[i]; + if ((Operand->getType()->isPointerType() && + !Operand->getType()->isDependentType()) || + Operand->getType()->isObjCObjectPointerType()) { + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (S.RequireCompleteType( + Loc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PointeeTy << Operand->getSourceRange())) + return false; + } + } + return true; +} + QualType Sema::CheckAdditionOperands( // C99 6.5.6 ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(Loc, lex, rex); + QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -7146,42 +5800,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 std::swap(PExp, IExp); if (PExp->getType()->isAnyPointerType()) { - if (IExp->getType()->isIntegerType()) { - QualType PointeeTy = PExp->getType()->getPointeeType(); - - // Check for arithmetic on pointers to incomplete types. - if (PointeeTy->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); - } + if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) + return QualType(); - // GNU extension: arithmetic on pointer to void - Diag(Loc, diag::ext_gnu_void_ptr) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } else if (PointeeTy->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex.get()->getType() << lex.get()->getSourceRange(); - return QualType(); - } + QualType PointeeTy = PExp->getType()->getPointeeType(); - // GNU extension: arithmetic on pointer to function - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << lex.get()->getType() << lex.get()->getSourceRange(); - } else { - // Check if we require a complete type. - if (((PExp->getType()->isPointerType() && - !PExp->getType()->isDependentType()) || - PExp->getType()->isObjCObjectPointerType()) && - RequireCompleteType(Loc, PointeeTy, - PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << PExp->getSourceRange() - << PExp->getType())) - return QualType(); - } // Diagnose bad cases where we step over interface counts. if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) @@ -7209,7 +5833,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(Loc, lex, rex); + QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -7231,35 +5855,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, if (lex.get()->getType()->isAnyPointerType()) { QualType lpointee = lex.get()->getType()->getPointeeType(); - // The LHS must be an completely-defined object type. - - bool ComplainAboutVoid = false; - Expr *ComplainAboutFunc = 0; - if (lpointee->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); - } - - // GNU C extension: arithmetic on pointer to void - ComplainAboutVoid = true; - } else if (lpointee->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex.get()->getType() << lex.get()->getSourceRange(); - return QualType(); - } - - // GNU C extension: arithmetic on pointer to function - ComplainAboutFunc = lex.get(); - } else if (!lpointee->isDependentType() && - RequireCompleteType(Loc, lpointee, - PDiag(diag::err_typecheck_sub_ptr_object) - << lex.get()->getSourceRange() - << lex.get()->getType())) - return QualType(); - // Diagnose bad cases where we step over interface counts. if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) @@ -7269,13 +5864,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, // The result type of a pointer-int computation is the pointer type. if (rex.get()->getType()->isIntegerType()) { - if (ComplainAboutVoid) - Diag(Loc, diag::ext_gnu_void_ptr) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - if (ComplainAboutFunc) - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << ComplainAboutFunc->getType() - << ComplainAboutFunc->getSourceRange(); + if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get())) + return QualType(); if (CompLHSTy) *CompLHSTy = lex.get()->getType(); return lex.get()->getType(); @@ -7285,33 +5875,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, if (const PointerType *RHSPTy = rex.get()->getType()->getAs()) { QualType rpointee = RHSPTy->getPointeeType(); - // RHS must be a completely-type object type. - // Handle the GNU void* extension. - if (rpointee->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); - } - - ComplainAboutVoid = true; - } else if (rpointee->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << rex.get()->getType() << rex.get()->getSourceRange(); - return QualType(); - } - - // GNU extension: arithmetic on pointer to function - if (!ComplainAboutFunc) - ComplainAboutFunc = rex.get(); - } else if (!rpointee->isDependentType() && - RequireCompleteType(Loc, rpointee, - PDiag(diag::err_typecheck_sub_ptr_object) - << rex.get()->getSourceRange() - << rex.get()->getType())) - return QualType(); - if (getLangOptions().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { @@ -7332,13 +5895,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, } } - if (ComplainAboutVoid) - Diag(Loc, diag::ext_gnu_void_ptr) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - if (ComplainAboutFunc) - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << ComplainAboutFunc->getType() - << ComplainAboutFunc->getSourceRange(); + if (!checkArithmeticBinOpPointerOperands(*this, Loc, + lex.get(), rex.get())) + return QualType(); if (CompLHSTy) *CompLHSTy = lex.get()->getType(); return Context.getPointerDiffType(); @@ -7394,19 +5953,24 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue()); Result = Result.shl(Right); + // Print the bit representation of the signed integer as an unsigned + // hexadecimal number. + llvm::SmallString<40> HexResult; + Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true); + // If we are only missing a sign bit, this is less likely to result in actual // bugs -- if the result is cast back to an unsigned type, it will have the // expected value. Thus we place this behind a different warning that can be // turned off separately if needed. if (LeftBits == ResultBits - 1) { - S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit) - << Result.toString(10) << LHSTy + S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) + << HexResult.str() << LHSTy << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return; } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) - << Result.toString(10) << Result.getMinSignedBits() << LHSTy + << HexResult.str() << Result.getMinSignedBits() << LHSTy << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } @@ -7427,7 +5991,7 @@ QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocati // Vector shifts promote their scalar inputs to vector type. if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 @@ -7720,7 +6284,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca // comparisons of member pointers to null pointer constants. if (RHSIsNull && ((lType->isAnyPointerType() || lType->isNullPtrType()) || - (!isRelational && lType->isMemberPointerType()))) { + (!isRelational && + (lType->isMemberPointerType() || lType->isBlockPointerType())))) { rex = ImpCastExprToType(rex.take(), lType, lType->isMemberPointerType() ? CK_NullToMemberPointer @@ -7729,7 +6294,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca } if (LHSIsNull && ((rType->isAnyPointerType() || rType->isNullPtrType()) || - (!isRelational && rType->isMemberPointerType()))) { + (!isRelational && + (rType->isMemberPointerType() || rType->isBlockPointerType())))) { lex = ImpCastExprToType(lex.take(), rType, rType->isMemberPointerType() ? CK_NullToMemberPointer @@ -7894,7 +6460,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, bool isRelational) { // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. - QualType vType = CheckVectorOperands(Loc, lex, rex); + QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false); if (vType.isNull()) return vType; @@ -7949,7 +6515,7 @@ inline QualType Sema::CheckBitwiseOperands( if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { if (lex.get()->getType()->hasIntegerRepresentation() && rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); return InvalidOperands(Loc, lex, rex); } @@ -7975,8 +6541,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // is a constant. if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() && rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() && - // Don't warn in macros. - !Loc.isMacroID()) { + // Don't warn in macros or template instantiations. + !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) { // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. @@ -8099,7 +6665,43 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { unsigned Diag = 0; bool NeedType = false; switch (IsLV) { // C99 6.5.16p2 - case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break; + case Expr::MLV_ConstQualified: + Diag = diag::err_typecheck_assign_const; + + // In ARC, use some specialized diagnostics for occasions where we + // infer 'const'. These are always pseudo-strong variables. + if (S.getLangOptions().ObjCAutoRefCount) { + DeclRefExpr *declRef = dyn_cast(E->IgnoreParenCasts()); + if (declRef && isa(declRef->getDecl())) { + VarDecl *var = cast(declRef->getDecl()); + + // Use the normal diagnostic if it's pseudo-__strong but the + // user actually wrote 'const'. + if (var->isARCPseudoStrong() && + (!var->getTypeSourceInfo() || + !var->getTypeSourceInfo()->getType().isConstQualified())) { + // There are two pseudo-strong cases: + // - self + ObjCMethodDecl *method = S.getCurMethodDecl(); + if (method && var == method->getSelfDecl()) + Diag = diag::err_typecheck_arr_assign_self; + + // - fast enumeration variables + else + Diag = diag::err_typecheck_arr_assign_enumeration; + + SourceRange Assign; + if (Loc != OrigLoc) + Assign = SourceRange(OrigLoc, OrigLoc); + S.Diag(Loc, Diag) << E->getSourceRange() << Assign; + // We need to preserve the AST regardless, so migration tool + // can do its job. + return false; + } + } + } + + break; case Expr::MLV_ArrayType: Diag = diag::err_typecheck_array_not_modifiable_lvalue; NeedType = true; @@ -8214,6 +6816,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc()); } } + + if (ConvTy == Compatible) { + if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) + checkRetainCycles(LHS, RHS.get()); + else if (getLangOptions().ObjCAutoRefCount) + checkUnsafeExprAssigns(Loc, LHS, RHS.get()); + } } else { // Compound assignment "x += y" ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType); @@ -8295,29 +6904,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, QualType PointeeTy = ResType->getPointeeType(); // C99 6.5.2.4p2, 6.5.6p2 - if (PointeeTy->isVoidType()) { - if (S.getLangOptions().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) - << Op->getSourceRange(); - return QualType(); - } - - // Pointer to void is a GNU extension in C. - S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); - } else if (PointeeTy->isFunctionType()) { - if (S.getLangOptions().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) - << Op->getType() << Op->getSourceRange(); - return QualType(); - } - - S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith) - << ResType << Op->getSourceRange(); - } else if (S.RequireCompleteType(OpLoc, PointeeTy, - S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << Op->getSourceRange() - << ResType)) + if (!checkArithmeticOpPointerOperand(S, OpLoc, Op)) return QualType(); + // Diagnose bad cases where we step over interface counts. else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) @@ -8400,6 +6989,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & LHS.get()->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty(); + bool Consumed = false; + if (PropRef->isImplicitProperty()) { // If using property-dot syntax notation for assignment, and there is a // setter, RHS expression is being passed to the setter argument. So, @@ -8407,6 +6998,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) { ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); LHSTy = (*P)->getType(); + Consumed = (getLangOptions().ObjCAutoRefCount && + (*P)->hasAttr()); // Otherwise, if the getter returns an l-value, just call that. } else { @@ -8418,14 +7011,26 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & return; } } + } else if (getLangOptions().ObjCAutoRefCount) { + const ObjCMethodDecl *setter + = PropRef->getExplicitProperty()->getSetterMethodDecl(); + if (setter) { + ObjCMethodDecl::param_iterator P = setter->param_begin(); + LHSTy = (*P)->getType(); + Consumed = (*P)->hasAttr(); + } } - if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) { + if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) || + getLangOptions().ObjCAutoRefCount) { InitializedEntity Entity = - InitializedEntity::InitializeParameter(Context, LHSTy); + InitializedEntity::InitializeParameter(Context, LHSTy, Consumed); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS); - if (!ArgE.isInvalid()) + if (!ArgE.isInvalid()) { RHS = ArgE; + if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver()) + checkRetainCycles(const_cast(PropRef->getBase()), RHS.get()); + } } } @@ -8682,8 +7287,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, VK = VK_LValue; // ...except that certain expressions are never l-values in C. - if (!S.getLangOptions().CPlusPlus && - IsCForbiddenLValueType(S.Context, Result)) + if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType()) VK = VK_RValue; return Result; @@ -8815,6 +7419,53 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, rhs = move(resolvedRHS); } + // The canonical way to check for a GNU null is with isNullPointerConstant, + // but we use a bit of a hack here for speed; this is a relatively + // hot path, and isNullPointerConstant is slow. + bool LeftNull = isa(lhs.get()->IgnoreParenImpCasts()); + bool RightNull = isa(rhs.get()->IgnoreParenImpCasts()); + + // Detect when a NULL constant is used improperly in an expression. These + // are mainly cases where the null pointer is used as an integer instead + // of a pointer. + if (LeftNull || RightNull) { + // Avoid analyzing cases where the result will either be invalid (and + // diagnosed as such) or entirely valid and not something to warn about. + QualType LeftType = lhs.get()->getType(); + QualType RightType = rhs.get()->getType(); + if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() && + !LeftType->isFunctionType() && + !RightType->isBlockPointerType() && + !RightType->isMemberPointerType() && + !RightType->isFunctionType()) { + if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || + Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || + Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || + Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || + Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || + Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { + // These are the operations that would not make sense with a null pointer + // no matter what the other expression is. + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << (LeftNull ? lhs.get()->getSourceRange() : SourceRange()) + << (RightNull ? rhs.get()->getSourceRange() : SourceRange()); + } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || + Opc == BO_EQ || Opc == BO_NE) { + // These are the operations that would not make sense with a null pointer + // if the other expression the other expression is not a pointer. + if (LeftNull != RightNull && + !LeftType->isAnyPointerType() && + !LeftType->canDecayToPointerType() && + !RightType->isAnyPointerType() && + !RightType->canDecayToPointerType()) { + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << (LeftNull ? lhs.get()->getSourceRange() + : rhs.get()->getSourceRange()); + } + } + } + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType()); @@ -8953,28 +7604,46 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, (BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc))) return; - if (BinOp::isComparisonOp(lhsopc)) + if (BinOp::isComparisonOp(lhsopc)) { + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << SourceRange(lhs->getLocStart(), OpLoc) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc); SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::warn_precedence_bitwise_rel) - << SourceRange(lhs->getLocStart(), OpLoc) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), Self.PDiag(diag::note_precedence_bitwise_silence) << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange(), + lhs->getSourceRange()); + SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), SourceRange(cast(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); - else if (BinOp::isComparisonOp(rhsopc)) + } else if (BinOp::isComparisonOp(rhsopc)) { + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << SourceRange(OpLoc, rhs->getLocEnd()) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc); SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::warn_precedence_bitwise_rel) - << SourceRange(OpLoc, rhs->getLocEnd()) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), Self.PDiag(diag::note_precedence_bitwise_silence) << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange(), + rhs->getSourceRange()); + SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocEnd(), cast(rhs)->getLHS()->getLocStart())); + SourceRange(lhs->getLocStart(), + cast(rhs)->getLHS()->getLocStart())); + } +} + +/// \brief It accepts a '&' expr that is inside a '|' one. +/// Emit a diagnostic together with a fixit hint that wraps the '&' expression +/// in parentheses. +static void +EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc, + BinaryOperator *Bop) { + assert(Bop->getOpcode() == BO_And); + Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or) + << Bop->getSourceRange() << OpLoc; + SuggestParentheses(Self, Bop->getOperatorLoc(), + Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence), + Bop->getSourceRange()); } /// \brief It accepts a '&&' expr that is inside a '||' one. @@ -8984,12 +7653,11 @@ static void EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, BinaryOperator *Bop) { assert(Bop->getOpcode() == BO_LAnd); + Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or) + << Bop->getSourceRange() << OpLoc; SuggestParentheses(Self, Bop->getOperatorLoc(), - Self.PDiag(diag::warn_logical_and_in_logical_or) - << Bop->getSourceRange() << OpLoc, Self.PDiag(diag::note_logical_and_in_logical_or_silence), - Bop->getSourceRange(), - Self.PDiag(0), SourceRange()); + Bop->getSourceRange()); } /// \brief Returns true if the given expression can be evaluated as a constant @@ -9043,13 +7711,28 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, } } +/// \brief Look for '&' in the left or right hand of a '|' expr. +static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc, + Expr *OrArg) { + if (BinaryOperator *Bop = dyn_cast(OrArg)) { + if (Bop->getOpcode() == BO_And) + return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop); + } +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *lhs, Expr *rhs){ // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) - return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + + // Diagnose "arg1 & arg2 | arg3" + if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) { + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs); + } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. // We don't warn for 'assert(a || b && "bad")' since this is safe. @@ -9274,6 +7957,29 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, Context.getPointerType(Context.VoidTy))); } +/// Given the last statement in a statement-expression, check whether +/// the result is a producing expression (like a call to an +/// ns_returns_retained function) and, if so, rebuild it to hoist the +/// release out of the full-expression. Otherwise, return null. +/// Cannot fail. +static Expr *maybeRebuildARCConsumingStmt(Stmt *s) { + // Should always be wrapped with one of these. + ExprWithCleanups *cleanups = dyn_cast(s); + if (!cleanups) return 0; + + ImplicitCastExpr *cast = dyn_cast(cleanups->getSubExpr()); + if (!cast || cast->getCastKind() != CK_ObjCConsumeObject) + return 0; + + // Splice out the cast. This shouldn't modify any interesting + // features of the statement. + Expr *producer = cast->getSubExpr(); + assert(producer->getType() == cast->getType()); + assert(producer->getValueKind() == cast->getValueKind()); + cleanups->setSubExpr(producer); + return cleanups; +} + ExprResult Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc) { // "({..})" @@ -9301,6 +8007,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, LastLabelStmt = Label; LastStmt = Label->getSubStmt(); } + if (Expr *LastE = dyn_cast(LastStmt)) { // Do function/array conversion on the last expression, but not // lvalue-to-rvalue. However, initialize an unqualified type. @@ -9310,12 +8017,24 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, Ty = LastExpr.get()->getType().getUnqualifiedType(); if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) { - LastExpr = PerformCopyInitialization( + // In ARC, if the final expression ends in a consume, splice + // the consume out and bind it later. In the alternate case + // (when dealing with a retainable type), the result + // initialization will create a produce. In both cases the + // result will be +1, and we'll need to balance that out with + // a bind. + if (Expr *rebuiltLastStmt + = maybeRebuildARCConsumingStmt(LastExpr.get())) { + LastExpr = rebuiltLastStmt; + } else { + LastExpr = PerformCopyInitialization( InitializedEntity::InitializeResult(LPLoc, Ty, false), SourceLocation(), - LastExpr); + LastExpr); + } + if (LastExpr.isInvalid()) return ExprError(); if (LastExpr.get() != 0) { @@ -9757,7 +8476,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If we don't have a function type, just build one from nothing. } else { FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default); + EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI); } @@ -9766,15 +8485,25 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. - if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction()) + if (getCurFunction()->NeedsScopeChecking() && + !hasAnyUnrecoverableErrorsInThisFunction()) DiagnoseInvalidJumps(cast(Body)); BSI->TheDecl->setBody(cast(Body)); - BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); + for (BlockDecl::capture_const_iterator ci = BSI->TheDecl->capture_begin(), + ce = BSI->TheDecl->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + QualType T = variable->getType(); + QualType::DestructionKind destructKind = T.isDestructedType(); + if (destructKind != QualType::DK_none) + getCurFunction()->setHasBranchProtectedScope(); + } + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result); + return Owned(Result); } @@ -9818,8 +8547,41 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, << OrigExpr->getType() << E->getSourceRange()); } - // FIXME: Check that type is complete/non-abstract - // FIXME: Warn if a non-POD type is passed in. + if (!TInfo->getType()->isDependentType()) { + if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(), + PDiag(diag::err_second_parameter_to_va_arg_incomplete) + << TInfo->getTypeLoc().getSourceRange())) + return ExprError(); + + if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(), + TInfo->getType(), + PDiag(diag::err_second_parameter_to_va_arg_abstract) + << TInfo->getTypeLoc().getSourceRange())) + return ExprError(); + + if (!TInfo->getType().isPODType(Context)) + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::warn_second_parameter_to_va_arg_not_pod) + << TInfo->getType() + << TInfo->getTypeLoc().getSourceRange(); + + // Check for va_arg where arguments of the given type will be promoted + // (i.e. this va_arg is guaranteed to have undefined behavior). + QualType PromoteType; + if (TInfo->getType()->isPromotableIntegerType()) { + PromoteType = Context.getPromotedIntegerType(TInfo->getType()); + if (Context.typesAreCompatible(PromoteType, TInfo->getType())) + PromoteType = QualType(); + } + if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float)) + PromoteType = Context.DoubleTy; + if (!PromoteType.isNull()) + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::warn_second_parameter_to_va_arg_never_compatible) + << TInfo->getType() + << PromoteType + << TInfo->getTypeLoc().getSourceRange(); + } QualType T = TInfo->getType().getNonLValueExprType(Context); return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T)); @@ -9913,6 +8675,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (lhq.getAddressSpace() != rhq.getAddressSpace()) { DiagKind = diag::err_typecheck_incompatible_address_space; break; + + + } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) { + DiagKind = diag::err_typecheck_incompatible_ownership; + break; } llvm_unreachable("unknown error case for discarding qualifiers!"); @@ -9950,6 +8717,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case IncompatibleVectors: DiagKind = diag::warn_incompatible_vectors; break; + case IncompatibleObjCWeakRef: + DiagKind = diag::err_arc_weak_unavailable_assign; + break; case Incompatible: DiagKind = diag::err_typecheck_convert_incompatible; isInvalid = true; @@ -10027,7 +8797,10 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { ExprEvalContexts.push_back( - ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size())); + ExpressionEvaluationContextRecord(NewContext, + ExprTemporaries.size(), + ExprNeedsCleanups)); + ExprNeedsCleanups = false; } void @@ -10062,15 +8835,27 @@ Sema::PopExpressionEvaluationContext() { // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they // will never be constructed. - if (Rec.Context == Unevaluated && - ExprTemporaries.size() > Rec.NumTemporaries) + if (Rec.Context == Unevaluated) { ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries, ExprTemporaries.end()); + ExprNeedsCleanups = Rec.ParentNeedsCleanups; + + // Otherwise, merge the contexts together. + } else { + ExprNeedsCleanups |= Rec.ParentNeedsCleanups; + } // Destroy the popped expression evaluation record. Rec.Destroy(); } +void Sema::DiscardCleanupsInEvaluationContext() { + ExprTemporaries.erase( + ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, + ExprTemporaries.end()); + ExprNeedsCleanups = false; +} + /// \brief Note that the given declaration was referenced in the source code. /// /// This routine should be invoke whenever a given declaration is referenced @@ -10364,7 +9149,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { /// during overload resolution or within sizeof/alignof/typeof/typeid. bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, const PartialDiagnostic &PD) { - switch (ExprEvalContexts.back().Context ) { + switch (ExprEvalContexts.back().Context) { case Unevaluated: // The argument will never be evaluated, so don't complain. break; @@ -10780,9 +9565,6 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { } ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { - ObjCMethodDecl *method = msg->getMethodDecl(); - assert(method && "__unknown_anytype message without result type?"); - // Verify that this is a legal result type of a call. if (DestType->isArrayType() || DestType->isFunctionType()) { S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function) @@ -10790,8 +9572,11 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { return ExprError(); } - assert(method->getResultType() == S.Context.UnknownAnyTy); - method->setResultType(DestType); + // Rewrite the method result type if available. + if (ObjCMethodDecl *method = msg->getMethodDecl()) { + assert(method->getResultType() == S.Context.UnknownAnyTy); + method->setResultType(DestType); + } // Change the type of the message. msg->setType(DestType.getNonReferenceType()); -- cgit v1.2.3