diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-03-16 16:52:15 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-03-16 16:52:15 +0000 |
commit | 1033b7c1e32962948b01a25145829f17bc70a8de (patch) | |
tree | 52aebaff3a47b97dbac434530524c30967468412 /lib/Sema | |
parent | 27c39af73c0d7d0b97e57b3a905040d4cefc9708 (diff) | |
download | FreeBSD-src-1033b7c1e32962948b01a25145829f17bc70a8de.zip FreeBSD-src-1033b7c1e32962948b01a25145829f17bc70a8de.tar.gz |
Update clang to r98631.
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/Makefile | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 165 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 207 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 58 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 24 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 167 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 1004 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 353 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 107 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 1085 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 64 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 175 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 96 |
24 files changed, 2075 insertions, 1533 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 5be6712..237803a 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -22,6 +22,7 @@ add_clang_library(clangSema SemaExprObjC.cpp SemaInit.cpp SemaLookup.cpp + SemaObjCProperty.cpp SemaOverload.cpp SemaStmt.cpp SemaTemplate.cpp diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile index 158f1af..3a5a99a 100644 --- a/lib/Sema/Makefile +++ b/lib/Sema/Makefile @@ -16,7 +16,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangSema BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a94d07a..4c25844 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -300,60 +300,38 @@ public: /// \brief The set of static functions seen so far that have not been used. std::vector<FunctionDecl*> UnusedStaticFuncs; - /// An enum describing the kind of diagnostics to use when checking - /// access. - enum AccessDiagnosticsKind { - /// Suppress diagnostics. - ADK_quiet, - - /// Use the normal diagnostics. - ADK_normal, - - /// Use the diagnostics appropriate for checking a covariant - /// return type. - ADK_covariance - }; - class AccessedEntity { public: - enum Kind { - /// A member declaration found through lookup. The target is the - /// member. - Member, - - /// A base-to-derived conversion. The target is the base class. - BaseToDerivedConversion, - - /// A derived-to-base conversion. The target is the base class. - DerivedToBaseConversion - }; - - bool isMemberAccess() const { return K == Member; } - - static AccessedEntity makeMember(CXXRecordDecl *NamingClass, - AccessSpecifier Access, - NamedDecl *Target) { - AccessedEntity E; - E.K = Member; - E.Access = Access; - E.Target = Target; - E.NamingClass = NamingClass; - return E; + /// A member declaration found through lookup. The target is the + /// member. + enum MemberNonce { Member }; + + /// A hierarchy (base-to-derived or derived-to-base) conversion. + /// The target is the base class. + enum BaseNonce { Base }; + + bool isMemberAccess() const { return IsMember; } + + AccessedEntity(MemberNonce _, + CXXRecordDecl *NamingClass, + AccessSpecifier Access, + NamedDecl *Target) + : Access(Access), IsMember(true), + Target(Target), NamingClass(NamingClass), + Diag(0) { } - static AccessedEntity makeBaseClass(bool BaseToDerived, - CXXRecordDecl *BaseClass, - CXXRecordDecl *DerivedClass, - AccessSpecifier Access) { - AccessedEntity E; - E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion; - E.Access = Access; - E.Target = BaseClass; - E.NamingClass = DerivedClass; - return E; + AccessedEntity(BaseNonce _, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) + : Access(Access), IsMember(false), + Target(BaseClass), NamingClass(DerivedClass), + Diag(0) { } - Kind getKind() const { return Kind(K); } + bool isQuiet() const { return Diag.getDiagID() == 0; } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } // These apply to member decls... @@ -364,11 +342,32 @@ public: CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); } CXXRecordDecl *getDerivedClass() const { return NamingClass; } + /// Sets a diagnostic to be performed. The diagnostic is given + /// four (additional) arguments: + /// %0 - 0 if the entity was private, 1 if protected + /// %1 - the DeclarationName of the entity + /// %2 - the TypeDecl type of the naming class + /// %3 - the TypeDecl type of the declaring class + void setDiag(const PartialDiagnostic &PDiag) { + assert(isQuiet() && "partial diagnostic already defined"); + Diag = PDiag; + } + PartialDiagnostic &setDiag(unsigned DiagID) { + assert(isQuiet() && "partial diagnostic already defined"); + assert(DiagID && "creating null diagnostic"); + Diag = PartialDiagnostic(DiagID); + return Diag; + } + const PartialDiagnostic &getDiag() const { + return Diag; + } + private: - unsigned K : 2; unsigned Access : 2; + bool IsMember; NamedDecl *Target; CXXRecordDecl *NamingClass; + PartialDiagnostic Diag; }; struct DelayedDiagnostic { @@ -384,9 +383,16 @@ public: struct { NamedDecl *Decl; } DeprecationData; /// Access control. - AccessedEntity AccessData; + char AccessData[sizeof(AccessedEntity)]; }; + void destroy() { + switch (Kind) { + case Access: getAccessData().~AccessedEntity(); break; + case Deprecation: break; + } + } + static DelayedDiagnostic makeDeprecation(SourceLocation Loc, NamedDecl *D) { DelayedDiagnostic DD; @@ -403,10 +409,16 @@ public: DD.Kind = Access; DD.Triggered = false; DD.Loc = Loc; - DD.AccessData = Entity; + new (&DD.getAccessData()) AccessedEntity(Entity); return DD; } + AccessedEntity &getAccessData() { + return *reinterpret_cast<AccessedEntity*>(AccessData); + } + const AccessedEntity &getAccessData() const { + return *reinterpret_cast<const AccessedEntity*>(AccessData); + } }; /// \brief The stack of diagnostics that were delayed due to being @@ -1469,7 +1481,7 @@ public: void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap); - + /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, @@ -1482,7 +1494,35 @@ public: ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, IdentifierInfo *NameII); - + + /// Called by ActOnProperty to handle @property declarations in + //// class extensions. + DeclPtrTy HandlePropertyInClassExtension(Scope *S, + ObjCCategoryDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + bool *isOverridingProperty, + QualType T, + tok::ObjCKeywordKind MethodImplKind); + + /// Called by ActOnProperty and HandlePropertyInClassExtension to + /// handle creating the ObjcPropertyDecl for a category or @interface. + ObjCPropertyDecl *CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, QualType T, + tok::ObjCKeywordKind MethodImplKind); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. @@ -2538,7 +2578,7 @@ public: SourceLocation Loc, SourceRange Range, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, - AccessDiagnosticsKind ADK, + unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name); @@ -2586,18 +2626,22 @@ public: CXXConstructorDecl *D, AccessSpecifier Access); AccessResult CheckDestructorAccess(SourceLocation Loc, - const RecordType *Record); + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag); + AccessResult CheckDirectMemberAccess(SourceLocation Loc, + NamedDecl *D, + const PartialDiagnostic &PDiag); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, + Expr *ArgExpr, NamedDecl *D, AccessSpecifier Access); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, - bool IsBaseToDerived, QualType Base, QualType Derived, const CXXBasePath &Path, + unsigned DiagID, bool ForceCheck = false, - bool ForceUnprivileged = false, - AccessDiagnosticsKind ADK = ADK_normal); + bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); @@ -3593,6 +3637,8 @@ public: DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); + bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params); + // Objective-C declarations. virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, @@ -4243,8 +4289,7 @@ private: SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const PartialDiagnostic &PD, - bool Equality = false); + const BinaryOperator::Opcode* BinOpc = 0); void CheckImplicitConversion(Expr *E, QualType Target); }; diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index eca8bb4..f0a38d5 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/ExprCXX.h" using namespace clang; @@ -55,7 +56,7 @@ struct EffectiveContext { explicit EffectiveContext(DeclContext *DC) { if (isa<FunctionDecl>(DC)) { - Function = cast<FunctionDecl>(DC); + Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); DC = Function->getDeclContext(); } else Function = 0; @@ -85,10 +86,34 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { + // A class always has access to its own members. if (EC.isClass(Class)) return Sema::AR_accessible; - // FIXME: implement + // Okay, check friends. + for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), + E = Class->friend_end(); I != E; ++I) { + FriendDecl *Friend = *I; + + if (Type *T = Friend->getFriendType()) { + if (EC.Record && + S.Context.hasSameType(QualType(T, 0), + S.Context.getTypeDeclType(EC.Record))) + return Sema::AR_accessible; + } else { + NamedDecl *D + = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + + // The decl pointers in EC have been canonicalized, so pointer + // equality is sufficient. + if (D == EC.Function || D == EC.Record) + return Sema::AR_accessible; + } + + // FIXME: templates! templated contexts! dependent delay! + } + + // That's it, give up. return Sema::AR_inaccessible; } @@ -230,18 +255,11 @@ static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, NamedDecl *D = Entity.getTargetDecl(); CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); - if (isa<CXXConstructorDecl>(D)) { - unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected - : diag::err_access_ctor_private); - S.Diag(Loc, DiagID) - << S.Context.getTypeDeclType(DeclaringClass); - } else { - unsigned DiagID = (Access == AS_protected ? diag::err_access_protected - : diag::err_access_private); - S.Diag(Loc, DiagID) - << D->getDeclName() - << S.Context.getTypeDeclType(DeclaringClass); - } + S.Diag(Loc, Entity.getDiag()) + << (Access == AS_protected) + << D->getDeclName() + << S.Context.getTypeDeclType(NamingClass) + << S.Context.getTypeDeclType(DeclaringClass); DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); } @@ -249,39 +267,25 @@ static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, const EffectiveContext &EC, AccessSpecifier Access, - const Sema::AccessedEntity &Entity, - Sema::AccessDiagnosticsKind ADK) { - if (ADK == Sema::ADK_covariance) { - S.Diag(Loc, diag::err_covariant_return_inaccessible_base) - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()) - << (Access == AS_protected); - } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) { - S.Diag(Loc, diag::err_downcast_from_inaccessible_base) - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()) - << (Access == AS_protected); - } else { - S.Diag(Loc, diag::err_upcast_to_inaccessible_base) - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()) - << (Access == AS_protected); - } + const Sema::AccessedEntity &Entity) { + S.Diag(Loc, Entity.getDiag()) + << (Access == AS_protected) + << DeclarationName() + << S.Context.getTypeDeclType(Entity.getDerivedClass()) + << S.Context.getTypeDeclType(Entity.getBaseClass()); DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), Entity.getBaseClass(), 0, Access); } -static void DiagnoseBadAccess(Sema &S, - SourceLocation Loc, +static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, const EffectiveContext &EC, CXXRecordDecl *NamingClass, AccessSpecifier Access, - const Sema::AccessedEntity &Entity, - Sema::AccessDiagnosticsKind ADK) { + const Sema::AccessedEntity &Entity) { if (Entity.isMemberAccess()) DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); else - DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK); + DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity); } @@ -344,8 +348,7 @@ static void TryElevateAccess(Sema &S, static Sema::AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC, SourceLocation Loc, - Sema::AccessedEntity const &Entity, - Sema::AccessDiagnosticsKind ADK) { + Sema::AccessedEntity const &Entity) { AccessSpecifier Access = Entity.getAccess(); assert(Access != AS_public); @@ -353,14 +356,14 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S, while (NamingClass->isAnonymousStructOrUnion()) // This should be guaranteed by the fact that the decl has // non-public access. If not, we should make it guaranteed! - NamingClass = cast<CXXRecordDecl>(NamingClass); + NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); if (!EC.Record) { TryElevateAccess(S, EC, Entity, Access); if (Access == AS_public) return Sema::AR_accessible; - if (ADK != Sema::ADK_quiet) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK); + if (!Entity.isQuiet()) + DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); return Sema::AR_inaccessible; } @@ -393,15 +396,13 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S, } // Okay, that's it, reject it. - if (ADK != Sema::ADK_quiet) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK); + if (!Entity.isQuiet()) + DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); return Sema::AR_inaccessible; } static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, - const Sema::AccessedEntity &Entity, - Sema::AccessDiagnosticsKind ADK - = Sema::ADK_normal) { + const Sema::AccessedEntity &Entity) { // If the access path is public, it's accessible everywhere. if (Entity.getAccess() == AS_public) return Sema::AR_accessible; @@ -411,14 +412,13 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, // can actually change our effective context for the purposes of // access control. if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { - assert(ADK == Sema::ADK_normal && "delaying abnormal access check"); S.DelayedDiagnostics.push_back( Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); return Sema::AR_delayed; } return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), - Loc, Entity, ADK); + Loc, Entity); } void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { @@ -426,18 +426,23 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { // declaration. EffectiveContext EC(Ctx->getDeclContext()); - if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal)) + if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData())) DD.Triggered = true; } Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, NamedDecl *D, AccessSpecifier Access) { - if (!getLangOptions().AccessControl || !E->getNamingClass()) + if (!getLangOptions().AccessControl || + !E->getNamingClass() || + Access == AS_public) return AR_accessible; - return CheckAccess(*this, E->getNameLoc(), - AccessedEntity::makeMember(E->getNamingClass(), Access, D)); + AccessedEntity Entity(AccessedEntity::Member, + E->getNamingClass(), Access, D); + Entity.setDiag(diag::err_access) << E->getSourceRange(); + + return CheckAccess(*this, E->getNameLoc(), Entity); } /// Perform access-control checking on a previously-unresolved member @@ -445,56 +450,90 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, NamedDecl *D, AccessSpecifier Access) { - if (!getLangOptions().AccessControl) + if (!getLangOptions().AccessControl || + Access == AS_public) return AR_accessible; - return CheckAccess(*this, E->getMemberLoc(), - AccessedEntity::makeMember(E->getNamingClass(), Access, D)); + AccessedEntity Entity(AccessedEntity::Member, + E->getNamingClass(), Access, D); + Entity.setDiag(diag::err_access) << E->getSourceRange(); + + return CheckAccess(*this, E->getMemberLoc(), Entity); } Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, - const RecordType *RT) { + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag) { if (!getLangOptions().AccessControl) return AR_accessible; - CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context); - + // There's never a path involved when checking implicit destructor access. AccessSpecifier Access = Dtor->getAccess(); if (Access == AS_public) return AR_accessible; - return CheckAccess(*this, Loc, - AccessedEntity::makeMember(NamingClass, Access, Dtor)); + CXXRecordDecl *NamingClass = Dtor->getParent(); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor); + Entity.setDiag(PDiag); // TODO: avoid copy + + return CheckAccess(*this, Loc, Entity); } /// Checks access to a constructor. Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, CXXConstructorDecl *Constructor, AccessSpecifier Access) { - if (!getLangOptions().AccessControl) + if (!getLangOptions().AccessControl || + Access == AS_public) return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - return CheckAccess(*this, UseLoc, - AccessedEntity::makeMember(NamingClass, Access, Constructor)); + AccessedEntity Entity(AccessedEntity::Member, + NamingClass, Access, Constructor); + Entity.setDiag(diag::err_access_ctor); + + return CheckAccess(*this, UseLoc, Entity); +} + +/// Checks direct (i.e. non-inherited) access to an arbitrary class +/// member. +Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, + NamedDecl *Target, + const PartialDiagnostic &Diag) { + AccessSpecifier Access = Target->getAccess(); + if (!getLangOptions().AccessControl || + Access == AS_public) + return AR_accessible; + + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target); + Entity.setDiag(Diag); + return CheckAccess(*this, UseLoc, Entity); } + /// Checks access to an overloaded member operator, including /// conversion operators. Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, Expr *ObjectExpr, + Expr *ArgExpr, NamedDecl *MemberOperator, AccessSpecifier Access) { - if (!getLangOptions().AccessControl) + if (!getLangOptions().AccessControl || + Access == AS_public) return AR_accessible; const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - return CheckAccess(*this, OpLoc, - AccessedEntity::makeMember(NamingClass, Access, MemberOperator)); + AccessedEntity Entity(AccessedEntity::Member, + NamingClass, Access, MemberOperator); + Entity.setDiag(diag::err_access) + << ObjectExpr->getSourceRange() + << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); + + return CheckAccess(*this, OpLoc, Entity); } /// Checks access for a hierarchy conversion. @@ -507,31 +546,29 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, /// context had no special privileges /// \param ADK controls the kind of diagnostics that are used Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, - bool IsBaseToDerived, QualType Base, QualType Derived, const CXXBasePath &Path, + unsigned DiagID, bool ForceCheck, - bool ForceUnprivileged, - AccessDiagnosticsKind ADK) { + bool ForceUnprivileged) { if (!ForceCheck && !getLangOptions().AccessControl) return AR_accessible; if (Path.Access == AS_public) return AR_accessible; - // TODO: preserve the information about which types exactly were used. CXXRecordDecl *BaseD, *DerivedD; BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); - AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived, - BaseD, DerivedD, - Path.Access); + + AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access); + if (DiagID) + Entity.setDiag(DiagID) << Derived << Base; if (ForceUnprivileged) - return CheckEffectiveAccess(*this, EffectiveContext(), - AccessLoc, Entity, ADK); - return CheckAccess(*this, AccessLoc, Entity, ADK); + return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity); + return CheckAccess(*this, AccessLoc, Entity); } /// Checks access to all the declarations in the given result set. @@ -540,9 +577,13 @@ void Sema::CheckLookupAccess(const LookupResult &R) { && "performing access check without access control"); assert(R.getNamingClass() && "performing access check without naming class"); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - if (I.getAccess() != AS_public) - CheckAccess(*this, R.getNameLoc(), - AccessedEntity::makeMember(R.getNamingClass(), - I.getAccess(), *I)); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + if (I.getAccess() != AS_public) { + AccessedEntity Entity(AccessedEntity::Member, + R.getNamingClass(), I.getAccess(), *I); + Entity.setDiag(diag::err_access); + + CheckAccess(*this, R.getNameLoc(), Entity); + } + } } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index e04abd2..014cec2 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -780,9 +780,9 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, } if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - /*IsBaseToDerived*/ true, SrcType, DestType, - Paths.front())) { + Paths.front(), + diag::err_downcast_from_inaccessible_base)) { msg = 0; return TC_Failed; } @@ -858,9 +858,9 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - /*IsBaseToDerived*/ false, DestType, SrcType, - Paths.front())) { + Paths.front(), + diag::err_upcast_to_inaccessible_base)) { msg = 0; return TC_Failed; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 30a6ab4..3fac79d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -59,9 +59,12 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, // Re-lex the token to get its length and original spelling. std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(StrTokSpellingLoc); - std::pair<const char *,const char *> Buffer = - SourceMgr.getBufferData(LocInfo.first); - const char *StrData = Buffer.first+LocInfo.second; + bool Invalid = false; + llvm::StringRef Buffer = SourceMgr.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return StrTokSpellingLoc; + + const char *StrData = Buffer.data()+LocInfo.second; // Create a langops struct and enable trigraphs. This is sufficient for // relexing tokens. @@ -69,8 +72,8 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, LangOpts.Trigraphs = true; // Create a lexer starting at the beginning of this token. - Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData, - Buffer.second); + Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.begin(), StrData, + Buffer.end()); Token TheTok; TheLexer.LexFromRawLexer(TheTok); @@ -2011,10 +2014,9 @@ bool IsSameFloatAfterCast(const APValue &value, /// \param lex the left-hand expression /// \param rex the right-hand expression /// \param OpLoc the location of the joining operator -/// \param Equality whether this is an "equality-like" join, which -/// suppresses the warning in some cases +/// \param BinOpc binary opcode or 0 void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const PartialDiagnostic &PD, bool Equality) { + const BinaryOperator::Opcode* BinOpc) { // Don't warn if we're in an unevaluated context. if (ExprEvalContexts.back().Context == Unevaluated) return; @@ -2075,17 +2077,51 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, // If the signed operand is non-negative, then the signed->unsigned // conversion won't change it. - if (signedRange.NonNegative) + if (signedRange.NonNegative) { + // Emit warnings for comparisons of unsigned to integer constant 0. + // always false: x < 0 (or 0 > x) + // always true: x >= 0 (or 0 <= x) + llvm::APSInt X; + if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) { + if (signedOperand != lex) { + if (*BinOpc == BinaryOperator::LT) { + Diag(OpLoc, diag::warn_lunsigned_always_true_comparison) + << "< 0" << "false" + << lex->getSourceRange() << rex->getSourceRange(); + } + else if (*BinOpc == BinaryOperator::GE) { + Diag(OpLoc, diag::warn_lunsigned_always_true_comparison) + << ">= 0" << "true" + << lex->getSourceRange() << rex->getSourceRange(); + } + } + else { + if (*BinOpc == BinaryOperator::GT) { + Diag(OpLoc, diag::warn_runsigned_always_true_comparison) + << "0 >" << "false" + << lex->getSourceRange() << rex->getSourceRange(); + } + else if (*BinOpc == BinaryOperator::LE) { + Diag(OpLoc, diag::warn_runsigned_always_true_comparison) + << "0 <=" << "true" + << lex->getSourceRange() << rex->getSourceRange(); + } + } + } return; + } // For (in)equality comparisons, if the unsigned operand is a // constant which cannot collide with a overflowed signed operand, // then reinterpreting the signed operand as unsigned will not // change the result of the comparison. - if (Equality && unsignedRange.Width < unsignedWidth) + if (BinOpc && + (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) && + unsignedRange.Width < unsignedWidth) return; - Diag(OpLoc, PD) + Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison + : diag::warn_mixed_sign_conditional) << lt << rt << lex->getSourceRange() << rex->getSourceRange(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index edf1bc5..4693fa9 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -365,8 +365,7 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, // Friend declarations and declarations introduced due to friends are never // added as results. - if (isa<FriendDecl>(ND) || - (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) + if (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)) return false; // Class template (partial) specializations are never added as results. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 94fcfc6..dab7d88 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2262,6 +2262,13 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, return true; } +static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { + CXXScopeSpec &SS = D.getCXXScopeSpec(); + if (!SS.isSet()) return; + DD->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()), + SS.getRange()); +} + NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, @@ -2371,6 +2378,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.isInvalidType()) NewVD->setInvalidDecl(); + SetNestedNameSpecifier(NewVD, D); + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); @@ -2718,6 +2727,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getIdentifierLoc(), Name, R, isInline, /*isImplicitlyDeclared=*/false); + NewFD->setTypeSourceInfo(TInfo); isVirtualOkay = true; } else { @@ -2798,6 +2808,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.isInvalidType()) NewFD->setInvalidDecl(); + SetNestedNameSpecifier(NewFD, D); + // Set the lexical context. If the declarator has a C++ // scope specifier, or is the object of a friend declaration, the // lexical context will be different from the semantic context. @@ -4248,9 +4260,10 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, CompoundStmt *Compound = isa<CXXTryStmt>(Body) ? cast<CXXTryStmt>(Body)->getTryBlock() : cast<CompoundStmt>(Body); - std::vector<Stmt*> Elements(Compound->body_begin(), Compound->body_end()); + llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(), + Compound->body_end()); Elements.push_back(L); - Compound->setStmts(Context, &Elements[0], Elements.size()); + Compound->setStmts(Context, Elements.data(), Elements.size()); } if (Body) { @@ -4845,6 +4858,13 @@ CreateNewDecl: cast_or_null<RecordDecl>(PrevDecl)); } + // Maybe add qualifier info. + if (SS.isNotEmpty()) { + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + New->setQualifierInfo(NNS, SS.getRange()); + } + if (Kind != TagDecl::TK_enum) { // Handle #pragma pack: if the #pragma pack stack has non-default // alignment, make up a packed attribute for this decl. These diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 242d66f..73a34f8 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1945,11 +1945,19 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), FD->getLocation(), DeclarationName(II), FD->getType(), FD->getTypeSourceInfo()); + if (FD->getQualifier()) { + FunctionDecl *NewFD = cast<FunctionDecl>(NewD); + NewFD->setQualifierInfo(FD->getQualifier(), FD->getQualifierRange()); + } } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); + if (VD->getQualifier()) { + VarDecl *NewVD = cast<VarDecl>(NewD); + NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange()); + } } return NewD; } @@ -2030,6 +2038,8 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { assert(SavedIndex <= DelayedDiagnostics.size() && "saved index is out of bounds"); + unsigned E = DelayedDiagnostics.size(); + // We only want to actually emit delayed diagnostics when we // successfully parsed a decl. Decl *D = Ctx ? Ctx.getAs<Decl>() : 0; @@ -2040,7 +2050,7 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { // only the declarator pops will be passed decls. This is correct; // we really do need to consider delayed diagnostics from the decl spec // for each of the different declarations. - for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) { + for (unsigned I = 0; I != E; ++I) { if (DelayedDiagnostics[I].Triggered) continue; @@ -2056,6 +2066,10 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { } } + // Destroy all the delayed diagnostics we're about to pop off. + for (unsigned I = SavedIndex; I != E; ++I) + DelayedDiagnostics[I].destroy(); + DelayedDiagnostics.set_size(SavedIndex); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e694cb4..c27b0d5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -298,6 +298,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { Invalid = true; } else if (OldParam->hasDefaultArg()) { // Merge the old default argument into the new parameter + NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); @@ -719,7 +720,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { /// if there is an error. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, - AccessDiagnosticsKind ADK, + unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name) { @@ -735,15 +736,12 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (ADK == ADK_quiet) + if (!InaccessibleBaseID) return false; // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false, - Base, Derived, Paths.front(), - /*force*/ false, - /*unprivileged*/ false, - ADK)) { + switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), + InaccessibleBaseID)) { case AR_accessible: return false; case AR_inaccessible: return true; case AR_dependent: return false; @@ -779,7 +777,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, - IgnoreAccess ? ADK_quiet : ADK_normal, + IgnoreAccess ? 0 + : diag::err_upcast_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName()); } @@ -1657,6 +1656,11 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + + // We don't know if a dependent type will have an implicit destructor. + if (BaseClassDecl->isDependentType()) + continue; + if (BaseClassDecl->hasTrivialDestructor()) continue; CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context); @@ -1848,6 +1852,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { // Ignore dependent destructors. if (Destructor->isDependentContext()) return; + + // FIXME: all the access-control diagnostics are positioned on the + // field/base declaration. That's probably good; that said, the + // user might reasonably want to know why the destructor is being + // emitted, and we currently don't say. CXXRecordDecl *ClassDecl = Destructor->getParent(); @@ -1866,25 +1875,41 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { if (FieldClassDecl->hasTrivialDestructor()) continue; - const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); + CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); + CheckDestructorAccess(Field->getLocation(), Dtor, + PartialDiagnostic(diag::err_access_dtor_field) + << Field->getDeclName() + << FieldType); + MarkDeclarationReferenced(Destructor->getLocation(), const_cast<CXXDestructorDecl*>(Dtor)); } + llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; + // Bases. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - // Ignore virtual bases. + // Bases are always records in a well-formed non-dependent class. + const RecordType *RT = Base->getType()->getAs<RecordType>(); + + // Remember direct virtual bases. if (Base->isVirtual()) - continue; + DirectVirtualBases.insert(RT); // Ignore trivial destructors. - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; + + CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + + // FIXME: caret should be on the start of the class name + CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor, + PartialDiagnostic(diag::err_access_dtor_base) + << Base->getType() + << Base->getSourceRange()); - const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); MarkDeclarationReferenced(Destructor->getLocation(), const_cast<CXXDestructorDecl*>(Dtor)); } @@ -1892,13 +1917,24 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { // Virtual bases. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) { + + // Bases are always records in a well-formed non-dependent class. + const RecordType *RT = VBase->getType()->getAs<RecordType>(); + + // Ignore direct virtual bases. + if (DirectVirtualBases.count(RT)) + continue; + // Ignore trivial destructors. - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; - - const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + + CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + CheckDestructorAccess(ClassDecl->getLocation(), Dtor, + PartialDiagnostic(diag::err_access_dtor_vbase) + << VBase->getType()); + MarkDeclarationReferenced(Destructor->getLocation(), const_cast<CXXDestructorDecl*>(Dtor)); } @@ -2392,22 +2428,26 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. + QualType Ty = Context.getFunctionType(Context.VoidTy, + 0, 0, false, 0, + /*FIXME:*/false, + false, 0, 0, false, + CC_Default); + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); CXXDestructorDecl *Destructor = CXXDestructorDecl::Create(Context, ClassDecl, - ClassDecl->getLocation(), Name, - Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0, - /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + ClassDecl->getLocation(), Name, Ty, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); ClassDecl->addDecl(Destructor); + + // This could be uniqued if it ever proves significant. + Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); } @@ -3779,45 +3819,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, DeclContext *PreviousContext = CurContext; CurContext = Destructor; - // C++ [class.dtor] p5 - // Before the implicitly-declared default destructor for a class is - // implicitly defined, all the implicitly-declared default destructors - // for its base class and its non-static data members shall have been - // implicitly defined. - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - E = ClassDecl->bases_end(); Base != E; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasTrivialDestructor()) { - if (CXXDestructorDecl *BaseDtor = - const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context))) - MarkDeclarationReferenced(CurrentLocation, BaseDtor); - else - assert(false && - "DefineImplicitDestructor - missing dtor in a base class"); - } - } + MarkBaseAndMemberDestructorsReferenced(Destructor); - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasTrivialDestructor()) { - if (CXXDestructorDecl *FieldDtor = - const_cast<CXXDestructorDecl*>( - FieldClassDecl->getDestructor(Context))) - MarkDeclarationReferenced(CurrentLocation, FieldDtor); - else - assert(false && - "DefineImplicitDestructor - missing dtor in class of a data member"); - } - } - } - // FIXME: If CheckDestructor fails, we should emit a note about where the // implicit destructor was needed. if (CheckDestructor(Destructor)) { @@ -3859,8 +3862,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *BaseAssignOpMethod = getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - BaseClassDecl)) + BaseClassDecl)) { + CheckDirectMemberAccess(Base->getSourceRange().getBegin(), + BaseAssignOpMethod, + PartialDiagnostic(diag::err_access_assign_base) + << Base->getType()); + MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); + } } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { @@ -3872,8 +3881,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (CXXMethodDecl *FieldAssignOpMethod = getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - FieldClassDecl)) + FieldClassDecl)) { + CheckDirectMemberAccess(Field->getLocation(), + FieldAssignOpMethod, + PartialDiagnostic(diag::err_access_assign_field) + << Field->getDeclName() << Field->getType()); + MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); + } } else if (FieldType->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); @@ -3948,8 +3963,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(Context, TypeQuals)) + BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { + CheckDirectMemberAccess(Base->getSourceRange().getBegin(), + BaseCopyCtor, + PartialDiagnostic(diag::err_access_copy_base) + << Base->getType()); + MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); + } } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); @@ -3961,8 +3982,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (CXXConstructorDecl *FieldCopyCtor = - FieldClassDecl->getCopyConstructor(Context, TypeQuals)) + FieldClassDecl->getCopyConstructor(Context, TypeQuals)) { + CheckDirectMemberAccess(Field->getLocation(), + FieldCopyCtor, + PartialDiagnostic(diag::err_access_copy_field) + << Field->getDeclName() << Field->getType()); + MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); + } } } CopyConstructor->setUsed(); @@ -4052,7 +4079,10 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { !ClassDecl->hasTrivialDestructor()) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); - CheckDestructorAccess(VD->getLocation(), Record); + CheckDestructorAccess(VD->getLocation(), Destructor, + PartialDiagnostic(diag::err_access_dtor_var) + << VD->getDeclName() + << VD->getType()); } } @@ -5715,7 +5745,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // Check if we the conversion from derived to base is valid. - if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance, + if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, + diag::err_covariant_return_inaccessible_base, diag::err_covariant_return_ambiguous_derived_to_base_conv, // FIXME: Should this point to the return type? New->getLocation(), SourceRange(), New->getDeclName())) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 762ef38..b2f6717 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -20,25 +20,6 @@ #include "clang/Parse/DeclSpec.h" using namespace clang; -bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, - ObjCMethodDecl *GetterMethod, - SourceLocation Loc) { - if (GetterMethod && - GetterMethod->getResultType() != property->getType()) { - AssignConvertType result = Incompatible; - if (property->getType()->isObjCObjectPointerType()) - result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType()); - if (result != Compatible) { - Diag(Loc, diag::warn_accessor_property_type_mismatch) - << property->getDeclName() - << GetterMethod->getSelector(); - Diag(GetterMethod->getLocation(), diag::note_declared_at); - return true; - } - } - return false; -} - /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { @@ -361,171 +342,6 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, } } -/// DiagnosePropertyMismatch - Compares two properties for their -/// attributes and types and warns on a variety of inconsistencies. -/// -void -Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, - ObjCPropertyDecl *SuperProperty, - const IdentifierInfo *inheritedName) { - ObjCPropertyDecl::PropertyAttributeKind CAttr = - Property->getPropertyAttributes(); - ObjCPropertyDecl::PropertyAttributeKind SAttr = - SuperProperty->getPropertyAttributes(); - if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) - && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) - Diag(Property->getLocation(), diag::warn_readonly_property) - << Property->getDeclName() << inheritedName; - if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) - != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "copy" << inheritedName; - else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) - != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "retain" << inheritedName; - - if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) - != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "atomic" << inheritedName; - if (Property->getSetterName() != SuperProperty->getSetterName()) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "setter" << inheritedName; - if (Property->getGetterName() != SuperProperty->getGetterName()) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "getter" << inheritedName; - - QualType LHSType = - Context.getCanonicalType(SuperProperty->getType()); - QualType RHSType = - Context.getCanonicalType(Property->getType()); - - if (!Context.typesAreCompatible(LHSType, RHSType)) { - // FIXME: Incorporate this test with typesAreCompatible. - if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) - if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) - return; - Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) - << Property->getType() << SuperProperty->getType() << inheritedName; - } -} - -/// ComparePropertiesInBaseAndSuper - This routine compares property -/// declarations in base and its super class, if any, and issues -/// diagnostics in a variety of inconsistant situations. -/// -void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { - ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); - if (!SDecl) - return; - // FIXME: O(N^2) - for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(), - E = SDecl->prop_end(); S != E; ++S) { - ObjCPropertyDecl *SuperPDecl = (*S); - // Does property in super class has declaration in current class? - for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(), - E = IDecl->prop_end(); I != E; ++I) { - ObjCPropertyDecl *PDecl = (*I); - if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) - DiagnosePropertyMismatch(PDecl, SuperPDecl, - SDecl->getIdentifier()); - } - } -} - -/// MatchOneProtocolPropertiesInClass - This routine goes thru the list -/// of properties declared in a protocol and compares their attribute against -/// the same property declared in the class or category. -void -Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, - ObjCProtocolDecl *PDecl) { - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); - if (!IDecl) { - // Category - ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "MatchOneProtocolPropertiesInClass"); - if (!CatDecl->IsClassExtension()) - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = (*P); - ObjCCategoryDecl::prop_iterator CP, CE; - // Is this property already in category's list of properties? - for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) - if ((*CP)->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); - } - return; - } - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = (*P); - ObjCInterfaceDecl::prop_iterator CP, CE; - // Is this property already in class's list of properties? - for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP) - if ((*CP)->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); - } -} - -/// CompareProperties - This routine compares properties -/// declared in 'ClassOrProtocol' objects (which can be a class or an -/// inherited protocol with the list of properties for class/category 'CDecl' -/// -void Sema::CompareProperties(Decl *CDecl, - DeclPtrTy ClassOrProtocol) { - Decl *ClassDecl = ClassOrProtocol.getAs<Decl>(); - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); - - if (!IDecl) { - // Category - ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "CompareProperties"); - if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { - for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), - E = MDecl->protocol_end(); P != E; ++P) - // Match properties of category with those of protocol (*P) - MatchOneProtocolPropertiesInClass(CatDecl, *P); - - // Go thru the list of protocols for this category and recursively match - // their properties with those in the category. - for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), - E = CatDecl->protocol_end(); P != E; ++P) - CompareProperties(CatDecl, DeclPtrTy::make(*P)); - } else { - ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); - for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), - E = MD->protocol_end(); P != E; ++P) - MatchOneProtocolPropertiesInClass(CatDecl, *P); - } - return; - } - - if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { - for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), - E = MDecl->protocol_end(); P != E; ++P) - // Match properties of class IDecl with those of protocol (*P). - MatchOneProtocolPropertiesInClass(IDecl, *P); - - // Go thru the list of protocols for this class and recursively match - // their properties with those declared in the class. - for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), - E = IDecl->protocol_end(); P != E; ++P) - CompareProperties(IDecl, DeclPtrTy::make(*P)); - } else { - ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); - for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), - E = MD->protocol_end(); P != E; ++P) - MatchOneProtocolPropertiesInClass(IDecl, *P); - } -} - /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// @@ -941,57 +757,6 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, } } -/// isPropertyReadonly - Return true if property is readonly, by searching -/// for the property in the class and in its categories and implementations -/// -bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, - ObjCInterfaceDecl *IDecl) { - // by far the most common case. - if (!PDecl->isReadOnly()) - return false; - // Even if property is ready only, if interface has a user defined setter, - // it is not considered read only. - if (IDecl->getInstanceMethod(PDecl->getSetterName())) - return false; - - // Main class has the property as 'readonly'. Must search - // through the category list to see if the property's - // attribute has been over-ridden to 'readwrite'. - for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); - Category; Category = Category->getNextClassCategory()) { - // Even if property is ready only, if a category has a user defined setter, - // it is not considered read only. - if (Category->getInstanceMethod(PDecl->getSetterName())) - return false; - ObjCPropertyDecl *P = - Category->FindPropertyDeclaration(PDecl->getIdentifier()); - if (P && !P->isReadOnly()) - return false; - } - - // Also, check for definition of a setter method in the implementation if - // all else failed. - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) { - if (ObjCImplementationDecl *IMD = - dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) { - if (IMD->getInstanceMethod(PDecl->getSetterName())) - return false; - } else if (ObjCCategoryImplDecl *CIMD = - dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { - if (CIMD->getInstanceMethod(PDecl->getSetterName())) - return false; - } - } - // Lastly, look through the implementation (if one is in scope). - if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation()) - if (ImpDecl->getInstanceMethod(PDecl->getSetterName())) - return false; - // If all fails, look at the super class. - if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass()) - return isPropertyReadonly(PDecl, SIDecl); - return true; -} - /// FIXME: Type hierarchies in Objective-C can be deep. We could most likely /// improve the efficiency of selector lookups and type checking by associating /// with each protocol / interface / category the flattened instance tables. If @@ -1131,140 +896,6 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } -/// CollectImmediateProperties - This routine collects all properties in -/// the class and its conforming protocols; but not those it its super class. -void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), - E = IDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); - } - if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { - if (!CATDecl->IsClassExtension()) - for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), - E = CATDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), - E = CATDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); - } - else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; - if (!PropEntry) - PropEntry = Prop; - } - // scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); - } -} - -/// LookupPropertyDecl - Looks up a property in the current class and all -/// its protocols. -ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, - IdentifierInfo *II) { - if (const ObjCInterfaceDecl *IDecl = - dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), - E = IDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->getIdentifier() == II) - return Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) { - ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); - if (Prop) - return Prop; - } - } - else if (const ObjCProtocolDecl *PDecl = - dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->getIdentifier() == II) - return Prop; - } - // scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) { - ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); - if (Prop) - return Prop; - } - } - return 0; -} - - -void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - const llvm::DenseSet<Selector>& InsMap) { - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; - CollectImmediateProperties(CDecl, PropMap); - if (PropMap.empty()) - return; - - llvm::DenseSet<ObjCPropertyDecl *> PropImplMap; - for (ObjCImplDecl::propimpl_iterator - I = IMPDecl->propimpl_begin(), - EI = IMPDecl->propimpl_end(); I != EI; ++I) - PropImplMap.insert((*I)->getPropertyDecl()); - - for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator - P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { - ObjCPropertyDecl *Prop = P->second; - // Is there a matching propery synthesize/dynamic? - if (Prop->isInvalidDecl() || - Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || - PropImplMap.count(Prop)) - continue; - if (LangOpts.ObjCNonFragileABI2) { - ActOnPropertyImplDecl(IMPDecl->getLocation(), - SourceLocation(), - true, DeclPtrTy::make(IMPDecl), - Prop->getIdentifier(), - Prop->getIdentifier()); - continue; - } - if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), - isa<ObjCCategoryDecl>(CDecl) ? - diag::warn_setter_getter_impl_required_in_category : - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getGetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - - if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), - isa<ObjCCategoryDecl>(CDecl) ? - diag::warn_setter_getter_impl_required_in_category : - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - } -} - void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -1336,41 +967,6 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, assert(false && "invalid ObjCContainerDecl type."); } -void -Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, - ObjCContainerDecl* IDecl) { - // Rules apply in non-GC mode only - if (getLangOptions().getGCMode() != LangOptions::NonGC) - return; - for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), - E = IDecl->prop_end(); - I != E; ++I) { - ObjCPropertyDecl *Property = (*I); - unsigned Attributes = Property->getPropertyAttributes(); - // We only care about readwrite atomic property. - if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || - !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) - continue; - if (const ObjCPropertyImplDecl *PIDecl - = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - ObjCMethodDecl *GetterMethod = - IMPDecl->getInstanceMethod(Property->getGetterName()); - ObjCMethodDecl *SetterMethod = - IMPDecl->getInstanceMethod(Property->getSetterName()); - if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { - SourceLocation MethodLoc = - (GetterMethod ? GetterMethod->getLocation() - : SetterMethod->getLocation()); - Diag(MethodLoc, diag::warn_atomic_property_rule) - << Property->getIdentifier(); - Diag(Property->getLocation(), diag::note_property_declare); - } - } - } -} - /// ActOnForwardClassDeclaration - Action::DeclPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, @@ -1638,111 +1234,6 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, return MethList.Method; } -/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods -/// have the property type and issue diagnostics if they don't. -/// Also synthesize a getter/setter method if none exist (and update the -/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized -/// methods is the "right" thing to do. -void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, - ObjCContainerDecl *CD) { - ObjCMethodDecl *GetterMethod, *SetterMethod; - - GetterMethod = CD->getInstanceMethod(property->getGetterName()); - SetterMethod = CD->getInstanceMethod(property->getSetterName()); - DiagnosePropertyAccessorMismatch(property, GetterMethod, - property->getLocation()); - - if (SetterMethod) { - ObjCPropertyDecl::PropertyAttributeKind CAttr = - property->getPropertyAttributes(); - if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) && - Context.getCanonicalType(SetterMethod->getResultType()) != - Context.VoidTy) - Diag(SetterMethod->getLocation(), diag::err_setter_type_void); - if (SetterMethod->param_size() != 1 || - ((*SetterMethod->param_begin())->getType() != property->getType())) { - Diag(property->getLocation(), - diag::warn_accessor_property_type_mismatch) - << property->getDeclName() - << SetterMethod->getSelector(); - Diag(SetterMethod->getLocation(), diag::note_declared_at); - } - } - - // Synthesize getter/setter methods if none exist. - // Find the default getter and if one not found, add one. - // FIXME: The synthesized property we set here is misleading. We almost always - // synthesize these methods unless the user explicitly provided prototypes - // (which is odd, but allowed). Sema should be typechecking that the - // declarations jive in that situation (which it is not currently). - if (!GetterMethod) { - // No instance method of same name as property getter name was found. - // Declare a getter method and add it to the list of methods - // for this class. - GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), - property->getLocation(), property->getGetterName(), - property->getType(), 0, CD, true, false, true, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); - CD->addDecl(GetterMethod); - } else - // A user declared getter will be synthesize when @synthesize of - // the property with the same name is seen in the @implementation - GetterMethod->setSynthesized(true); - property->setGetterMethodDecl(GetterMethod); - - // Skip setter if property is read-only. - if (!property->isReadOnly()) { - // Find the default setter and if one not found, add one. - if (!SetterMethod) { - // No instance method of same name as property setter name was found. - // Declare a setter method and add it to the list of methods - // for this class. - SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), - property->getLocation(), - property->getSetterName(), - Context.VoidTy, 0, CD, true, false, true, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); - // Invent the arguments for the setter. We don't bother making a - // nice name for the argument. - ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, - property->getLocation(), - property->getIdentifier(), - property->getType(), - /*TInfo=*/0, - VarDecl::None, - 0); - SetterMethod->setMethodParams(Context, &Argument, 1); - CD->addDecl(SetterMethod); - } else - // A user declared setter will be synthesize when @synthesize of - // the property with the same name is seen in the @implementation - SetterMethod->setSynthesized(true); - property->setSetterMethodDecl(SetterMethod); - } - // Add any synthesized methods to the global pool. This allows us to - // handle the following, which is supported by GCC (and part of the design). - // - // @interface Foo - // @property double bar; - // @end - // - // void thisIsUnfortunate() { - // id foo; - // double bar = [foo bar]; - // } - // - if (GetterMethod) - AddInstanceMethodToGlobalPool(GetterMethod); - if (SetterMethod) - AddInstanceMethodToGlobalPool(SetterMethod); -} - /// CompareMethodParamsInBaseAndSuper - This routine compares methods with /// identical selector names in current and its super classes and issues /// a warning if any of their argument types are incompatible. @@ -2106,501 +1597,6 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( return DeclPtrTy::make(ObjCMethod); } -void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, - SourceLocation Loc, - unsigned &Attributes) { - // FIXME: Improve the reported location. - - // readonly and readwrite/assign/retain/copy conflict. - if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | - ObjCDeclSpec::DQ_PR_assign | - ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain))) { - const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ? - "readwrite" : - (Attributes & ObjCDeclSpec::DQ_PR_assign) ? - "assign" : - (Attributes & ObjCDeclSpec::DQ_PR_copy) ? - "copy" : "retain"; - - Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? - diag::err_objc_property_attr_mutually_exclusive : - diag::warn_objc_property_attr_mutually_exclusive) - << "readonly" << which; - } - - // Check for copy or retain on non-object types. - if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && - !PropertyTy->isObjCObjectPointerType() && - !PropertyTy->isBlockPointerType() && - !Context.isObjCNSObjectType(PropertyTy)) { - Diag(Loc, diag::err_objc_property_requires_object) - << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); - Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); - } - - // Check for more than one of { assign, copy, retain }. - if (Attributes & ObjCDeclSpec::DQ_PR_assign) { - if (Attributes & ObjCDeclSpec::DQ_PR_copy) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "assign" << "copy"; - Attributes &= ~ObjCDeclSpec::DQ_PR_copy; - } - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "assign" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; - } - } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "copy" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; - } - } - - // Warn if user supplied no assignment attribute, property is - // readwrite, and this is an object type. - if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain)) && - !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && - PropertyTy->isObjCObjectPointerType()) { - // Skip this warning in gc-only mode. - if (getLangOptions().getGCMode() != LangOptions::GCOnly) - Diag(Loc, diag::warn_objc_property_no_assignment_attribute); - - // If non-gc code warn that this is likely inappropriate. - if (getLangOptions().getGCMode() == LangOptions::NonGC) - Diag(Loc, diag::warn_objc_property_default_assign_on_object); - - // FIXME: Implement warning dependent on NSCopying being - // implemented. See also: - // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496> - // (please trim this list while you are at it). - } - - if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) - && getLangOptions().getGCMode() == LangOptions::GCOnly - && PropertyTy->isBlockPointerType()) - Diag(Loc, diag::warn_objc_property_copy_missing_on_block); -} - -Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, - FieldDeclarator &FD, - ObjCDeclSpec &ODS, - Selector GetterSel, - Selector SetterSel, - DeclPtrTy ClassCategory, - bool *isOverridingProperty, - tok::ObjCKeywordKind MethodImplKind) { - unsigned Attributes = ODS.getPropertyAttributes(); - bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || - // default is readwrite! - !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); - // property is defaulted to 'assign' if it is readwrite and is - // not retain or copy - bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || - (isReadWrite && - !(Attributes & ObjCDeclSpec::DQ_PR_retain) && - !(Attributes & ObjCDeclSpec::DQ_PR_copy))); - QualType T = GetTypeForDeclarator(FD.D, S); - if (T->isReferenceType()) { - Diag(AtLoc, diag::error_reference_property); - return DeclPtrTy(); - } - Decl *ClassDecl = ClassCategory.getAs<Decl>(); - ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class - // May modify Attributes. - CheckObjCPropertyAttributes(T, AtLoc, Attributes); - if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) - if (CDecl->IsClassExtension()) { - // Diagnose if this property is already in continuation class. - DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier()); - if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { - Diag(AtLoc, diag::err_duplicate_property); - Diag((*Found.first)->getLocation(), diag::note_property_declare); - return DeclPtrTy(); - } - ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, - FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), - AtLoc, T); - DC->addDecl(PDecl); - - // This is a continuation class. property requires special - // handling. - if ((CCPrimary = CDecl->getClassInterface())) { - // Find the property in continuation class's primary class only. - IdentifierInfo *PropertyId = FD.D.getIdentifier(); - if (ObjCPropertyDecl *PIDecl = - CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) { - // property 'PIDecl's readonly attribute will be over-ridden - // with continuation class's readwrite property attribute! - unsigned PIkind = PIDecl->getPropertyAttributes(); - if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - unsigned retainCopyNonatomic = - (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_nonatomic); - if ((Attributes & retainCopyNonatomic) != - (PIkind & retainCopyNonatomic)) { - Diag(AtLoc, diag::warn_property_attr_mismatch); - Diag(PIDecl->getLocation(), diag::note_property_declare); - } - DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = - DC->lookup(PIDecl->getDeclName()); - bool PropertyInPrimaryClass = false; - for (; Found.first != Found.second; ++Found.first) - if (isa<ObjCPropertyDecl>(*Found.first)) { - PropertyInPrimaryClass = true; - break; - } - if (!PropertyInPrimaryClass) { - // Protocol is not in the primary class. Must build one for it. - ObjCDeclSpec ProtocolPropertyODS; - // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and - // ObjCPropertyDecl::PropertyAttributeKind have identical values. - // Should consolidate both into one enum type. - ProtocolPropertyODS.setPropertyAttributes( - (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind); - DeclPtrTy ProtocolPtrTy = - ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, - PIDecl->getGetterName(), - PIDecl->getSetterName(), - DeclPtrTy::make(CCPrimary), isOverridingProperty, - MethodImplKind); - PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>(); - } - PIDecl->makeitReadWriteAttribute(); - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - PIDecl->setSetterName(SetterSel); - } else { - Diag(AtLoc, diag::err_use_continuation_class) - << CCPrimary->getDeclName(); - Diag(PIDecl->getLocation(), diag::note_property_declare); - } - *isOverridingProperty = true; - // Make sure setter decl is synthesized, and added to primary - // class's list. - ProcessPropertyDecl(PIDecl, CCPrimary); - return DeclPtrTy(); - } - - // No matching property found in the primary class. Just fall thru - // and add property to continuation class's primary class. - ClassDecl = CCPrimary; - } else { - Diag(CDecl->getLocation(), diag::err_continuation_class); - *isOverridingProperty = true; - return DeclPtrTy(); - } - } - - // Issue a warning if property is 'assign' as default and its object, which is - // gc'able conforms to NSCopying protocol - if (getLangOptions().getGCMode() != LangOptions::NonGC && - isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) - if (T->isObjCObjectPointerType()) { - QualType InterfaceTy = T->getPointeeType(); - if (const ObjCInterfaceType *OIT = - InterfaceTy->getAs<ObjCInterfaceType>()) { - ObjCInterfaceDecl *IDecl = OIT->getDecl(); - if (IDecl) - if (ObjCProtocolDecl* PNSCopying = - LookupProtocol(&Context.Idents.get("NSCopying"))) - if (IDecl->ClassImplementsProtocol(PNSCopying, true)) - Diag(AtLoc, diag::warn_implements_nscopying) - << FD.D.getIdentifier(); - } - } - if (T->isObjCInterfaceType()) - Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); - - DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); - assert(DC && "ClassDecl is not a DeclContext"); - ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, - FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), - AtLoc, T); - DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName()); - if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { - Diag(PDecl->getLocation(), diag::err_duplicate_property); - Diag((*Found.first)->getLocation(), diag::note_property_declare); - PDecl->setInvalidDecl(); - } - else - DC->addDecl(PDecl); - - if (T->isArrayType() || T->isFunctionType()) { - Diag(AtLoc, diag::err_property_type) << T; - PDecl->setInvalidDecl(); - } - - ProcessDeclAttributes(S, PDecl, FD.D); - - // Regardless of setter/getter attribute, we save the default getter/setter - // selector names in anticipation of declaration of setter/getter methods. - PDecl->setGetterName(GetterSel); - PDecl->setSetterName(SetterSel); - - if (Attributes & ObjCDeclSpec::DQ_PR_readonly) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); - - if (Attributes & ObjCDeclSpec::DQ_PR_getter) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); - - if (Attributes & ObjCDeclSpec::DQ_PR_setter) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); - - if (isReadWrite) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); - - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - - if (isAssign) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); - - if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - - if (MethodImplKind == tok::objc_required) - PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); - else if (MethodImplKind == tok::objc_optional) - PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); - // A case of continuation class adding a new property in the class. This - // is not what it was meant for. However, gcc supports it and so should we. - // Make sure setter/getters are declared here. - if (CCPrimary) - ProcessPropertyDecl(PDecl, CCPrimary); - - return DeclPtrTy::make(PDecl); -} - -ObjCIvarDecl* -Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, - IdentifierInfo *NameII) { - ObjCIvarDecl *Ivar = 0; - ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); - if (Prop && !Prop->isInvalidDecl()) { - DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); - QualType PropType = Context.getCanonicalType(Prop->getType()); - assert(EnclosingContext && - "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar"); - Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, - Prop->getLocation(), - NameII, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, - (Expr *)0); - Ivar->setLexicalDeclContext(IDecl); - IDecl->addDecl(Ivar); - Prop->setPropertyIvarDecl(Ivar); - } - return Ivar; -} - -/// ActOnPropertyImplDecl - This routine performs semantic checks and -/// builds the AST node for a property implementation declaration; declared -/// as @synthesize or @dynamic. -/// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, - SourceLocation PropertyLoc, - bool Synthesize, - DeclPtrTy ClassCatImpDecl, - IdentifierInfo *PropertyId, - IdentifierInfo *PropertyIvar) { - Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>(); - // Make sure we have a context for the property implementation declaration. - if (!ClassImpDecl) { - Diag(AtLoc, diag::error_missing_property_context); - return DeclPtrTy(); - } - ObjCPropertyDecl *property = 0; - ObjCInterfaceDecl* IDecl = 0; - // Find the class or category class where this property must have - // a declaration. - ObjCImplementationDecl *IC = 0; - ObjCCategoryImplDecl* CatImplClass = 0; - if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) { - IDecl = IC->getClassInterface(); - // We always synthesize an interface for an implementation - // without an interface decl. So, IDecl is always non-zero. - assert(IDecl && - "ActOnPropertyImplDecl - @implementation without @interface"); - - // Look for this property declaration in the @implementation's @interface - property = IDecl->FindPropertyDeclaration(PropertyId); - if (!property) { - Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); - return DeclPtrTy(); - } - if (const ObjCCategoryDecl *CD = - dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { - if (!CD->IsClassExtension()) { - Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); - Diag(property->getLocation(), diag::note_property_declare); - return DeclPtrTy(); - } - } - } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { - if (Synthesize) { - Diag(AtLoc, diag::error_synthesize_category_decl); - return DeclPtrTy(); - } - IDecl = CatImplClass->getClassInterface(); - if (!IDecl) { - Diag(AtLoc, diag::error_missing_property_interface); - return DeclPtrTy(); - } - ObjCCategoryDecl *Category = - IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); - - // If category for this implementation not found, it is an error which - // has already been reported eralier. - if (!Category) - return DeclPtrTy(); - // Look for this property declaration in @implementation's category - property = Category->FindPropertyDeclaration(PropertyId); - if (!property) { - Diag(PropertyLoc, diag::error_bad_category_property_decl) - << Category->getDeclName(); - return DeclPtrTy(); - } - } else { - Diag(AtLoc, diag::error_bad_property_context); - return DeclPtrTy(); - } - ObjCIvarDecl *Ivar = 0; - // Check that we have a valid, previously declared ivar for @synthesize - if (Synthesize) { - // @synthesize - if (!PropertyIvar) - PropertyIvar = PropertyId; - QualType PropType = Context.getCanonicalType(property->getType()); - // Check that this is a previously declared 'ivar' in 'IDecl' interface - ObjCInterfaceDecl *ClassDeclared; - Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); - if (!Ivar) { - DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); - assert(EnclosingContext && - "null DeclContext for synthesized ivar - ActOnPropertyImplDecl"); - Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc, - PropertyIvar, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, - (Expr *)0); - IDecl->makeDeclVisibleInContext(Ivar, false); - property->setPropertyIvarDecl(Ivar); - if (!getLangOptions().ObjCNonFragileABI) - Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; - // Note! I deliberately want it to fall thru so, we have a - // a property implementation and to avoid future warnings. - } else if (getLangOptions().ObjCNonFragileABI && - ClassDeclared != IDecl) { - Diag(PropertyLoc, diag::error_ivar_in_superclass_use) - << property->getDeclName() << Ivar->getDeclName() - << ClassDeclared->getDeclName(); - Diag(Ivar->getLocation(), diag::note_previous_access_declaration) - << Ivar << Ivar->getNameAsCString(); - // Note! I deliberately want it to fall thru so more errors are caught. - } - QualType IvarType = Context.getCanonicalType(Ivar->getType()); - - // Check that type of property and its ivar are type compatible. - if (PropType != IvarType) { - if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { - Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); - // Note! I deliberately want it to fall thru so, we have a - // a property implementation and to avoid future warnings. - } - - // FIXME! Rules for properties are somewhat different that those - // for assignments. Use a new routine to consolidate all cases; - // specifically for property redeclarations as well as for ivars. - QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); - QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); - if (lhsType != rhsType && - lhsType->isArithmeticType()) { - Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment - } - // __weak is explicit. So it works on Canonical type. - if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { - Diag(PropertyLoc, diag::error_weak_property) - << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment - } - if ((property->getType()->isObjCObjectPointerType() || - PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { - Diag(PropertyLoc, diag::error_strong_property) - << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment - } - } - } else if (PropertyIvar) - // @dynamic - Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); - assert (property && "ActOnPropertyImplDecl - property declaration missing"); - ObjCPropertyImplDecl *PIDecl = - ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, - property, - (Synthesize ? - ObjCPropertyImplDecl::Synthesize - : ObjCPropertyImplDecl::Dynamic), - Ivar); - if (IC) { - if (Synthesize) - if (ObjCPropertyImplDecl *PPIDecl = - IC->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) - << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() - << PropertyIvar; - Diag(PPIDecl->getLocation(), diag::note_previous_use); - } - - if (ObjCPropertyImplDecl *PPIDecl - = IC->FindPropertyImplDecl(PropertyId)) { - Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; - Diag(PPIDecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); - } - IC->addPropertyImplementation(PIDecl); - } else { - if (Synthesize) - if (ObjCPropertyImplDecl *PPIDecl = - CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) - << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() - << PropertyIvar; - Diag(PPIDecl->getLocation(), diag::note_previous_use); - } - - if (ObjCPropertyImplDecl *PPIDecl = - CatImplClass->FindPropertyImplDecl(PropertyId)) { - Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; - Diag(PPIDecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); - } - CatImplClass->addPropertyImplementation(PIDecl); - } - - return DeclPtrTy::make(PIDecl); -} - bool Sema::CheckObjCDeclScope(Decl *D) { if (isa<TranslationUnitDecl>(CurContext->getLookupContext())) return false; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 9be411b..4ce1ce9 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -294,12 +294,12 @@ bool Sema::CheckExceptionSpecSubset( continue; // Do this check from a context without privileges. - switch (CheckBaseClassAccess(SourceLocation(), false, + switch (CheckBaseClassAccess(SourceLocation(), CanonicalSuperT, CanonicalSubT, Paths.front(), + /*Diagnostic*/ 0, /*ForceCheck*/ true, - /*ForceUnprivileged*/ true, - ADK_quiet)) { + /*ForceUnprivileged*/ true)) { case AR_accessible: break; case AR_inaccessible: continue; case AR_dependent: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2249579..a39ba2f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -58,7 +58,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { Diag(Loc, diag::warn_unavailable) << D->getDeclName(); Diag(D->getLocation(), diag::note_unavailable_here) << 0; } - + // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { @@ -202,7 +202,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { DefaultFunctionArrayConversion(E); - + QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type"); if (!Ty->isDependentType() && Ty.hasQualifiers() && @@ -214,8 +214,8 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { // rvalue is T // // C99 6.3.2.1p2: - // If the lvalue has qualified type, the value has the unqualified - // version of the type of the lvalue; otherwise, the value has the + // If the lvalue has qualified type, the value has the unqualified + // version of the type of the lvalue; otherwise, the value has the // type of the lvalue. ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp); } @@ -289,7 +289,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { return true; if (!Expr->getType()->isPODType() && - DiagRuntimeBehavior(Expr->getLocStart(), + DiagRuntimeBehavior(Expr->getLocStart(), PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) << Expr->getType() << CT)) return true; @@ -370,7 +370,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { if (Literal.Pascal) StrTy = Context.UnsignedCharTy; // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings ) StrTy.addConst(); // Get an array type for the string, according to C99 6.4.5. This includes @@ -423,10 +423,10 @@ static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock, // all get the bit). Walk the nesting chain. for (unsigned I = S.FunctionScopes.size() - 1; I; --I) { BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]); - + if (!NextBlock) continue; - + // If we found the defining block for the variable, don't mark the block as // having a reference outside it. if (NextBlock->TheDecl == VD->getDeclContext()) @@ -469,9 +469,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, MarkDeclarationReferenced(Loc, D); - return Owned(DeclRefExpr::Create(Context, - SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, - SS? SS->getRange() : SourceRange(), + return Owned(DeclRefExpr::Create(Context, + SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, + SS? SS->getRange() : SourceRange(), D, Loc, Ty)); } @@ -768,14 +768,14 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef, return true; } - + /// Determines if this is an instance member of a class. static bool IsInstanceMember(NamedDecl *D) { assert(D->isCXXClassMember() && "checking whether non-member is instance member"); if (isa<FieldDecl>(D)) return true; - + if (isa<CXXMethodDecl>(D)) return !cast<CXXMethodDecl>(D)->isStatic(); @@ -971,7 +971,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); - else + else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << R.getLookupName() << SS.getRange() @@ -980,7 +980,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); - + // Tell the callee to try to recover. return false; } @@ -993,7 +993,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, // to recover well anyway. if (SS.isEmpty()) Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); - else + else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << R.getLookupName() << SS.getRange(); @@ -1107,7 +1107,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to - // reference the ivar. + // reference the ivar. if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) { R.clear(); OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); @@ -1303,7 +1303,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, // turn this into Self->ivar, just return a BareIVarExpr or something. IdentifierInfo &II = Context.Idents.get("self"); UnqualifiedId SelfName; - SelfName.setIdentifier(&II, SourceLocation()); + SelfName.setIdentifier(&II, SourceLocation()); CXXScopeSpec SelfScopeSpec; OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, SelfName, false, false); @@ -1326,7 +1326,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, // Needed to implement property "super.method" notation. if (Lookup.empty() && II->isStr("super")) { QualType T; - + if (getCurMethodDecl()->isInstanceMethod()) T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( getCurMethodDecl()->getClassInterface())); @@ -1363,7 +1363,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); if (!RD) return false; - + QualType DestRecordType; QualType DestType; QualType FromRecordType; @@ -1371,7 +1371,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, bool PointerConversions = false; if (isa<FieldDecl>(Member)) { DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD)); - + if (FromType->getAs<PointerType>()) { DestType = Context.getPointerType(DestRecordType); FromRecordType = FromType->getPointeeType(); @@ -1383,10 +1383,10 @@ Sema::PerformObjectMemberConversion(Expr *&From, } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) { if (Method->isStatic()) return false; - + DestType = Method->getThisType(Context); DestRecordType = DestType->getPointeeType(); - + if (FromType->getAs<PointerType>()) { FromRecordType = FromType->getPointeeType(); PointerConversions = true; @@ -1398,16 +1398,16 @@ Sema::PerformObjectMemberConversion(Expr *&From, // No conversion necessary. return false; } - + if (DestType->isDependentType() || FromType->isDependentType()) return false; - + // If the unqualified types are the same, no conversion is necessary. if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return false; - + // C++ [class.member.lookup]p8: - // [...] Ambiguities can often be resolved by qualifying a name with its + // [...] Ambiguities can often be resolved by qualifying a name with its // class name. // // If the member was a qualified name and the qualified referred to a @@ -1435,7 +1435,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, IntermediateType = Context.getPointerType(IntermediateType); } } - + if (!IntermediateType.isNull() && IsDerivedFrom(FromRecordType, IntermediateRecordType) && IsDerivedFrom(IntermediateRecordType, DestRecordType)) { @@ -1448,18 +1448,18 @@ Sema::PerformObjectMemberConversion(Expr *&From, return true; ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); + /*isLvalue=*/!PointerConversions); ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, /*isLvalue=*/!PointerConversions); return false; } - + if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, From->getSourceRange().getBegin(), From->getSourceRange())) return true; - + ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, /*isLvalue=*/true); return false; @@ -1633,7 +1633,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return Owned(ULE); } - + /// \brief Complete semantic analysis for a reference to the given declaration. Sema::OwningExprResult @@ -1658,7 +1658,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // Make sure that we're referring to a value. ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD) { - Diag(Loc, diag::err_ref_non_value) + Diag(Loc, diag::err_ref_non_value) << D << SS.getRange(); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); @@ -1683,7 +1683,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // We do not do this for things like enum constants, global variables, etc, // as they do not get snapshotted. // - if (getCurBlock() && + if (getCurBlock() && ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) { if (VD->getType().getTypePtr()->isVariablyModifiedType()) { Diag(Loc, diag::err_ref_vm_type); @@ -1819,7 +1819,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { if ((result & APFloat::opOverflow) || ((result & APFloat::opUnderflow) && Val.isZero())) { unsigned diagnostic; - llvm::SmallVector<char, 20> buffer; + llvm::SmallString<20> buffer; if (result & APFloat::opOverflow) { diagnostic = diag::warn_float_overflow; APFloat::getLargest(Format).toString(buffer); @@ -2531,7 +2531,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, } assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - + if (!isa<TypeDecl>(DC)) { SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) << DC << SS.getRange(); @@ -2548,7 +2548,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // 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) && + if (SemaRef.CorrectTypo(R, 0, &SS, DC) && (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) { SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << R.getLookupName() << SS.getRange() @@ -2685,7 +2685,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, return Owned(MemExpr); } - assert(R.isSingleResult()); + assert(R.isSingleResult()); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2831,13 +2831,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Diag(Loc, diag::err_member_reference_needs_call) << QualType(Fun, 0) << CodeModificationHint::CreateInsertion(Loc, "()"); - + OwningExprResult NewBase - = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, + = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, MultiExprArg(*this, 0, 0), 0, Loc); if (NewBase.isInvalid()) return ExprError(); - + BaseExpr = NewBase.takeAs<Expr>(); DefaultFunctionArrayConversion(BaseExpr); BaseType = BaseExpr->getType(); @@ -2907,20 +2907,20 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // 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; - + if (Getter) PType = Getter->getResultType(); else // Get the expression type from Setter's incoming parameter. PType = (*(Setter->param_end() -1))->getType(); // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } @@ -2928,7 +2928,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, << MemberName << BaseType); } } - + if (BaseType->isObjCClassType() && BaseType != Context.ObjCClassRedefinitionType) { BaseType = Context.ObjCClassRedefinitionType; @@ -2975,7 +2975,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } } } - + // Handle field access to simple records. This also handles access // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { @@ -3005,13 +3005,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, LookupMemberName); if (CorrectTypo(Res, 0, 0, IDecl) && (IV = Res.getAsSingle<ObjCIvarDecl>())) { - Diag(R.getNameLoc(), + Diag(R.getNameLoc(), diag::err_typecheck_member_reference_ivar_suggest) << IDecl->getDeclName() << MemberName << IV->getDeclName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), IV->getNameAsString()); Diag(IV->getLocation(), diag::note_previous_decl) - << IV->getDeclName(); + << IV->getDeclName(); } } @@ -3179,7 +3179,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Attempt to correct for typos in property names. LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), LookupOrdinaryName); - if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && + if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && Res.getAsSingle<ObjCPropertyDecl>()) { Diag(R.getNameLoc(), diag::err_property_not_found_suggest) << MemberName << BaseType << Res.getLookupName() @@ -3187,7 +3187,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Res.getLookupName().getAsString()); ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) - << Property->getDeclName(); + << Property->getDeclName(); return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl); @@ -3216,7 +3216,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member, MemberLoc)); } - + Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr->getSourceRange(); @@ -3341,11 +3341,11 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Expr *ResultE = Result.takeAs<Expr>(); InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); - Result = InitSeq.Perform(*this, Entity, Kind, + Result = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, (void**)&ResultE, 1)); if (Result.isInvalid()) return ExprError(); - + // Build the default argument expression. return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Result.takeAs<Expr>())); @@ -3380,7 +3380,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // assignment, to the types of the corresponding parameter, ... unsigned NumArgsInProto = Proto->getNumArgs(); bool Invalid = false; - + // If too few arguments are available (and we don't have default // arguments for the remaining parameters), don't make the call. if (NumArgs < NumArgsInProto) { @@ -3405,7 +3405,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, } } llvm::SmallVector<Expr *, 8> AllArgs; - VariadicCallType CallType = + VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; if (Fn->getType()->isBlockPointerType()) CallType = VariadicBlock; // Block @@ -3418,7 +3418,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, unsigned TotalNumArgs = AllArgs.size(); for (unsigned i = 0; i < TotalNumArgs; ++i) Call->setArg(i, AllArgs[i]); - + return false; } @@ -3439,23 +3439,23 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // Continue to check argument types (even if we have too few/many args). for (unsigned i = FirstProtoArg; i != NumArgsToCheck; i++) { QualType ProtoArgType = Proto->getArgType(i); - + Expr *Arg; if (ArgIx < NumArgs) { Arg = Args[ArgIx++]; - + if (RequireCompleteType(Arg->getSourceRange().getBegin(), ProtoArgType, PDiag(diag::err_call_incomplete_argument) << Arg->getSourceRange())) return true; - + // Pass the argument ParmVarDecl *Param = 0; if (FDecl && i < FDecl->getNumParams()) Param = FDecl->getParamDecl(i); - + InitializedEntity Entity = Param? InitializedEntity::InitializeParameter(Param) : InitializedEntity::InitializeParameter(ProtoArgType); @@ -3468,17 +3468,17 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, Arg = ArgE.takeAs<Expr>(); } else { ParmVarDecl *Param = FDecl->getParamDecl(i); - + OwningExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); if (ArgExpr.isInvalid()) return true; - + Arg = ArgExpr.takeAs<Expr>(); } AllArgs.push_back(Arg); } - + // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { // Promote the arguments (C99 6.5.2.2p7). @@ -3570,32 +3570,32 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc); } - + // Determine whether this is a call to a pointer-to-member function. if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) { if (BO->getOpcode() == BinaryOperator::PtrMemD || BO->getOpcode() == BinaryOperator::PtrMemI) { - if (const FunctionProtoType *FPT = + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(BO->getType())) { QualType ResultTy = FPT->getResultType().getNonReferenceType(); - - ExprOwningPtr<CXXMemberCallExpr> - TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, + + ExprOwningPtr<CXXMemberCallExpr> + TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, NumArgs, ResultTy, RParenLoc)); - - if (CheckCallReturnType(FPT->getResultType(), - BO->getRHS()->getSourceRange().getBegin(), + + if (CheckCallReturnType(FPT->getResultType(), + BO->getRHS()->getSourceRange().getBegin(), TheCall.get(), 0)) return ExprError(); - if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, + if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, RParenLoc)) return ExprError(); return Owned(MaybeBindToTemporary(TheCall.release()).release()); } - return ExprError(Diag(Fn->getLocStart(), + return ExprError(Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); } @@ -3661,7 +3661,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, << Fn->getType() << Fn->getSourceRange()); // Check for a valid return type - if (CheckCallReturnType(FuncT->getResultType(), + if (CheckCallReturnType(FuncT->getResultType(), Fn->getSourceRange().getBegin(), TheCall.get(), FDecl)) return ExprError(); @@ -3762,7 +3762,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, InitializedEntity Entity = InitializedEntity::InitializeTemporary(literalType); InitializationKind Kind - = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), + = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), /*IsCStyleCast=*/true); InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, @@ -3780,7 +3780,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, } Result.release(); - + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, literalExpr, isFileScope)); } @@ -3807,13 +3807,13 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, if (SrcTy->hasPointerRepresentation()) { if (DestTy->hasPointerRepresentation()) - return DestTy->isObjCObjectPointerType() ? - CastExpr::CK_AnyPointerToObjCPointerCast : + return DestTy->isObjCObjectPointerType() ? + CastExpr::CK_AnyPointerToObjCPointerCast : CastExpr::CK_BitCast; if (DestTy->isIntegerType()) return CastExpr::CK_PointerToIntegral; } - + if (SrcTy->isIntegerType()) { if (DestTy->isIntegerType()) return CastExpr::CK_IntegralCast; @@ -3822,14 +3822,14 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, if (DestTy->isRealFloatingType()) return CastExpr::CK_IntegralToFloating; } - + if (SrcTy->isRealFloatingType()) { if (DestTy->isRealFloatingType()) return CastExpr::CK_FloatingCast; if (DestTy->isIntegerType()) return CastExpr::CK_FloatingToIntegral; } - + // FIXME: Assert here. // assert(false && "Unhandled cast combination!"); return CastExpr::CK_Unknown; @@ -3853,7 +3853,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Kind = CastExpr::CK_ToVoid; return false; } - + if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && (castType->isStructureType() || castType->isUnionType())) { @@ -3864,14 +3864,14 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Kind = CastExpr::CK_NoOp; return false; } - + if (castType->isUnionType()) { // GCC cast to union extension RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator Field, FieldEnd; for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { - if (Context.hasSameUnqualifiedType(Field->getType(), + if (Context.hasSameUnqualifiedType(Field->getType(), castExpr->getType())) { Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) << castExpr->getSourceRange(); @@ -3884,22 +3884,22 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Kind = CastExpr::CK_ToUnion; return false; } - + // Reject any other conversions to non-scalar types. return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) << castType << castExpr->getSourceRange(); } - - if (!castExpr->getType()->isScalarType() && + + if (!castExpr->getType()->isScalarType() && !castExpr->getType()->isVectorType()) { return Diag(castExpr->getLocStart(), diag::err_typecheck_expect_scalar_operand) << castExpr->getType() << castExpr->getSourceRange(); } - - if (castType->isExtVectorType()) + + if (castType->isExtVectorType()) return CheckExtVectorCast(TyR, castType, castExpr, Kind); - + if (castType->isVectorType()) return CheckVectorCast(TyR, castType, castExpr->getType(), Kind); if (castExpr->getType()->isVectorType()) @@ -3907,10 +3907,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; - + if (isa<ObjCSelectorExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); - + if (!castType->isArithmeticType()) { QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType() && castExprType->isArithmeticType()) @@ -3948,12 +3948,12 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, return false; } -bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, +bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, CastExpr::CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); - + QualType SrcTy = CastExpr->getType(); - + // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. if (SrcTy->isVectorType()) { @@ -3975,7 +3975,7 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); ImpCastExprToType(CastExpr, DestElemTy, getScalarCastKind(Context, SrcTy, DestElemTy)); - + Kind = CastExpr::CK_VectorSplat; return false; } @@ -4105,7 +4105,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); - CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + CheckSignCompare(LHS, RHS, QuestionLoc); UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); @@ -4169,14 +4169,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); return RHSTy; } - + // All objective-c pointer type analysis is done here. QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!compositeType.isNull()) return compositeType; - - + + // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { @@ -4198,7 +4198,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The block pointer types aren't identical, continue checking. QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType(); QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType(); - + if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) @@ -4216,7 +4216,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } - + // Check constraints for C object pointers types (C99 6.5.15p3,6). if (LHSTy->isPointerType() && RHSTy->isPointerType()) { // get the "pointed to" types @@ -4300,7 +4300,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation QuestionLoc) { QualType LHSTy = LHS->getType(); QualType RHSTy = RHS->getType(); - + // Handle things like Class and struct objc_class*. Here we case the result // to the pseudo-builtin, because that will be implicitly cast back to the // redefinition type if an attempt is made to access its fields. @@ -4338,7 +4338,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, } // Check constraints for Objective-C object pointers types. if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { - + if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { // Two identical object pointer types are always compatible. return LHSTy; @@ -4346,7 +4346,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); QualType compositeType = LHSTy; - + // If both operands are interfaces and either operand can be // assigned to the other, use that type as the composite // type. This allows @@ -4357,7 +4357,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, // allow silent coercion. Finally, if the types are // incompatible then make sure to use 'id' as the composite // type so the result is acceptable for sending messages to. - + // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { @@ -4374,7 +4374,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); - } else if (!(compositeType = + } else if (!(compositeType = Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) ; else { @@ -4512,7 +4512,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { lhptee = Context.UnsignedCharTy; else if (lhptee->isSignedIntegerType()) lhptee = Context.getCorrespondingUnsignedType(lhptee); - + if (rhptee->isCharType()) rhptee = Context.UnsignedCharTy; else if (rhptee->isSignedIntegerType()) @@ -4526,7 +4526,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { return ConvTy; return IncompatiblePointerSign; } - + // If we are a multi-level pointer, it's possible that our issue is simply // one of qualification - e.g. char ** -> const char ** is not allowed. If // the eventual target type is the same and the pointers have the same @@ -4535,15 +4535,15 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { do { lhptee = lhptee->getAs<PointerType>()->getPointeeType(); rhptee = rhptee->getAs<PointerType>()->getPointeeType(); - + lhptee = Context.getCanonicalType(lhptee); rhptee = Context.getCanonicalType(rhptee); } while (lhptee->isPointerType() && rhptee->isPointerType()); - + if (Context.hasSameUnqualifiedType(lhptee, rhptee)) return IncompatibleNestedPointerQualifiers; } - + // General pointer incompatibility takes priority over qualifiers. return IncompatiblePointer; } @@ -4584,21 +4584,21 @@ Sema::AssignConvertType Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) return Compatible; - QualType lhptee = + QualType lhptee = lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = + QualType rhptee = rhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); // make sure we operate on the canonical type lhptee = Context.getCanonicalType(lhptee); rhptee = Context.getCanonicalType(rhptee); if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) return CompatiblePointerDiscardsQualifiers; - + if (Context.typesAreCompatible(lhsType, rhsType)) return Compatible; if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) return IncompatibleObjCQualifiedId; - return IncompatiblePointer; + return IncompatiblePointer; } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently @@ -4824,7 +4824,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { break; } - if (rExpr->isNullPointerConstant(Context, + if (rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer); InitField = *it; @@ -4868,7 +4868,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { if ((lhsType->isPointerType() || lhsType->isObjCObjectPointerType() || lhsType->isBlockPointerType()) - && rExpr->isNullPointerConstant(Context, + && rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown); return Compatible; @@ -4976,13 +4976,13 @@ QualType Sema::CheckMultiplyDivideOperands( if (!lex->getType()->isArithmeticType() || !rex->getType()->isArithmeticType()) return InvalidOperands(Loc, lex, rex); - + // Check for division by zero. if (isDiv && rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero) + DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero) << rex->getSourceRange()); - + return compType; } @@ -4998,12 +4998,12 @@ QualType Sema::CheckRemainderOperands( if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) return InvalidOperands(Loc, lex, rex); - + // Check for remainder by zero. if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero) << rex->getSourceRange()); - + return compType; } @@ -5282,8 +5282,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); - CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison, - (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE)); + CheckSignCompare(lex, rex, Loc, &Opc); // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) @@ -5320,13 +5319,13 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Expr *literalString = 0; Expr *literalStringStripped = 0; if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && - !RHSStripped->isNullPointerConstant(Context, + !RHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { literalString = lex; literalStringStripped = LHSStripped; } else if ((isa<StringLiteral>(RHSStripped) || isa<ObjCEncodeExpr>(RHSStripped)) && - !LHSStripped->isNullPointerConstant(Context, + !LHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { literalString = rex; literalStringStripped = RHSStripped; @@ -5343,7 +5342,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, case BinaryOperator::NE: resultComparison = ") != 0"; break; default: assert(false && "Invalid comparison operator"); } - + DiagRuntimeBehavior(Loc, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) @@ -5372,9 +5371,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } - bool LHSIsNull = lex->isNullPointerConstant(Context, + bool LHSIsNull = lex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); - bool RHSIsNull = rex->isNullPointerConstant(Context, + bool RHSIsNull = rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); // All of the following pointer related warnings are GCC extensions, except @@ -5417,9 +5416,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); } else if (NonStandardCompositeType) { - Diag(Loc, + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T + << lType << rType << T << lex->getSourceRange() << rex->getSourceRange(); } @@ -5490,9 +5489,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); } else if (NonStandardCompositeType) { - Diag(Loc, + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T + << lType << rType << T << lex->getSourceRange() << rex->getSourceRange(); } @@ -5678,10 +5677,10 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) return InvalidOperands(Loc, lex, rex); - + return Context.IntTy; } - + // C++ [expr.log.and]p1 // C++ [expr.log.or]p1 // The operands are both implicitly converted to type bool (clause 4). @@ -5693,16 +5692,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] if (PerformImplicitConversion(lex, Context.BoolTy, LHS, AA_Passing, /*IgnoreBaseAccess=*/false)) return InvalidOperands(Loc, lex, rex); - + StandardConversionSequence RHS; if (!IsStandardConversion(rex, Context.BoolTy, /*InOverloadResolution=*/false, RHS)) return InvalidOperands(Loc, lex, rex); - + if (PerformImplicitConversion(rex, Context.BoolTy, RHS, AA_Passing, /*IgnoreBaseAccess=*/false)) return InvalidOperands(Loc, lex, rex); - + // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 // The result is a bool. @@ -6342,10 +6341,10 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, Self.Diag(Loc, PD) << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); - + if (!SecondPD.getDiagID()) return; - + EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the @@ -6353,7 +6352,7 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, Self.Diag(Loc, SecondPD); return; } - + Self.Diag(Loc, SecondPD) << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); @@ -6443,12 +6442,12 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, if (S && OverOp != OO_None) LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), Functions); - + // Build the (potentially-overloaded, potentially-dependent) // binary operation. return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); } - + // Build a built-in binary operation. return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); } @@ -6556,10 +6555,10 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, if (S && OverOp != OO_None) LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), Functions); - + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); } - + return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); } @@ -6819,7 +6818,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); BlockScopeInfo *CurBlock = getCurBlock(); - + if (ParamInfo.getNumTypeObjects() == 0 || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) { ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); @@ -6986,13 +6985,13 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, PopFunctionOrBlockScope(); return ExprError(); } - + AnalysisContext AC(BSI->TheDecl); CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); CheckUnreachable(AC); Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs); - PopFunctionOrBlockScope(); + PopFunctionOrBlockScope(); return Owned(Result); } @@ -7049,14 +7048,14 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } -static void +static void MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, QualType DstType, Expr *SrcExpr, CodeModificationHint &Hint) { if (!SemaRef.getLangOptions().ObjC1) return; - + const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>(); if (!PT) return; @@ -7068,12 +7067,12 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, if (!ID || !ID->getIdentifier()->isStr("NSString")) return; } - + // Strip off any parens and casts. StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts()); if (!SL || SL->isWide()) return; - + Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@"); } @@ -7085,7 +7084,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, bool isInvalid = false; unsigned DiagKind; CodeModificationHint Hint; - + switch (ConvTy) { default: assert(0 && "Unknown conversion type"); case Compatible: return false; @@ -7202,7 +7201,7 @@ Sema::PopExpressionEvaluationContext() { // Mark any remaining declarations in the current position of the stack // as "referenced". If they were not meant to be referenced, semantic // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - for (PotentiallyReferencedDecls::iterator + for (PotentiallyReferencedDecls::iterator I = Rec.PotentiallyReferenced->begin(), IEnd = Rec.PotentiallyReferenced->end(); I != IEnd; ++I) @@ -7217,13 +7216,13 @@ Sema::PopExpressionEvaluationContext() { I != IEnd; ++I) Diag(I->first, I->second); } - } + } // When are coming out of an unevaluated context, clear out any // 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 && + if (Rec.Context == Unevaluated && ExprTemporaries.size() > Rec.NumTemporaries) ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries, ExprTemporaries.end()); @@ -7252,7 +7251,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // template or not. The reason for this is that unevaluated expressions // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and // -Wunused-parameters) - if (isa<ParmVarDecl>(D) || + if (isa<ParmVarDecl>(D) || (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) D->setUsed(true); @@ -7290,7 +7289,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (!Constructor->isUsed()) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } - + MaybeMarkVirtualMembersReferenced(Loc, Constructor); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) @@ -7312,32 +7311,32 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { = Function->getTemplateSpecializationInfo()) { if (SpecInfo->getPointOfInstantiation().isInvalid()) SpecInfo->setPointOfInstantiation(Loc); - else if (SpecInfo->getTemplateSpecializationKind() + else if (SpecInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) AlreadyInstantiated = true; - } else if (MemberSpecializationInfo *MSInfo + } else if (MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo()) { if (MSInfo->getPointOfInstantiation().isInvalid()) MSInfo->setPointOfInstantiation(Loc); - else if (MSInfo->getTemplateSpecializationKind() + else if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) AlreadyInstantiated = true; } - + if (!AlreadyInstantiated) { if (isa<CXXRecordDecl>(Function->getDeclContext()) && cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass()) PendingLocalImplicitInstantiations.push_back(std::make_pair(Function, Loc)); else - PendingImplicitInstantiations.push_back(std::make_pair(Function, + PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); } } - + // FIXME: keep track of references to static functions Function->setUsed(true); - + return; } @@ -7365,29 +7364,29 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { /// of the program being compiled. /// /// This routine emits the given diagnostic when the code currently being -/// type-checked is "potentially evaluated", meaning that there is a +/// type-checked is "potentially evaluated", meaning that there is a /// possibility that the code will actually be executable. Code in sizeof() /// expressions, code used only during overload resolution, etc., are not /// potentially evaluated. This routine will suppress such diagnostics or, /// in the absolutely nutty case of potentially potentially evaluated -/// expressions (C++ typeid), queue the diagnostic to potentially emit it +/// expressions (C++ typeid), queue the diagnostic to potentially emit it /// later. -/// +/// /// This routine should be used for all diagnostics that describe the run-time /// behavior of a program, such as passing a non-POD value through an ellipsis. /// Failure to do so will likely result in spurious diagnostics or failures /// during overload resolution or within sizeof/alignof/typeof/typeid. -bool Sema::DiagRuntimeBehavior(SourceLocation Loc, +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context ) { case Unevaluated: // The argument will never be evaluated, so don't complain. break; - + case PotentiallyEvaluated: Diag(Loc, PD); return true; - + case PotentiallyPotentiallyEvaluated: ExprEvalContexts.back().addDiagnostic(Loc, PD); break; @@ -7405,12 +7404,12 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here) << FD->getDeclName() : PDiag(); SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation(); - + if (RequireCompleteType(Loc, ReturnType, - FD ? + FD ? PDiag(diag::err_call_function_incomplete_return) << CE->getSourceRange() << FD->getDeclName() : - PDiag(diag::err_call_incomplete_return) + PDiag(diag::err_call_incomplete_return) << CE->getSourceRange(), std::make_pair(NoteLoc, Note))) return true; @@ -7460,7 +7459,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Open = E->getSourceRange().getBegin(); SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); - + Diag(Loc, diagnostic) << E->getSourceRange() << CodeModificationHint::CreateInsertion(Open, "(") diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b9c8afa..e1e5efa 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2085,7 +2085,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; - CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + CheckSignCompare(LHS, RHS, QuestionLoc); // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c60455d..c98ba43 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -106,7 +106,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, // which is an array type. StrTy = Context.CharTy; // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings) StrTy.addConst(); StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), ArrayType::Normal, 0); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3540cd0..98a7eec 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1051,6 +1051,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); bool InitializedSomething = false; + bool CheckForMissingFields = true; while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); @@ -1070,6 +1071,10 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, hadError = true; InitializedSomething = true; + + // Disable check for missing fields when designators are used. + // This matches gcc behaviour. + CheckForMissingFields = false; continue; } @@ -1106,6 +1111,21 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, ++Field; } + // Emit warnings for missing struct field initializers. + if (CheckForMissingFields && Field != FieldEnd && + !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) { + // It is possible we have one or more unnamed bitfields remaining. + // Find first (if any) named field and emit warning. + for (RecordDecl::field_iterator it = Field, end = RD->field_end(); + it != end; ++it) { + if (!it->isUnnamedBitfield()) { + SemaRef.Diag(IList->getSourceRange().getEnd(), + diag::warn_missing_field_initializers) << it->getName(); + break; + } + } + } + if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || Index >= IList->getNumInits()) return; @@ -3381,7 +3401,7 @@ InitializationSequence::Perform(Sema &S, // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); - S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, + S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, Conversion, FnAccess); // FIXME: Should we move this initialization into a separate diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 744b806..6caeec6 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -590,13 +590,73 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { return false; } -// Find the next outer declaration context corresponding to this scope. -static DeclContext *findOuterContext(Scope *S) { - for (S = S->getParent(); S; S = S->getParent()) - if (S->getEntity()) - return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext(); +// Find the next outer declaration context from this scope. This +// routine actually returns the semantic outer context, which may +// differ from the lexical context (encoded directly in the Scope +// stack) when we are parsing a member of a class template. In this +// case, the second element of the pair will be true, to indicate that +// name lookup should continue searching in this semantic context when +// it leaves the current template parameter scope. +static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { + DeclContext *DC = static_cast<DeclContext *>(S->getEntity()); + DeclContext *Lexical = 0; + for (Scope *OuterS = S->getParent(); OuterS; + OuterS = OuterS->getParent()) { + if (OuterS->getEntity()) { + Lexical = static_cast<DeclContext *>(OuterS->getEntity()); + break; + } + } + + // C++ [temp.local]p8: + // In the definition of a member of a class template that appears + // outside of the namespace containing the class template + // definition, the name of a template-parameter hides the name of + // a member of this namespace. + // + // Example: + // + // namespace N { + // class C { }; + // + // template<class T> class B { + // void f(T); + // }; + // } + // + // template<class C> void N::B<C>::f(C) { + // C b; // C is the template parameter, not N::C + // } + // + // In this example, the lexical context we return is the + // TranslationUnit, while the semantic context is the namespace N. + if (!Lexical || !DC || !S->getParent() || + !S->getParent()->isTemplateParamScope()) + return std::make_pair(Lexical, false); + + // Find the outermost template parameter scope. + // For the example, this is the scope for the template parameters of + // template<class C>. + Scope *OutermostTemplateScope = S->getParent(); + while (OutermostTemplateScope->getParent() && + OutermostTemplateScope->getParent()->isTemplateParamScope()) + OutermostTemplateScope = OutermostTemplateScope->getParent(); - return 0; + // Find the namespace context in which the original scope occurs. In + // the example, this is namespace N. + DeclContext *Semantic = DC; + while (!Semantic->isFileContext()) + Semantic = Semantic->getParent(); + + // Find the declaration context just outside of the template + // parameter scope. This is the context in which the template is + // being lexically declaration (a namespace context). In the + // example, this is the global scope. + if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && + Lexical->Encloses(Semantic)) + return std::make_pair(Semantic, true); + + return std::make_pair(Lexical, false); } bool Sema::CppLookupName(LookupResult &R, Scope *S) { @@ -627,6 +687,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // } // } // + DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { // Check whether the IdResolver has anything in this scope. bool Found = false; @@ -641,10 +702,26 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return true; } - if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { - DeclContext *OuterCtx = findOuterContext(S); - for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; - Ctx = Ctx->getLookupParent()) { + DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && + S->getParent() && !S->getParent()->isTemplateParamScope()) { + // We've just searched the last template parameter scope and + // found nothing, so look into the the contexts between the + // lexical and semantic declaration contexts returned by + // findOuterContext(). This implements the name lookup behavior + // of C++ [temp.local]p8. + Ctx = OutsideOfTemplateParamDC; + OutsideOfTemplateParamDC = 0; + } + + if (Ctx) { + DeclContext *OuterCtx; + bool SearchAfterTemplateScope; + llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + if (SearchAfterTemplateScope) + OutsideOfTemplateParamDC = OuterCtx; + + for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing // non-transparent context. @@ -725,7 +802,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } } - if (Ctx) { + // If we have a context, and it's not a context stashed in the + // template parameter scope for an out-of-line definition, also + // look into that context. + if (Ctx && !(Found && S && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); @@ -2216,15 +2296,16 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, } } + // FIXME: C++ [temp.local]p8 DeclContext *Entity = 0; if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. Entity = (DeclContext *)S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S); + DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx; + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { if (Method->isInstanceMethod()) { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp new file mode 100644 index 0000000..3a0fe0a --- /dev/null +++ b/lib/Sema/SemaObjCProperty.cpp @@ -0,0 +1,1085 @@ +//===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective C @property and +// @synthesize declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Grammar actions. +//===----------------------------------------------------------------------===// + +Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, + FieldDeclarator &FD, + ObjCDeclSpec &ODS, + Selector GetterSel, + Selector SetterSel, + DeclPtrTy ClassCategory, + bool *isOverridingProperty, + tok::ObjCKeywordKind MethodImplKind) { + unsigned Attributes = ODS.getPropertyAttributes(); + bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || + // default is readwrite! + !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); + // property is defaulted to 'assign' if it is readwrite and is + // not retain or copy + bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || + (isReadWrite && + !(Attributes & ObjCDeclSpec::DQ_PR_retain) && + !(Attributes & ObjCDeclSpec::DQ_PR_copy))); + + QualType T = GetTypeForDeclarator(FD.D, S); + if (T->isReferenceType()) { + Diag(AtLoc, diag::error_reference_property); + return DeclPtrTy(); + } + // Validate the attributes on the @property. + CheckObjCPropertyAttributes(T, AtLoc, Attributes); + + // Proceed with constructing the ObjCPropertDecls. + ObjCContainerDecl *ClassDecl = + cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>()); + + if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) + if (CDecl->IsClassExtension()) + return HandlePropertyInClassExtension(S, CDecl, AtLoc, + FD, GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, + isOverridingProperty, T, + MethodImplKind); + + return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, T, MethodImplKind)); +} + +Sema::DeclPtrTy +Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, + SourceLocation AtLoc, FieldDeclarator &FD, + Selector GetterSel, Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + bool *isOverridingProperty, + QualType T, + tok::ObjCKeywordKind MethodImplKind) { + + // Diagnose if this property is already in continuation class. + DeclContext *DC = cast<DeclContext>(CDecl); + IdentifierInfo *PropertyId = FD.D.getIdentifier(); + + if (ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { + Diag(AtLoc, diag::err_duplicate_property); + Diag(prevDecl->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + + // Create a new ObjCPropertyDecl with the DeclContext being + // the class extension. + ObjCPropertyDecl *PDecl = + ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), + PropertyId, AtLoc, T); + DC->addDecl(PDecl); + + // We need to look in the @interface to see if the @property was + // already declared. + ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); + if (!CCPrimary) { + Diag(CDecl->getLocation(), diag::err_continuation_class); + *isOverridingProperty = true; + return DeclPtrTy(); + } + + // Find the property in continuation class's primary class only. + ObjCPropertyDecl *PIDecl = + CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId); + + if (!PIDecl) { + // No matching property found in the primary class. Just fall thru + // and add property to continuation class's primary class. + ObjCPropertyDecl *PDecl = + CreatePropertyDecl(S, CCPrimary, AtLoc, + FD, GetterSel, SetterSel, isAssign, isReadWrite, + Attributes, T, MethodImplKind); + + // A case of continuation class adding a new property in the class. This + // is not what it was meant for. However, gcc supports it and so should we. + // Make sure setter/getters are declared here. + ProcessPropertyDecl(PDecl, CCPrimary); + return DeclPtrTy::make(PDecl); + + } + + // The property 'PIDecl's readonly attribute will be over-ridden + // with continuation class's readwrite property attribute! + unsigned PIkind = PIDecl->getPropertyAttributes(); + if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { + unsigned retainCopyNonatomic = + (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_nonatomic); + if ((Attributes & retainCopyNonatomic) != + (PIkind & retainCopyNonatomic)) { + Diag(AtLoc, diag::warn_property_attr_mismatch); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = + DC->lookup(PIDecl->getDeclName()); + bool PropertyInPrimaryClass = false; + for (; Found.first != Found.second; ++Found.first) + if (isa<ObjCPropertyDecl>(*Found.first)) { + PropertyInPrimaryClass = true; + break; + } + if (!PropertyInPrimaryClass) { + // Protocol is not in the primary class. Must build one for it. + ObjCDeclSpec ProtocolPropertyODS; + // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind + // and ObjCPropertyDecl::PropertyAttributeKind have identical + // values. Should consolidate both into one enum type. + ProtocolPropertyODS. + setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) + PIkind); + + DeclPtrTy ProtocolPtrTy = + ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + PIDecl->getGetterName(), + PIDecl->getSetterName(), + DeclPtrTy::make(CCPrimary), isOverridingProperty, + MethodImplKind); + PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>(); + } + PIDecl->makeitReadWriteAttribute(); + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + PIDecl->setSetterName(SetterSel); + } else { + Diag(AtLoc, diag::err_use_continuation_class) + << CCPrimary->getDeclName(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + *isOverridingProperty = true; + // Make sure setter decl is synthesized, and added to primary class's list. + ProcessPropertyDecl(PIDecl, CCPrimary); + return DeclPtrTy(); +} + +ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + QualType T, + tok::ObjCKeywordKind MethodImplKind){ + + IdentifierInfo *PropertyId = FD.D.getIdentifier(); + + // Issue a warning if property is 'assign' as default and its object, which is + // gc'able conforms to NSCopying protocol + if (getLangOptions().getGCMode() != LangOptions::NonGC && + isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) + if (T->isObjCObjectPointerType()) { + QualType InterfaceTy = T->getPointeeType(); + if (const ObjCInterfaceType *OIT = + InterfaceTy->getAs<ObjCInterfaceType>()) { + ObjCInterfaceDecl *IDecl = OIT->getDecl(); + if (IDecl) + if (ObjCProtocolDecl* PNSCopying = + LookupProtocol(&Context.Idents.get("NSCopying"))) + if (IDecl->ClassImplementsProtocol(PNSCopying, true)) + Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; + } + } + if (T->isObjCInterfaceType()) + Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); + + DeclContext *DC = cast<DeclContext>(CDecl); + ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, + FD.D.getIdentifierLoc(), + PropertyId, AtLoc, T); + + if (ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { + Diag(PDecl->getLocation(), diag::err_duplicate_property); + Diag(prevDecl->getLocation(), diag::note_property_declare); + PDecl->setInvalidDecl(); + } + else + DC->addDecl(PDecl); + + if (T->isArrayType() || T->isFunctionType()) { + Diag(AtLoc, diag::err_property_type) << T; + PDecl->setInvalidDecl(); + } + + ProcessDeclAttributes(S, PDecl, FD.D); + + // Regardless of setter/getter attribute, we save the default getter/setter + // selector names in anticipation of declaration of setter/getter methods. + PDecl->setGetterName(GetterSel); + PDecl->setSetterName(SetterSel); + + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + + if (Attributes & ObjCDeclSpec::DQ_PR_getter) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); + + if (Attributes & ObjCDeclSpec::DQ_PR_setter) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); + + if (isReadWrite) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + + if (isAssign) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + + if (MethodImplKind == tok::objc_required) + PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); + else if (MethodImplKind == tok::objc_optional) + PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); + + return PDecl; +} + + +/// ActOnPropertyImplDecl - This routine performs semantic checks and +/// builds the AST node for a property implementation declaration; declared +/// as @synthesize or @dynamic. +/// +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool Synthesize, + DeclPtrTy ClassCatImpDecl, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar) { + Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>(); + // Make sure we have a context for the property implementation declaration. + if (!ClassImpDecl) { + Diag(AtLoc, diag::error_missing_property_context); + return DeclPtrTy(); + } + ObjCPropertyDecl *property = 0; + ObjCInterfaceDecl* IDecl = 0; + // Find the class or category class where this property must have + // a declaration. + ObjCImplementationDecl *IC = 0; + ObjCCategoryImplDecl* CatImplClass = 0; + if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) { + IDecl = IC->getClassInterface(); + // We always synthesize an interface for an implementation + // without an interface decl. So, IDecl is always non-zero. + assert(IDecl && + "ActOnPropertyImplDecl - @implementation without @interface"); + + // Look for this property declaration in the @implementation's @interface + property = IDecl->FindPropertyDeclaration(PropertyId); + if (!property) { + Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); + return DeclPtrTy(); + } + if (const ObjCCategoryDecl *CD = + dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { + if (!CD->IsClassExtension()) { + Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); + Diag(property->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + } + } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { + if (Synthesize) { + Diag(AtLoc, diag::error_synthesize_category_decl); + return DeclPtrTy(); + } + IDecl = CatImplClass->getClassInterface(); + if (!IDecl) { + Diag(AtLoc, diag::error_missing_property_interface); + return DeclPtrTy(); + } + ObjCCategoryDecl *Category = + IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); + + // If category for this implementation not found, it is an error which + // has already been reported eralier. + if (!Category) + return DeclPtrTy(); + // Look for this property declaration in @implementation's category + property = Category->FindPropertyDeclaration(PropertyId); + if (!property) { + Diag(PropertyLoc, diag::error_bad_category_property_decl) + << Category->getDeclName(); + return DeclPtrTy(); + } + } else { + Diag(AtLoc, diag::error_bad_property_context); + return DeclPtrTy(); + } + ObjCIvarDecl *Ivar = 0; + // Check that we have a valid, previously declared ivar for @synthesize + if (Synthesize) { + // @synthesize + if (!PropertyIvar) + PropertyIvar = PropertyId; + QualType PropType = Context.getCanonicalType(property->getType()); + // Check that this is a previously declared 'ivar' in 'IDecl' interface + ObjCInterfaceDecl *ClassDeclared; + Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); + if (!Ivar) { + DeclContext *EnclosingContext = cast_or_null<DeclContext>(ClassImpDecl); + assert(EnclosingContext && + "null DeclContext for synthesized ivar - ActOnPropertyImplDecl"); + Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc, + PropertyIvar, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Public, + (Expr *)0); + EnclosingContext->addDecl(Ivar); + IDecl->makeDeclVisibleInContext(Ivar, false); + property->setPropertyIvarDecl(Ivar); + + if (!getLangOptions().ObjCNonFragileABI) + Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; + // Note! I deliberately want it to fall thru so, we have a + // a property implementation and to avoid future warnings. + } else if (getLangOptions().ObjCNonFragileABI && + ClassDeclared != IDecl) { + Diag(PropertyLoc, diag::error_ivar_in_superclass_use) + << property->getDeclName() << Ivar->getDeclName() + << ClassDeclared->getDeclName(); + Diag(Ivar->getLocation(), diag::note_previous_access_declaration) + << Ivar << Ivar->getNameAsCString(); + // Note! I deliberately want it to fall thru so more errors are caught. + } + QualType IvarType = Context.getCanonicalType(Ivar->getType()); + + // Check that type of property and its ivar are type compatible. + if (PropType != IvarType) { + if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { + Diag(PropertyLoc, diag::error_property_ivar_type) + << property->getDeclName() << Ivar->getDeclName(); + // Note! I deliberately want it to fall thru so, we have a + // a property implementation and to avoid future warnings. + } + + // FIXME! Rules for properties are somewhat different that those + // for assignments. Use a new routine to consolidate all cases; + // specifically for property redeclarations as well as for ivars. + QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); + QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); + if (lhsType != rhsType && + lhsType->isArithmeticType()) { + Diag(PropertyLoc, diag::error_property_ivar_type) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + // __weak is explicit. So it works on Canonical type. + if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_weak_property) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + if ((property->getType()->isObjCObjectPointerType() || + PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_strong_property) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + } + } else if (PropertyIvar) + // @dynamic + Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); + assert (property && "ActOnPropertyImplDecl - property declaration missing"); + ObjCPropertyImplDecl *PIDecl = + ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, + property, + (Synthesize ? + ObjCPropertyImplDecl::Synthesize + : ObjCPropertyImplDecl::Dynamic), + Ivar); + if (IC) { + if (Synthesize) + if (ObjCPropertyImplDecl *PPIDecl = + IC->FindPropertyImplIvarDecl(PropertyIvar)) { + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + << PropertyIvar; + Diag(PPIDecl->getLocation(), diag::note_previous_use); + } + + if (ObjCPropertyImplDecl *PPIDecl + = IC->FindPropertyImplDecl(PropertyId)) { + Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PPIDecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + IC->addPropertyImplementation(PIDecl); + } else { + if (Synthesize) + if (ObjCPropertyImplDecl *PPIDecl = + CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) { + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + << PropertyIvar; + Diag(PPIDecl->getLocation(), diag::note_previous_use); + } + + if (ObjCPropertyImplDecl *PPIDecl = + CatImplClass->FindPropertyImplDecl(PropertyId)) { + Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PPIDecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + CatImplClass->addPropertyImplementation(PIDecl); + } + + return DeclPtrTy::make(PIDecl); +} + +//===----------------------------------------------------------------------===// +// Helper methods. +//===----------------------------------------------------------------------===// + +/// DiagnosePropertyMismatch - Compares two properties for their +/// attributes and types and warns on a variety of inconsistencies. +/// +void +Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *inheritedName) { + ObjCPropertyDecl::PropertyAttributeKind CAttr = + Property->getPropertyAttributes(); + ObjCPropertyDecl::PropertyAttributeKind SAttr = + SuperProperty->getPropertyAttributes(); + if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) + && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) + Diag(Property->getLocation(), diag::warn_readonly_property) + << Property->getDeclName() << inheritedName; + if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) + != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "copy" << inheritedName; + else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) + != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "retain" << inheritedName; + + if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) + != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "atomic" << inheritedName; + if (Property->getSetterName() != SuperProperty->getSetterName()) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "setter" << inheritedName; + if (Property->getGetterName() != SuperProperty->getGetterName()) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "getter" << inheritedName; + + QualType LHSType = + Context.getCanonicalType(SuperProperty->getType()); + QualType RHSType = + Context.getCanonicalType(Property->getType()); + + if (!Context.typesAreCompatible(LHSType, RHSType)) { + // FIXME: Incorporate this test with typesAreCompatible. + if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) + if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) + return; + Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) + << Property->getType() << SuperProperty->getType() << inheritedName; + } +} + +bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, + ObjCMethodDecl *GetterMethod, + SourceLocation Loc) { + if (GetterMethod && + GetterMethod->getResultType() != property->getType()) { + AssignConvertType result = Incompatible; + if (property->getType()->isObjCObjectPointerType()) + result = CheckAssignmentConstraints(GetterMethod->getResultType(), + property->getType()); + if (result != Compatible) { + Diag(Loc, diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << GetterMethod->getSelector(); + Diag(GetterMethod->getLocation(), diag::note_declared_at); + return true; + } + } + return false; +} + +/// ComparePropertiesInBaseAndSuper - This routine compares property +/// declarations in base and its super class, if any, and issues +/// diagnostics in a variety of inconsistant situations. +/// +void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { + ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); + if (!SDecl) + return; + // FIXME: O(N^2) + for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(), + E = SDecl->prop_end(); S != E; ++S) { + ObjCPropertyDecl *SuperPDecl = (*S); + // Does property in super class has declaration in current class? + for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(), + E = IDecl->prop_end(); I != E; ++I) { + ObjCPropertyDecl *PDecl = (*I); + if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) + DiagnosePropertyMismatch(PDecl, SuperPDecl, + SDecl->getIdentifier()); + } + } +} + +/// MatchOneProtocolPropertiesInClass - This routine goes thru the list +/// of properties declared in a protocol and compares their attribute against +/// the same property declared in the class or category. +void +Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, + ObjCProtocolDecl *PDecl) { + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); + assert (CatDecl && "MatchOneProtocolPropertiesInClass"); + if (!CatDecl->IsClassExtension()) + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCCategoryDecl::prop_iterator CP, CE; + // Is this property already in category's list of properties? + for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } + return; + } + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCInterfaceDecl::prop_iterator CP, CE; + // Is this property already in class's list of properties? + for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } +} + +/// CompareProperties - This routine compares properties +/// declared in 'ClassOrProtocol' objects (which can be a class or an +/// inherited protocol with the list of properties for class/category 'CDecl' +/// +void Sema::CompareProperties(Decl *CDecl, + DeclPtrTy ClassOrProtocol) { + Decl *ClassDecl = ClassOrProtocol.getAs<Decl>(); + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); + + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); + assert (CatDecl && "CompareProperties"); + if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { + for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Match properties of category with those of protocol (*P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); + + // Go thru the list of protocols for this category and recursively match + // their properties with those in the category. + for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), + E = CatDecl->protocol_end(); P != E; ++P) + CompareProperties(CatDecl, DeclPtrTy::make(*P)); + } else { + ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); + } + return; + } + + if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Match properties of class IDecl with those of protocol (*P). + MatchOneProtocolPropertiesInClass(IDecl, *P); + + // Go thru the list of protocols for this class and recursively match + // their properties with those declared in the class. + for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), + E = IDecl->protocol_end(); P != E; ++P) + CompareProperties(IDecl, DeclPtrTy::make(*P)); + } else { + ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MatchOneProtocolPropertiesInClass(IDecl, *P); + } +} + +/// isPropertyReadonly - Return true if property is readonly, by searching +/// for the property in the class and in its categories and implementations +/// +bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, + ObjCInterfaceDecl *IDecl) { + // by far the most common case. + if (!PDecl->isReadOnly()) + return false; + // Even if property is ready only, if interface has a user defined setter, + // it is not considered read only. + if (IDecl->getInstanceMethod(PDecl->getSetterName())) + return false; + + // Main class has the property as 'readonly'. Must search + // through the category list to see if the property's + // attribute has been over-ridden to 'readwrite'. + for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + // Even if property is ready only, if a category has a user defined setter, + // it is not considered read only. + if (Category->getInstanceMethod(PDecl->getSetterName())) + return false; + ObjCPropertyDecl *P = + Category->FindPropertyDeclaration(PDecl->getIdentifier()); + if (P && !P->isReadOnly()) + return false; + } + + // Also, check for definition of a setter method in the implementation if + // all else failed. + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) { + if (ObjCImplementationDecl *IMD = + dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) { + if (IMD->getInstanceMethod(PDecl->getSetterName())) + return false; + } else if (ObjCCategoryImplDecl *CIMD = + dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { + if (CIMD->getInstanceMethod(PDecl->getSetterName())) + return false; + } + } + // Lastly, look through the implementation (if one is in scope). + if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation()) + if (ImpDecl->getInstanceMethod(PDecl->getSetterName())) + return false; + // If all fails, look at the super class. + if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass()) + return isPropertyReadonly(PDecl, SIDecl); + return true; +} + +/// CollectImmediateProperties - This routine collects all properties in +/// the class and its conforming protocols; but not those it its super class. +void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { + if (!CATDecl->IsClassExtension()) + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), + E = CATDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; + if (!PropEntry) + PropEntry = Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } +} + +/// LookupPropertyDecl - Looks up a property in the current class and all +/// its protocols. +ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, + IdentifierInfo *II) { + if (const ObjCInterfaceDecl *IDecl = + dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->getIdentifier() == II) + return Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) { + ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); + if (Prop) + return Prop; + } + } + else if (const ObjCProtocolDecl *PDecl = + dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->getIdentifier() == II) + return Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) { + ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); + if (Prop) + return Prop; + } + } + return 0; +} + + +void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const llvm::DenseSet<Selector>& InsMap) { + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + CollectImmediateProperties(CDecl, PropMap); + if (PropMap.empty()) + return; + + llvm::DenseSet<ObjCPropertyDecl *> PropImplMap; + for (ObjCImplDecl::propimpl_iterator + I = IMPDecl->propimpl_begin(), + EI = IMPDecl->propimpl_end(); I != EI; ++I) + PropImplMap.insert((*I)->getPropertyDecl()); + + for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { + ObjCPropertyDecl *Prop = P->second; + // Is there a matching propery synthesize/dynamic? + if (Prop->isInvalidDecl() || + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || + PropImplMap.count(Prop)) + continue; + if (LangOpts.ObjCNonFragileABI2) { + ActOnPropertyImplDecl(IMPDecl->getLocation(), + SourceLocation(), + true, DeclPtrTy::make(IMPDecl), + Prop->getIdentifier(), + Prop->getIdentifier()); + continue; + } + if (!InsMap.count(Prop->getGetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getGetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getSetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + } +} + +void +Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl) { + // Rules apply in non-GC mode only + if (getLangOptions().getGCMode() != LangOptions::NonGC) + return; + for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), + E = IDecl->prop_end(); + I != E; ++I) { + ObjCPropertyDecl *Property = (*I); + unsigned Attributes = Property->getPropertyAttributes(); + // We only care about readwrite atomic property. + if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || + !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) + continue; + if (const ObjCPropertyImplDecl *PIDecl + = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + ObjCMethodDecl *GetterMethod = + IMPDecl->getInstanceMethod(Property->getGetterName()); + ObjCMethodDecl *SetterMethod = + IMPDecl->getInstanceMethod(Property->getSetterName()); + if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { + SourceLocation MethodLoc = + (GetterMethod ? GetterMethod->getLocation() + : SetterMethod->getLocation()); + Diag(MethodLoc, diag::warn_atomic_property_rule) + << Property->getIdentifier(); + Diag(Property->getLocation(), diag::note_property_declare); + } + } + } +} + +/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods +/// have the property type and issue diagnostics if they don't. +/// Also synthesize a getter/setter method if none exist (and update the +/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized +/// methods is the "right" thing to do. +void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, + ObjCContainerDecl *CD) { + ObjCMethodDecl *GetterMethod, *SetterMethod; + + GetterMethod = CD->getInstanceMethod(property->getGetterName()); + SetterMethod = CD->getInstanceMethod(property->getSetterName()); + DiagnosePropertyAccessorMismatch(property, GetterMethod, + property->getLocation()); + + if (SetterMethod) { + ObjCPropertyDecl::PropertyAttributeKind CAttr = + property->getPropertyAttributes(); + if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) && + Context.getCanonicalType(SetterMethod->getResultType()) != + Context.VoidTy) + Diag(SetterMethod->getLocation(), diag::err_setter_type_void); + if (SetterMethod->param_size() != 1 || + ((*SetterMethod->param_begin())->getType() != property->getType())) { + Diag(property->getLocation(), + diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << SetterMethod->getSelector(); + Diag(SetterMethod->getLocation(), diag::note_declared_at); + } + } + + // Synthesize getter/setter methods if none exist. + // Find the default getter and if one not found, add one. + // FIXME: The synthesized property we set here is misleading. We almost always + // synthesize these methods unless the user explicitly provided prototypes + // (which is odd, but allowed). Sema should be typechecking that the + // declarations jive in that situation (which it is not currently). + if (!GetterMethod) { + // No instance method of same name as property getter name was found. + // Declare a getter method and add it to the list of methods + // for this class. + GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), property->getGetterName(), + property->getType(), 0, CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + CD->addDecl(GetterMethod); + } else + // A user declared getter will be synthesize when @synthesize of + // the property with the same name is seen in the @implementation + GetterMethod->setSynthesized(true); + property->setGetterMethodDecl(GetterMethod); + + // Skip setter if property is read-only. + if (!property->isReadOnly()) { + // Find the default setter and if one not found, add one. + if (!SetterMethod) { + // No instance method of same name as property setter name was found. + // Declare a setter method and add it to the list of methods + // for this class. + SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), + property->getSetterName(), + Context.VoidTy, 0, CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + // Invent the arguments for the setter. We don't bother making a + // nice name for the argument. + ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, + property->getLocation(), + property->getIdentifier(), + property->getType(), + /*TInfo=*/0, + VarDecl::None, + 0); + SetterMethod->setMethodParams(Context, &Argument, 1); + CD->addDecl(SetterMethod); + } else + // A user declared setter will be synthesize when @synthesize of + // the property with the same name is seen in the @implementation + SetterMethod->setSynthesized(true); + property->setSetterMethodDecl(SetterMethod); + } + // Add any synthesized methods to the global pool. This allows us to + // handle the following, which is supported by GCC (and part of the design). + // + // @interface Foo + // @property double bar; + // @end + // + // void thisIsUnfortunate() { + // id foo; + // double bar = [foo bar]; + // } + // + if (GetterMethod) + AddInstanceMethodToGlobalPool(GetterMethod); + if (SetterMethod) + AddInstanceMethodToGlobalPool(SetterMethod); +} + +void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, + SourceLocation Loc, + unsigned &Attributes) { + // FIXME: Improve the reported location. + + // readonly and readwrite/assign/retain/copy conflict. + if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | + ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain))) { + const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ? + "readwrite" : + (Attributes & ObjCDeclSpec::DQ_PR_assign) ? + "assign" : + (Attributes & ObjCDeclSpec::DQ_PR_copy) ? + "copy" : "retain"; + + Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? + diag::err_objc_property_attr_mutually_exclusive : + diag::warn_objc_property_attr_mutually_exclusive) + << "readonly" << which; + } + + // Check for copy or retain on non-object types. + if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && + !PropertyTy->isObjCObjectPointerType() && + !PropertyTy->isBlockPointerType() && + !Context.isObjCNSObjectType(PropertyTy)) { + Diag(Loc, diag::err_objc_property_requires_object) + << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); + Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); + } + + // Check for more than one of { assign, copy, retain }. + if (Attributes & ObjCDeclSpec::DQ_PR_assign) { + if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "copy"; + Attributes &= ~ObjCDeclSpec::DQ_PR_copy; + } + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "copy" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + } + + // Warn if user supplied no assignment attribute, property is + // readwrite, and this is an object type. + if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain)) && + !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && + PropertyTy->isObjCObjectPointerType()) { + // Skip this warning in gc-only mode. + if (getLangOptions().getGCMode() != LangOptions::GCOnly) + Diag(Loc, diag::warn_objc_property_no_assignment_attribute); + + // If non-gc code warn that this is likely inappropriate. + if (getLangOptions().getGCMode() == LangOptions::NonGC) + Diag(Loc, diag::warn_objc_property_default_assign_on_object); + + // FIXME: Implement warning dependent on NSCopying being + // implemented. See also: + // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496> + // (please trim this list while you are at it). + } + + if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) + && getLangOptions().getGCMode() == LangOptions::GCOnly + && PropertyTy->isBlockPointerType()) + Diag(Loc, diag::warn_objc_property_copy_missing_on_block); +} + +ObjCIvarDecl* +Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, + IdentifierInfo *NameII) { + ObjCIvarDecl *Ivar = 0; + ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); + if (Prop && !Prop->isInvalidDecl()) { + DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); + QualType PropType = Context.getCanonicalType(Prop->getType()); + assert(EnclosingContext && + "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar"); + Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, + Prop->getLocation(), + NameII, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Public, + (Expr *)0); + Ivar->setLexicalDeclContext(IDecl); + IDecl->addDecl(Ivar); + Prop->setPropertyIvarDecl(Ivar); + } + return Ivar; +} + diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ff59fc3..f73ec9c 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1135,6 +1135,12 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // Objective C++: We're able to convert from a pointer to an // interface to a pointer to a different interface. if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) { + const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType(); + const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType(); + if (getLangOptions().CPlusPlus && LHS && RHS && + !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs( + FromObjCPtr->getPointeeType())) + return false; ConvertedType = ToType; return true; } @@ -1405,8 +1411,9 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, } if (!IgnoreBaseAccess) - CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true, - FromClass, ToClass, Paths.front()); + CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass, + Paths.front(), + diag::err_downcast_from_inaccessible_base); // Must be a base to derived member conversion. Kind = CastExpr::CK_BaseToDerivedMemberPointer; @@ -5542,7 +5549,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess()); if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method)) return ExprError(); @@ -5726,7 +5733,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { // Best->Access is only meaningful for class members. - CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method, + Best->getAccess()); OwningExprResult Arg1 = PerformCopyInitialization( @@ -5900,7 +5908,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched an overloaded operator. Build a call to that // operator. - CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess()); + CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl, + Best->getAccess()); // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); @@ -6269,7 +6278,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); - CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess()); + CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess()); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -6284,7 +6293,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CommaLocs, RParenLoc).release(); } - CheckMemberOperatorAccess(LParenLoc, Object, + CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->Function, Best->getAccess()); // We found an overloaded operator(). Build a CXXOperatorCallExpr diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 75d9f67..fd65c32 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -76,10 +76,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (!E) return; - // Ignore expressions that have void type. - if (E->getType()->isVoidType()) - return; - SourceLocation Loc; SourceRange R1, R2; if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) @@ -103,6 +99,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + if (E->getType()->isVoidType()) + return; + // If the callee has attribute pure, const, or warn_unused_result, warn with // a more specific message to make it clear what is happening. if (const Decl *FD = CE->getCalleeDecl()) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7c4cab1..434d556 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Template.h" @@ -696,6 +697,12 @@ Sema::ActOnTemplateParameterList(unsigned Depth, RAngleLoc); } +static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { + if (SS.isSet()) + T->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()), + SS.getRange()); +} + Sema::DeclResult Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, const CXXScopeSpec &SS, @@ -863,6 +870,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, PrevClassTemplate? PrevClassTemplate->getTemplatedDecl() : 0, /*DelayTypeCreation=*/true); + SetNestedNameSpecifier(NewClass, SS); ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, @@ -3490,6 +3498,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateArgs, CanonType, PrevPartial); + SetNestedNameSpecifier(Partial, SS); if (PrevPartial) { ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial); @@ -3546,6 +3555,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate, Converted, PrevDecl); + SetNestedNameSpecifier(Specialization, SS); if (PrevDecl) { ClassTemplate->getSpecializations().RemoveNode(PrevDecl); @@ -4327,6 +4337,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, TemplateNameLoc, ClassTemplate, Converted, PrevDecl); + SetNestedNameSpecifier(Specialization, SS); if (PrevDecl) { // Remove the previous declaration from the folding set, since we want diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 8f73337..0d6acd0 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -567,6 +567,15 @@ namespace { Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); + /// \brief Transforms a function proto type by performing + /// substitution in the function parameters, possibly adjusting + /// their types and marking default arguments as uninstantiated. + bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars); + + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, @@ -859,6 +868,61 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( } +bool +TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { + // Create a local instantiation scope for the parameters. + Sema::LocalInstantiationScope + Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0); + + if (TreeTransform<TemplateInstantiator>:: + TransformFunctionTypeParams(TL, PTypes, PVars)) + return true; + + // Check instantiated parameters. + if (SemaRef.CheckInstantiatedParams(PVars)) + return true; + + return false; +} + +ParmVarDecl * +TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return 0; + + // TODO: do we have to clone this decl if the types match and + // there's no default argument? + + ParmVarDecl *NewParm + = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); + + // Maybe adjust new parameter type. + NewParm->setType(SemaRef.adjustParameterType(NewParm->getType())); + + // Mark the (new) default argument as uninstantiated (if any). + if (OldParm->hasUninstantiatedDefaultArg()) { + Expr *Arg = OldParm->getUninstantiatedDefaultArg(); + NewParm->setUninstantiatedDefaultArg(Arg); + } else if (Expr *Arg = OldParm->getDefaultArg()) + NewParm->setUninstantiatedDefaultArg(Arg); + + NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); + + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + return NewParm; +} + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index cf8d38c..dbe041c 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/Preprocessor.h" @@ -89,13 +90,18 @@ namespace { } // Helper functions for instantiating methods. - QualType SubstFunctionType(FunctionDecl *D, + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl<ParmVarDecl *> &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); TemplateParameterList * SubstTemplateParams(TemplateParameterList *List); + + bool SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl); + bool SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl); bool InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, @@ -103,6 +109,38 @@ namespace { }; } +bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl) { + NestedNameSpecifier *OldQual = OldDecl->getQualifier(); + if (!OldQual) return false; + + SourceRange QualRange = OldDecl->getQualifierRange(); + + NestedNameSpecifier *NewQual + = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs); + if (!NewQual) + return true; + + NewDecl->setQualifierInfo(NewQual, QualRange); + return false; +} + +bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl) { + NestedNameSpecifier *OldQual = OldDecl->getQualifier(); + if (!OldQual) return false; + + SourceRange QualRange = OldDecl->getQualifierRange(); + + NestedNameSpecifier *NewQual + = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs); + if (!NewQual) + return true; + + NewDecl->setQualifierInfo(NewQual, QualRange); + return false; +} + // FIXME: Is this too simple? void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) { for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr; @@ -286,6 +324,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Var)) + return 0; + // If we are instantiating a static data member defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. @@ -510,6 +552,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { /*PrevDecl=*/0); Enum->setInstantiationOfMemberEnum(D); Enum->setAccess(D->getAccess()); + if (SubstQualifier(D, Enum)) return 0; Owner->addDecl(Enum); Enum->startDefinition(); @@ -610,6 +653,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL, /*DelayTypeCreation=*/true); + // Substitute the nested name specifier, if any. + if (SubstQualifier(Pattern, RecordInst)) + return 0; + ClassTemplateDecl *Inst = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), InstParams, RecordInst, 0); @@ -744,6 +791,11 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, D->getLocation(), D->getIdentifier(), D->getTagKeywordLoc(), PrevDecl); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Record)) + return 0; + Record->setImplicit(D->isImplicit()); // FIXME: Check against AS_none is an ugly hack to work around the issue that // the tag decls introduced by friend class declarations don't have an access @@ -797,9 +849,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = SubstFunctionType(D, Params); - if (T.isNull()) + TypeSourceInfo *TInfo = D->getTypeSourceInfo(); + TInfo = SubstFunctionType(D, Params); + if (!TInfo) return 0; + QualType T = TInfo->getType(); // If we're instantiating a local function declaration, put the result // in the owner; otherwise we need to find the instantiated context. @@ -812,9 +866,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getDeclName(), T, D->getTypeSourceInfo(), + D->getDeclName(), T, TInfo, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Function)) + return 0; + Function->setLexicalDeclContext(Owner); // Attach the parameters @@ -932,9 +991,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = SubstFunctionType(D, Params); - if (T.isNull()) + TypeSourceInfo *TInfo = D->getTypeSourceInfo(); + TInfo = SubstFunctionType(D, Params); + if (!TInfo) return 0; + QualType T = TInfo->getType(); // Build the instantiated method declaration. CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); @@ -947,8 +1008,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXConstructorDecl::Create(SemaRef.Context, Record, Constructor->getLocation(), - Name, T, - Constructor->getTypeSourceInfo(), + Name, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { @@ -966,15 +1026,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ConvTy); Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, - T, Conversion->getTypeSourceInfo(), + T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->getTypeSourceInfo(), + D->getDeclName(), T, TInfo, D->isStatic(), D->isInlineSpecified()); } + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Method)) + return 0; + if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -1504,6 +1568,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstTemplateArgs, CanonType, 0); + // Substitute the nested name specifier, if any. + if (SubstQualifier(PartialSpec, InstPartialSpec)) + return 0; + InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); @@ -1514,60 +1582,49 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return false; } -/// \brief Does substitution on the type of the given function, including -/// all of the function parameters. -/// -/// \param D The function whose type will be the basis of the substitution -/// -/// \param Params the instantiated parameter declarations - -/// \returns the instantiated function's type if successful, a NULL -/// type if there was an error. -QualType -TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, - llvm::SmallVectorImpl<ParmVarDecl *> &Params) { - bool InvalidDecl = false; - - // Substitute all of the function's formal parameter types. - TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs); - llvm::SmallVector<QualType, 4> ParamTys; - for (FunctionDecl::param_iterator P = D->param_begin(), - PEnd = D->param_end(); - P != PEnd; ++P) { - if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) { - if (PInst->getType()->isVoidType()) { - SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type); +bool +Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) { + bool Invalid = false; + for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i) + if (ParmVarDecl *PInst = Params[i]) { + if (PInst->isInvalidDecl()) + Invalid = true; + else if (PInst->getType()->isVoidType()) { + Diag(PInst->getLocation(), diag::err_param_with_void_type); PInst->setInvalidDecl(); - } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), - PInst->getType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType)) + Invalid = true; + } + else if (RequireNonAbstractType(PInst->getLocation(), + PInst->getType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType)) { PInst->setInvalidDecl(); + Invalid = true; + } + } + return Invalid; +} - Params.push_back(PInst); - ParamTys.push_back(PInst->getType()); +TypeSourceInfo* +TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, + llvm::SmallVectorImpl<ParmVarDecl *> &Params) { + TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); + assert(OldTInfo && "substituting function without type source info"); + assert(Params.empty() && "parameter vector is non-empty at start"); + TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); + if (!NewTInfo) + return 0; - if (PInst->isInvalidDecl()) - InvalidDecl = true; - } else - InvalidDecl = true; - } + // Get parameters from the new type info. + TypeLoc NewTL = NewTInfo->getTypeLoc(); + FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); + assert(NewProtoLoc && "Missing prototype?"); + for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) + Params.push_back(NewProtoLoc->getArg(i)); - // FIXME: Deallocate dead declarations. - if (InvalidDecl) - return QualType(); - - const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>(); - assert(Proto && "Missing prototype?"); - QualType ResultType - = SemaRef.SubstType(Proto->getResultType(), TemplateArgs, - D->getLocation(), D->getDeclName()); - if (ResultType.isNull()) - return QualType(); - - return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(), - Proto->isVariadic(), Proto->getTypeQuals(), - D->getLocation(), D->getDeclName()); + return NewTInfo; } /// \brief Initializes the common fields of an instantiation function diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 17f9419..d6f3352 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -315,6 +315,21 @@ public: QualType ObjectType = QualType()); #include "clang/AST/TypeLocNodes.def" + /// \brief Transforms the parameters of a function type into the + /// given vectors. + /// + /// The result vectors should be kept in sync; null entries in the + /// variables vector are acceptable. + /// + /// Return true on error. + bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars); + + /// \brief Transforms a single function-type parameter. Return null + /// on error. + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, QualType ObjectType); @@ -2520,18 +2535,33 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, } template<typename Derived> -QualType -TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - QualType ObjectType) { +ParmVarDecl * +TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return 0; + + if (NewDI == OldDI) + return OldParm; + else + return ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); +} + +template<typename Derived> +bool TreeTransform<Derived>:: + TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); - // Transform the parameters. - llvm::SmallVector<QualType, 4> ParamTypes; - llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { ParmVarDecl *OldParm = TL.getArg(i); @@ -2539,24 +2569,9 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl *NewParm; if (OldParm) { - TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - assert(OldDI->getType() == T->getArgType(i)); - - TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); - if (!NewDI) - return QualType(); - - if (NewDI == OldDI) - NewParm = OldParm; - else - NewParm = ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - /* DefArg */ NULL); + NewParm = getDerived().TransformFunctionTypeParam(OldParm); + if (!NewParm) + return true; NewType = NewParm->getType(); // Deal with the possibility that we don't have a parameter @@ -2567,13 +2582,32 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, QualType OldType = T->getArgType(i); NewType = getDerived().TransformType(OldType); if (NewType.isNull()) - return QualType(); + return true; } - ParamTypes.push_back(NewType); - ParamDecls.push_back(NewParm); + PTypes.push_back(NewType); + PVars.push_back(NewParm); } + return false; +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType) { + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + // Transform the parameters. + llvm::SmallVector<QualType, 4> ParamTypes; + llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; + if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + return QualType(); + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || |