summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/Makefile2
-rw-r--r--lib/Sema/Sema.h165
-rw-r--r--lib/Sema/SemaAccess.cpp207
-rw-r--r--lib/Sema/SemaCXXCast.cpp8
-rw-r--r--lib/Sema/SemaChecking.cpp58
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp24
-rw-r--r--lib/Sema/SemaDeclAttr.cpp16
-rw-r--r--lib/Sema/SemaDeclCXX.cpp167
-rw-r--r--lib/Sema/SemaDeclObjC.cpp1004
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp6
-rw-r--r--lib/Sema/SemaExpr.cpp353
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--lib/Sema/SemaExprObjC.cpp2
-rw-r--r--lib/Sema/SemaInit.cpp22
-rw-r--r--lib/Sema/SemaLookup.cpp107
-rw-r--r--lib/Sema/SemaObjCProperty.cpp1085
-rw-r--r--lib/Sema/SemaOverload.cpp23
-rw-r--r--lib/Sema/SemaStmt.cpp7
-rw-r--r--lib/Sema/SemaTemplate.cpp11
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp64
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp175
-rw-r--r--lib/Sema/TreeTransform.h96
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() ||
OpenPOWER on IntegriCloud