diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Lookup.h | 104 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 69 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 99 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 527 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 418 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 59 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 214 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 112 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 38 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 15 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 269 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 57 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 133 |
24 files changed, 1559 insertions, 785 deletions
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index fbd1450..8c4caaf 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -572,11 +572,11 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, break; case Decl::ObjCImplementation: - Kind = CXCursor_ObjCClassDefn; + Kind = CXCursor_ObjCImplementationDecl; break; case Decl::ObjCCategoryImpl: - Kind = CXCursor_ObjCCategoryDefn; + Kind = CXCursor_ObjCCategoryImplDecl; break; default: diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 9064de6..f4cea2e 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -123,9 +123,7 @@ public: Temporary }; - typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; - typedef DeclsTy::const_iterator iterator; - + typedef UnresolvedSetImpl::iterator iterator; typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS); LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, @@ -133,6 +131,7 @@ public: Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) : ResultKind(NotFound), Paths(0), + NamingClass(0), SemaRef(SemaRef), Name(Name), NameLoc(NameLoc), @@ -152,6 +151,7 @@ public: LookupResult(TemporaryToken _, const LookupResult &Other) : ResultKind(NotFound), Paths(0), + NamingClass(0), SemaRef(Other.SemaRef), Name(Other.Name), NameLoc(Other.NameLoc), @@ -224,8 +224,8 @@ public: return Ambiguity; } - iterator begin() const { return Decls.begin(); } - iterator end() const { return Decls.end(); } + iterator begin() const { return iterator(Decls.begin()); } + iterator end() const { return iterator(Decls.end()); } /// \brief Return true if no decls were found bool empty() const { return Decls.empty(); } @@ -247,32 +247,57 @@ public: return IDNS; } - /// \brief Add a declaration to these results. Does not test the - /// acceptance criteria. + /// \brief Returns whether these results arose from performing a + /// lookup into a class. + bool isClassLookup() const { + return NamingClass != 0; + } + + /// \brief Returns the 'naming class' for this lookup, i.e. the + /// class which was looked into to find these results. + /// + /// C++0x [class.access.base]p5: + /// The access to a member is affected by the class in which the + /// member is named. This naming class is the class in which the + /// member name was looked up and found. [Note: this class can be + /// explicit, e.g., when a qualified-id is used, or implicit, + /// e.g., when a class member access operator (5.2.5) is used + /// (including cases where an implicit "this->" is added). If both + /// a class member access operator and a qualified-id are used to + /// name the member (as in p->T::m), the class naming the member + /// is the class named by the nested-name-specifier of the + /// qualified-id (that is, T). -- end note ] + /// + /// This is set by the lookup routines when they find results in a class. + CXXRecordDecl *getNamingClass() const { + return NamingClass; + } + + /// \brief Sets the 'naming class' for this lookup. + void setNamingClass(CXXRecordDecl *Record) { + NamingClass = Record; + } + + /// \brief Add a declaration to these results with its natural access. + /// Does not test the acceptance criteria. void addDecl(NamedDecl *D) { - Decls.push_back(D); + addDecl(D, D->getAccess()); + } + + /// \brief Add a declaration to these results with the given access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D, AccessSpecifier AS) { + Decls.addDecl(D, AS); ResultKind = Found; } /// \brief Add all the declarations from another set of lookup /// results. void addAllDecls(const LookupResult &Other) { - Decls.append(Other.begin(), Other.end()); + Decls.append(Other.Decls.begin(), Other.Decls.end()); ResultKind = Found; } - /// \brief Hides a set of declarations. - template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) { - unsigned I = 0, N = Decls.size(); - while (I < N) { - if (Set.count(Decls[I])) - Decls[I] = Decls[--N]; - else - I++; - } - Decls.set_size(N); - } - /// \brief Determine whether no result was found because we could not /// search into dependent base classes of the current instantiation. bool wasNotFoundInCurrentInstantiation() const { @@ -319,13 +344,13 @@ public: NamedDecl *getFoundDecl() const { assert(getResultKind() == Found && "getFoundDecl called on non-unique result"); - return Decls[0]->getUnderlyingDecl(); + return (*begin())->getUnderlyingDecl(); } /// Fetches a representative decl. Useful for lazy diagnostics. NamedDecl *getRepresentativeDecl() const { assert(!Decls.empty() && "cannot get representative of empty set"); - return Decls[0]; + return *begin(); } /// \brief Asks if the result is a single tag decl. @@ -403,7 +428,7 @@ public: /// sugared. class Filter { LookupResult &Results; - unsigned I; + LookupResult::iterator I; bool Changed; #ifndef NDEBUG bool CalledDone; @@ -411,7 +436,7 @@ public: friend class LookupResult; Filter(LookupResult &Results) - : Results(Results), I(0), Changed(false) + : Results(Results), I(Results.begin()), Changed(false) #ifndef NDEBUG , CalledDone(false) #endif @@ -426,23 +451,30 @@ public: #endif bool hasNext() const { - return I != Results.Decls.size(); + return I != Results.end(); } NamedDecl *next() { - assert(I < Results.Decls.size() && "next() called on empty filter"); - return Results.Decls[I++]; + assert(I != Results.end() && "next() called on empty filter"); + return *I++; } /// Erase the last element returned from this iterator. void erase() { - Results.Decls[--I] = Results.Decls.back(); - Results.Decls.pop_back(); + Results.Decls.erase(--I); Changed = true; } + /// Replaces the current entry with the given one, preserving the + /// access bits. void replace(NamedDecl *D) { - Results.Decls[I-1] = D; + Results.Decls.replace(I-1, D); + Changed = true; + } + + /// Replaces the current entry with the given one. + void replace(NamedDecl *D, AccessSpecifier AS) { + Results.Decls.replace(I-1, D, AS); Changed = true; } @@ -466,6 +498,8 @@ private: void diagnose() { if (isAmbiguous()) SemaRef.DiagnoseAmbiguousLookup(*this); + else if (isClassLookup() && SemaRef.getLangOptions().AccessControl) + SemaRef.CheckAccess(*this); } void setAmbiguous(AmbiguityKind AK) { @@ -482,7 +516,7 @@ private: assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || (Decls.size() == 1 && - isa<FunctionTemplateDecl>(Decls[0]->getUnderlyingDecl()))); + isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); @@ -492,8 +526,7 @@ private: } bool sanityCheckUnresolved() const { - for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end(); - I != E; ++I) + for (iterator I = begin(), E = end(); I != E; ++I) if (isa<UnresolvedUsingValueDecl>(*I)) return true; return false; @@ -504,8 +537,9 @@ private: // Results. LookupResultKind ResultKind; AmbiguityKind Ambiguity; // ill-defined unless ambiguous - DeclsTy Decls; + UnresolvedSet<8> Decls; CXXBasePaths *Paths; + CXXRecordDecl *NamingClass; // Parameters. Sema &SemaRef; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index fab7292..06e9e3a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1291,6 +1291,17 @@ public: ObjCContainerDecl* IDecl, bool IncompleteImpl = false); + /// DiagnoseUnimplementedProperties - This routine warns on those properties + /// which must be implemented by this implementation. + 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, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. @@ -1651,6 +1662,11 @@ public: virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + OwningExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *Ty, + SourceLocation RParenLoc, + ExprArg Op); + virtual bool TypeIsVectorType(TypeTy *Ty) { return GetTypeFromParser(Ty)->isVectorType(); } @@ -1658,13 +1674,18 @@ public: OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME); OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, SourceLocation RParenLoc, ExprArg E, - QualType Ty); + TypeSourceInfo *TInfo); virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + OwningExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, + SourceLocation RParenLoc, + ExprArg InitExpr); + virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, MultiExprArg InitList, SourceLocation RParenLoc); @@ -1920,6 +1941,13 @@ public: ExprArg E, SourceLocation RParenLoc); + OwningExprResult BuildCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + TypeSourceInfo *Ty, + ExprArg E, + SourceRange AngleBrackets, + SourceRange Parens); + /// ActOnCXXTypeid - Parse typeid( something ). virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, @@ -2033,7 +2061,6 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); - bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -2334,6 +2361,9 @@ public: CXXBasePaths &Paths, bool NoPrivileges = false); + void CheckAccess(const LookupResult &R); + bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access); + bool CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, CXXBasePaths& Paths, SourceLocation AccessLoc, @@ -3153,13 +3183,17 @@ public: /// relevant to this particular scope). LocalInstantiationScope *Outer; + /// \brief Whether we have already exited this scope. + bool Exited; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false) { if (!CombineWithOuterScope) SemaRef.CurrentInstantiationScope = this; else @@ -3168,7 +3202,15 @@ public: } ~LocalInstantiationScope() { + if (!Exited) + SemaRef.CurrentInstantiationScope = Outer; + } + + /// \brief Exit this local instantiation scope early. + void Exit() { SemaRef.CurrentInstantiationScope = Outer; + LocalDecls.clear(); + Exited = true; } Decl *getInstantiationOf(const Decl *D) { @@ -3215,7 +3257,16 @@ public: /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations; - void PerformPendingImplicitInstantiations(); + /// \brief The queue of implicit template instantiations that are required + /// and must be performed within the current local scope. + /// + /// This queue is only used for member functions of local classes in + /// templates, which must be instantiated in the same scope as their + /// enclosing function, so that they can reference function-local + /// types, static variables, enumerators, etc. + std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; + + void PerformPendingImplicitInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3300,6 +3351,7 @@ public: SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -3317,6 +3369,7 @@ public: SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -3327,6 +3380,7 @@ public: SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc); virtual DeclPtrTy ActOnStartClassImplementation( @@ -3373,14 +3427,13 @@ public: ObjCMethodDecl *MethodDecl, bool IsInstance); - void MergeProtocolPropertiesIntoClass(Decl *CDecl, - DeclPtrTy MergeProtocols); + void CompareProperties(Decl *CDecl, DeclPtrTy MergeProtocols); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); - void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, - ObjCProtocolDecl *PDecl); + void MatchOneProtocolPropertiesInClass(Decl *CDecl, + ObjCProtocolDecl *PDecl); virtual void ActOnAtEnd(SourceRange AtEnd, DeclPtrTy classDecl, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index b7cc37b..51f9e30 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -137,3 +138,101 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, return false; } + +/// Diagnose the path which caused the given declaration to become +/// inaccessible. +static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D, + AccessSpecifier Access) { + // Easy case: the decl's natural access determined its path access. + if (Access == D->getAccess() || D->getAccess() == AS_private) { + S.Diag(D->getLocation(), diag::note_access_natural) + << (unsigned) (Access == AS_protected); + return; + } + + // TODO: flesh this out + S.Diag(D->getLocation(), diag::note_access_constrained_by_path) + << (unsigned) (Access == AS_protected); +} + +/// Checks access to the given declaration in the current context. +/// +/// \param R the means via which the access was made; must have a naming +/// class set +/// \param D the declaration accessed +/// \param Access the best access along any inheritance path from the +/// naming class to the declaration. AS_none means the path is impossible +bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D, + AccessSpecifier Access) { + assert(R.getNamingClass() && "performing access check without naming class"); + + // If the access path is public, it's accessible everywhere. + if (Access == AS_public) + return false; + + // Otherwise, derive the current class context. + DeclContext *DC = CurContext; + while (isa<CXXRecordDecl>(DC) && + cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion()) + DC = DC->getParent(); + + CXXRecordDecl *CurRecord; + if (isa<CXXRecordDecl>(DC)) + CurRecord = cast<CXXRecordDecl>(DC); + else if (isa<CXXMethodDecl>(DC)) + CurRecord = cast<CXXMethodDecl>(DC)->getParent(); + else { + Diag(R.getNameLoc(), diag::err_access_outside_class) + << (Access == AS_protected); + DiagnoseAccessPath(*this, R, D, Access); + return true; + } + + CXXRecordDecl *NamingClass = R.getNamingClass(); + 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); + + // White-list accesses from within the declaring class. + if (Access != AS_none && + CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl()) + return false; + + // Protected access. + if (Access == AS_protected) { + // FIXME: implement [class.protected]p1 + if (CurRecord->isDerivedFrom(NamingClass)) + return false; + + // FIXME: dependent classes + } + + // FIXME: friends + + // Okay, it's a bad access, reject it. + + + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + + if (Access == AS_protected) { + Diag(R.getNameLoc(), diag::err_access_protected) + << Context.getTypeDeclType(DeclaringClass) + << Context.getTypeDeclType(CurRecord); + DiagnoseAccessPath(*this, R, D, Access); + return true; + } + + assert(Access == AS_private || Access == AS_none); + Diag(R.getNameLoc(), diag::err_access_private) + << Context.getTypeDeclType(DeclaringClass) + << Context.getTypeDeclType(CurRecord); + DiagnoseAccessPath(*this, R, D, Access); + return true; +} + +/// Checks access to all the declarations in the given result set. +void Sema::CheckAccess(const LookupResult &R) { + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + CheckAccess(R, *I, I.getAccess()); +} diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index f924bd3..57c4f9b 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -116,11 +116,26 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, ExprArg E, SourceLocation RParenLoc) { + + TypeSourceInfo *DestTInfo; + QualType DestType = GetTypeFromParser(Ty, &DestTInfo); + if (!DestTInfo) + DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation()); + + return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E), + SourceRange(LAngleBracketLoc, RAngleBracketLoc), + SourceRange(LParenLoc, RParenLoc)); +} + +Action::OwningExprResult +Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, + TypeSourceInfo *DestTInfo, ExprArg E, + SourceRange AngleBrackets, SourceRange Parens) { Expr *Ex = E.takeAs<Expr>(); - // FIXME: Preserve type source info. - QualType DestType = GetTypeFromParser(Ty); - SourceRange OpRange(OpLoc, RParenLoc); - SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc); + QualType DestType = DestTInfo->getType(); + + SourceRange OpRange(OpLoc, Parens.getEnd()); + SourceRange DestRange = AngleBrackets; // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? @@ -133,14 +148,14 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, if (!TypeDependent) CheckConstCast(*this, Ex, DestType, OpRange, DestRange); return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(), - Ex, DestType, OpLoc)); + Ex, DestTInfo, OpLoc)); case tok::kw_dynamic_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; if (!TypeDependent) CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } case tok::kw_reinterpret_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -148,7 +163,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context) CXXReinterpretCastExpr( DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } case tok::kw_static_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -169,7 +184,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, } return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 8594583..7a0b625 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -30,9 +30,9 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, if (T.isNull()) return 0; - T = Context.getCanonicalType(T); + T = Context.getCanonicalType(T).getUnqualifiedType(); - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { // If we've hit a namespace or the global scope, then the // nested-name-specifier can't refer to the current instantiation. if (Ctx->isFileContext()) @@ -210,28 +210,6 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { return getCurrentInstantiationOf(NNS) == 0; } -/// \brief Determine whether the given scope specifier refers to a -/// current instantiation that has any dependent base clases. -/// -/// This check is typically used when we've performed lookup into the -/// current instantiation of a template, but that lookup failed. When -/// there are dependent bases present, however, the lookup needs to be -/// delayed until template instantiation time. -bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) { - if (!SS.isSet()) - return false; - - NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep(); - if (!NNS->isDependent()) - return false; - - CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS); - if (!CurrentInstantiation) - return false; - - return CurrentInstantiation->hasAnyDependentBases(); -} - /// \brief If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 5f124e4..6ff8b1d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,14 +13,22 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" #include <limits> +#include <queue> using namespace clang; /// getLocationOfStringLiteralByte - Return a source location that points to the @@ -2029,3 +2037,522 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } +// MarkLive - Mark all the blocks reachable from e as live. Returns the total +// number of blocks just marked live. +static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) { + unsigned count = 0; + std::queue<CFGBlock*> workq; + // Prep work queue + live.set(e->getBlockID()); + ++count; + workq.push(e); + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + ++count; + workq.push(*I); + } + } + } + return count; +} + +static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1, + SourceRange &R2) { + Stmt *S; + unsigned sn = 0; + R1 = R2 = SourceRange(); + + top: + if (sn < b.size()) + S = b[sn].getStmt(); + else if (b.getTerminator()) + S = b.getTerminator(); + else + return SourceLocation(); + + switch (S->getStmtClass()) { + case Expr::BinaryOperatorClass: { + BinaryOperator *BO = cast<BinaryOperator>(S); + if (BO->getOpcode() == BinaryOperator::Comma) { + if (sn+1 < b.size()) + return b[sn+1].getStmt()->getLocStart(); + CFGBlock *n = &b; + while (1) { + if (n->getTerminator()) + return n->getTerminator()->getLocStart(); + if (n->succ_size() != 1) + return SourceLocation(); + n = n[0].succ_begin()[0]; + if (n->pred_size() != 1) + return SourceLocation(); + if (!n->empty()) + return n[0][0].getStmt()->getLocStart(); + } + } + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return BO->getOperatorLoc(); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(S); + R1 = UO->getSubExpr()->getSourceRange(); + return UO->getOperatorLoc(); + } + case Expr::CompoundAssignOperatorClass: { + const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); + R1 = CAO->getLHS()->getSourceRange(); + R2 = CAO->getRHS()->getSourceRange(); + return CAO->getOperatorLoc(); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(S); + return CO->getQuestionLoc(); + } + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(S); + R1 = ME->getSourceRange(); + return ME->getMemberLoc(); + } + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); + R1 = ASE->getLHS()->getSourceRange(); + R2 = ASE->getRHS()->getSourceRange(); + return ASE->getRBracketLoc(); + } + case Expr::CStyleCastExprClass: { + const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); + R1 = CSC->getSubExpr()->getSourceRange(); + return CSC->getLParenLoc(); + } + case Expr::CXXFunctionalCastExprClass: { + const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); + R1 = CE->getSubExpr()->getSourceRange(); + return CE->getTypeBeginLoc(); + } + case Expr::ImplicitCastExprClass: + ++sn; + goto top; + case Stmt::CXXTryStmtClass: { + return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); + } + default: ; + } + R1 = S->getSourceRange(); + return S->getLocStart(); +} + +static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, + SourceManager &SM) { + std::queue<CFGBlock*> workq; + // Prep work queue + workq.push(e); + SourceRange R1, R2; + SourceLocation top = GetUnreachableLoc(*e, R1, R2); + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + SourceLocation c = GetUnreachableLoc(*item, R1, R2); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } + live.set(item->getBlockID()); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + workq.push(*I); + } + } + } + return top; +} + +static int LineCmp(const void *p1, const void *p2) { + SourceLocation *Line1 = (SourceLocation *)p1; + SourceLocation *Line2 = (SourceLocation *)p2; + return !(*Line1 < *Line2); +} + +namespace { + struct ErrLoc { + SourceLocation Loc; + SourceRange R1; + SourceRange R2; + ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) + : Loc(l), R1(r1), R2(r2) { } + }; +} + +/// CheckUnreachable - Check for unreachable code. +void Sema::CheckUnreachable(AnalysisContext &AC) { + unsigned count; + // We avoid checking when there are errors, as the CFG won't faithfully match + // the user's code. + if (getDiagnostics().hasErrorOccurred()) + return; + if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) + return; + + CFG *cfg = AC.getCFG(); + if (cfg == 0) + return; + + llvm::BitVector live(cfg->getNumBlockIDs()); + // Mark all live things first. + count = MarkLive(&cfg->getEntry(), live); + + if (count == cfg->getNumBlockIDs()) + // If there are no dead blocks, we're done. + return; + + SourceRange R1, R2; + + llvm::SmallVector<ErrLoc, 24> lines; + bool AddEHEdges = AC.getAddEHEdges(); + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (!AddEHEdges && b.getTerminator() + && isa<CXXTryStmt>(b.getTerminator())) { + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += MarkLive(&b, live); + continue; + } + SourceLocation c = GetUnreachableLoc(b, R1, R2); + if (!c.isValid()) { + // Blocks without a location can't produce a warning, so don't mark + // reachable blocks from here as live. + live.set(b.getBlockID()); + ++count; + continue; + } + lines.push_back(ErrLoc(c, R1, R2)); + // Avoid excessive errors by marking everything reachable from here + count += MarkLive(&b, live); + } + } + } + + if (count < cfg->getNumBlockIDs()) { + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange())); + } + } + + llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); + for (llvm::SmallVector<ErrLoc, 24>::iterator I = lines.begin(), + E = lines.end(); + I != E; + ++I) + if (I->Loc.isValid()) + Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; +} + +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. +Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { + CFG *cfg = AC.getCFG(); + if (cfg == 0) + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; + + // The CFG leaves in dead things, and we don't want the dead code paths to + // confuse us, so we mark all live things first. + std::queue<CFGBlock*> workq; + llvm::BitVector live(cfg->getNumBlockIDs()); + unsigned count = MarkLive(&cfg->getEntry(), live); + + bool AddEHEdges = AC.getAddEHEdges(); + if (!AddEHEdges && count != cfg->getNumBlockIDs()) + // When there are things remaining dead, and we didn't add EH edges + // from CallExprs to the catch clauses, we have to go back and + // mark them as live. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += MarkLive(&b, live); + continue; + } + } + } + + // Now we know what is live, we check the live precessors of the exit block + // and look for fall through paths, being careful to ignore normal returns, + // and exceptional paths. + bool HasLiveReturn = false; + bool HasFakeEdge = false; + bool HasPlainEdge = false; + bool HasAbnormalEdge = false; + for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), + E = cfg->getExit().pred_end(); + I != E; + ++I) { + CFGBlock& B = **I; + if (!live[B.getBlockID()]) + continue; + if (B.size() == 0) { + if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { + HasAbnormalEdge = true; + continue; + } + + // A labeled empty statement, or the entry block... + HasPlainEdge = true; + continue; + } + Stmt *S = B[B.size()-1]; + if (isa<ReturnStmt>(S)) { + HasLiveReturn = true; + continue; + } + if (isa<ObjCAtThrowStmt>(S)) { + HasFakeEdge = true; + continue; + } + if (isa<CXXThrowExpr>(S)) { + HasFakeEdge = true; + continue; + } + if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { + if (AS->isMSAsm()) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } + } + if (isa<CXXTryStmt>(S)) { + HasAbnormalEdge = true; + continue; + } + + bool NoReturnEdge = false; + if (CallExpr *C = dyn_cast<CallExpr>(S)) { + if (B.succ_begin()[0] != &cfg->getExit()) { + HasAbnormalEdge = true; + continue; + } + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (CEE->getType().getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<NoReturnAttr>()) { + NoReturnEdge = true; + HasFakeEdge = true; + } + } + } + // FIXME: Add noreturn message sends. + if (NoReturnEdge == false) + HasPlainEdge = true; + } + if (!HasPlainEdge) { + if (HasLiveReturn) + return NeverFallThrough; + return NeverFallThroughOrReturn; + } + if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) + return MaybeFallThrough; + // This says AlwaysFallThrough for calls to functions that are not marked + // noreturn, that don't return. If people would like this warning to be more + // accurate, such functions should be marked as noreturn. + return AlwaysFallThrough; +} + +/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// function that should return a value. Check that we don't fall off the end +/// of a noreturn function. We assume that functions and blocks not marked +/// noreturn will return. +void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, + AnalysisContext &AC) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If the result type of the function is a dependent type, we don't know + // whether it will be void or not, so don't + if (FD->getResultType()->isDependentType()) + return; + if (FD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (MD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn) + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Function try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); + break; + case NeverFallThrough: + break; + } + } +} + +/// CheckFallThroughForBlock - Check that we don't fall off the end of a block +/// that should return a value. Check that we don't fall off the end of a +/// noreturn block. We assume that functions and blocks not marked noreturn +/// will return. +void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, + AnalysisContext &AC) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ + if (FT->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FT->getNoReturnAttr()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if (ReturnsVoid + && !HasNoReturn + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Funtion try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); + break; + case NeverFallThrough: + break; + } + } +} + +/// CheckParmsForFunctionDef - Check that the parameters of the given +/// function are appropriate for the definition of a function. This +/// takes care of any checks that cannot be performed on the +/// declaration itself, e.g., that the types of each of the function +/// parameters are complete. +bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { + bool HasInvalidParm = false; + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + + // C99 6.7.5.3p4: the parameters in a parameter type list in a + // function declarator that is part of a function definition of + // that function shall not have incomplete type. + // + // This is also C++ [dcl.fct]p6. + if (!Param->isInvalidDecl() && + RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) { + Param->setInvalidDecl(); + HasInvalidParm = true; + } + + // C99 6.9.1p5: If the declarator includes a parameter type list, the + // declaration of each parameter shall include an identifier. + if (Param->getIdentifier() == 0 && + !Param->isImplicit() && + !getLangOptions().CPlusPlus) + Diag(Param->getLocation(), diag::err_parameter_name_omitted); + } + + return HasInvalidParm; +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index a4cda01..fcd419b 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2234,30 +2234,36 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: What if we're calling a pseudo-destructor? // FIXME: What if we're calling a member function? + typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; + llvm::SmallVector<ResultCandidate, 8> Results; + Expr *NakedFn = Fn->IgnoreParenCasts(); if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet, /*PartialOverloading=*/ true); else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) { FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); - if (FDecl) - AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, - false, false, /*PartialOverloading*/ true); + if (FDecl) { + if (!FDecl->getType()->getAs<FunctionProtoType>()) + Results.push_back(ResultCandidate(FDecl)); + else + AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, + false, false, /*PartialOverloading*/ true); + } } - // Sort the overload candidate set by placing the best overloads first. - std::stable_sort(CandidateSet.begin(), CandidateSet.end(), - IsBetterOverloadCandidate(*this)); + if (!CandidateSet.empty()) { + // Sort the overload candidate set by placing the best overloads first. + std::stable_sort(CandidateSet.begin(), CandidateSet.end(), + IsBetterOverloadCandidate(*this)); - // Add the remaining viable overload candidates as code-completion reslults. - typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; - llvm::SmallVector<ResultCandidate, 8> Results; - - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - CandEnd = CandidateSet.end(); - Cand != CandEnd; ++Cand) { - if (Cand->Viable) - Results.push_back(ResultCandidate(Cand->Function)); + // Add the remaining viable overload candidates as code-completion reslults. + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) { + if (Cand->Viable) + Results.push_back(ResultCandidate(Cand->Function)); + } } if (Results.empty()) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0ccb8f2..fbe0289 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -18,13 +18,10 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/Analysis/CFG.h" #include "clang/AST/CXXInheritance.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Template.h" @@ -34,13 +31,10 @@ // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include <algorithm> #include <cstring> #include <functional> -#include <queue> using namespace clang; /// getDeclName - Return a pretty name for the specified decl if possible, or @@ -1305,382 +1299,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // Keep a chain of previous declarations. New->setPreviousDeclaration(Old); -} - -static void MarkLive(CFGBlock *e, llvm::BitVector &live) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } -} - -static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, - SourceManager &SM) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - SourceLocation top; - if (!e->empty()) - top = e[0][0].getStmt()->getLocStart(); - bool FromMainFile = false; - bool FromSystemHeader = false; - bool TopValid = false; - if (top.isValid()) { - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - TopValid = true; - } - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - SourceLocation c; - if (!item->empty()) - c = item[0][0].getStmt()->getLocStart(); - else if (item->getTerminator()) - c = item->getTerminator()->getLocStart(); - if (c.isValid() - && (!TopValid - || (SM.isFromMainFile(c) && !FromMainFile) - || (FromSystemHeader && !SM.isInSystemHeader(c)) - || SM.isBeforeInTranslationUnit(c, top))) { - top = c; - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - } - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } - return top; -} -namespace { -class LineCmp { - SourceManager &SM; -public: - LineCmp(SourceManager &sm) : SM(sm) { - } - bool operator () (SourceLocation l1, SourceLocation l2) { - return l1 < l2; - } -}; -} - -/// CheckUnreachable - Check for unreachable code. -void Sema::CheckUnreachable(AnalysisContext &AC) { - // We avoid checking when there are errors, as the CFG won't faithfully match - // the user's code. - if (getDiagnostics().hasErrorOccurred()) - return; - if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - CFG *cfg = AC.getCFG(); - if (cfg == 0) - return; - - llvm::BitVector live(cfg->getNumBlockIDs()); - // Mark all live things first. - MarkLive(&cfg->getEntry(), live); - - llvm::SmallVector<SourceLocation, 24> lines; - // First, give warnings for blocks with no predecessors, as they - // can't be part of a loop. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) { - if (b.pred_begin() == b.pred_end()) { - if (!b.empty()) - lines.push_back(b[0].getStmt()->getLocStart()); - else if (b.getTerminator()) - lines.push_back(b.getTerminator()->getLocStart()); - // Avoid excessive errors by marking everything reachable from here - MarkLive(&b, live); - } - } - } - - // And then give warnings for the tops of loops. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) - // Avoid excessive errors by marking everything reachable from here - lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager())); - } - - std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager())); - for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(), - E = lines.end(); - I != E; - ++I) - if (I->isValid()) - Diag(*I, diag::warn_unreachable); -} - -/// CheckFallThrough - Check that we don't fall off the end of a -/// Statement that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end, -/// NeverFallThroughOrReturn iff we never fall off the end of the statement or -/// return. We assume NeverFallThrough iff we never fall off the end of the -/// statement but we may return. We assume that functions not marked noreturn -/// will return. -Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { - CFG *cfg = AC.getCFG(); - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; - - // The CFG leaves in dead things, and we don't want to dead code paths to - // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; - llvm::BitVector live(cfg->getNumBlockIDs()); - MarkLive(&cfg->getEntry(), live); - - // Now we know what is live, we check the live precessors of the exit block - // and look for fall through paths, being careful to ignore normal returns, - // and exceptional paths. - bool HasLiveReturn = false; - bool HasFakeEdge = false; - bool HasPlainEdge = false; - for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), - E = cfg->getExit().pred_end(); - I != E; - ++I) { - CFGBlock& B = **I; - if (!live[B.getBlockID()]) - continue; - if (B.size() == 0) { - // A labeled empty statement, or the entry block... - HasPlainEdge = true; - continue; - } - Stmt *S = B[B.size()-1]; - if (isa<ReturnStmt>(S)) { - HasLiveReturn = true; - continue; - } - if (isa<ObjCAtThrowStmt>(S)) { - HasFakeEdge = true; - continue; - } - if (isa<CXXThrowExpr>(S)) { - HasFakeEdge = true; - continue; - } - if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { - if (AS->isMSAsm()) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } - } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (CEE->getType().getNoReturnAttr()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } - } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; - } - if (!HasPlainEdge) { - if (HasLiveReturn) - return NeverFallThrough; - return NeverFallThroughOrReturn; - } - if (HasFakeEdge || HasLiveReturn) - return MaybeFallThrough; - // This says AlwaysFallThrough for calls to functions that are not marked - // noreturn, that don't return. If people would like this warning to be more - // accurate, such functions should be marked as noreturn. - return AlwaysFallThrough; -} - -/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a -/// function that should return a value. Check that we don't fall off the end -/// of a noreturn function. We assume that functions and blocks not marked -/// noreturn will return. -void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // If the result type of the function is a dependent type, we don't know - // whether it will be void or not, so don't - if (FD->getResultType()->isDependentType()) - return; - if (FD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (MD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (MD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) - == Diagnostic::Ignored || ReturnsVoid) - && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) - == Diagnostic::Ignored || !HasNoReturn) - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Function try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckFallThroughForBlock - Check that we don't fall off the end of a block -/// that should return a value. Check that we don't fall off the end of a -/// noreturn block. We assume that functions and blocks not marked noreturn -/// will return. -void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ - if (FT->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FT->getNoReturnAttr()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if (ReturnsVoid - && !HasNoReturn - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Funtion try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckParmsForFunctionDef - Check that the parameters of the given -/// function are appropriate for the definition of a function. This -/// takes care of any checks that cannot be performed on the -/// declaration itself, e.g., that the types of each of the function -/// parameters are complete. -bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { - bool HasInvalidParm = false; - for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - - // C99 6.7.5.3p4: the parameters in a parameter type list in a - // function declarator that is part of a function definition of - // that function shall not have incomplete type. - // - // This is also C++ [dcl.fct]p6. - if (!Param->isInvalidDecl() && - RequireCompleteType(Param->getLocation(), Param->getType(), - diag::err_typecheck_decl_incomplete_type)) { - Param->setInvalidDecl(); - HasInvalidParm = true; - } - - // C99 6.9.1p5: If the declarator includes a parameter type list, the - // declaration of each parameter shall include an identifier. - if (Param->getIdentifier() == 0 && - !Param->isImplicit() && - !getLangOptions().CPlusPlus) - Diag(Param->getLocation(), diag::err_parameter_name_omitted); - } - - return HasInvalidParm; + // Inherit access appropriately. + New->setAccess(Old->getAccess()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with @@ -1773,6 +1394,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { /// \return true if this is a forbidden redeclaration static bool CheckAnonMemberRedeclaration(Sema &SemaRef, Scope *S, + DeclContext *Owner, DeclarationName Name, SourceLocation NameLoc, unsigned diagnostic) { @@ -1785,6 +1407,11 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); + if (PrevDecl && Owner->isRecord()) { + RecordDecl *Record = cast<RecordDecl>(Owner); + if (!SemaRef.isDeclInScope(PrevDecl, Record, S)) + return false; + } SemaRef.Diag(NameLoc, diagnostic) << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -1819,7 +1446,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(), + if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(), (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be @@ -3243,7 +2870,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Synthesize a parameter for each argument type. for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), AE = FT->arg_type_end(); AI != AE; ++AI) { - ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, + ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD, SourceLocation(), 0, *AI, /*TInfo=*/0, VarDecl::None, 0); @@ -3322,6 +2949,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { + // Fake up an access specifier if it's supposed to be a class member. + if (isa<CXXRecordDecl>(NewFD->getDeclContext())) + NewFD->setAccess(AS_public); + // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). // Note that this is not the case for explicit specializations of @@ -3332,7 +2963,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - } else if (!Redeclaration) { + } else if (!Redeclaration && + !(isFriend && CurContext->isDependentContext())) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, @@ -4236,8 +3868,13 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { QualType T = adjustParameterType(parmDeclType); + // Temporarily put parameter variables in the translation unit, not + // the enclosing context. This prevents them from accidentally + // looking like class members in C++. + DeclContext *DC = Context.getTranslationUnitDecl(); + ParmVarDecl *New - = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, + = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II, T, TInfo, StorageClass, 0); if (D.isInvalidType()) @@ -4476,7 +4113,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - AnalysisContext AC(dcl); + // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 + // explosion for destrutors that can result and the compile time hit. + AnalysisContext AC(dcl, false); FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); if (FunTmpl) @@ -6064,7 +5703,8 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, // Verify that there isn't already something declared with this name in this // scope. - NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName); + NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); @@ -6092,8 +5732,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, IdLoc, Id, Owned(Val)); // Register this decl in the current scope stack. - if (New) + if (New) { + New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); + } return DeclPtrTy::make(New); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a81a04e..9ec95f3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1062,8 +1062,23 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!TyD) { if (R.isAmbiguous()) return true; + if (SS.isSet() && isDependentScopeSpecifier(SS)) { + bool NotUnknownSpecialization = false; + DeclContext *DC = computeDeclContext(SS, false); + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC)) + NotUnknownSpecialization = !Record->hasAnyDependentBases(); + + if (!NotUnknownSpecialization) { + // When the scope specifier can refer to a member of an unknown + // specialization, we take it as a type name. + BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + *MemberOrBase, SS.getRange()); + R.clear(); + } + } + // If no results were found, try to correct typos. - if (R.empty() && + if (R.empty() && BaseType.isNull() && CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { @@ -1106,20 +1121,22 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, } } - if (!TyD) { + if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); return true; } } - BaseType = Context.getTypeDeclType(TyD); - if (SS.isSet()) { - NestedNameSpecifier *Qualifier = - static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + if (BaseType.isNull()) { + BaseType = Context.getTypeDeclType(TyD); + if (SS.isSet()) { + NestedNameSpecifier *Qualifier = + static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - // FIXME: preserve source range information - BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + // FIXME: preserve source range information + BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + } } } @@ -4470,9 +4487,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); OverloadCandidateSet CandidateSet; - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); @@ -5594,26 +5611,24 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType(); QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType(); - QualType CNewTy = Context.getCanonicalType(NewTy); - QualType COldTy = Context.getCanonicalType(OldTy); - - if (CNewTy == COldTy && - CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers()) + if (Context.hasSameType(NewTy, OldTy)) return false; // Check if the return types are covariant QualType NewClassTy, OldClassTy; /// Both types must be pointers or references to classes. - if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) { - if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) { + if (const PointerType *NewPT = NewTy->getAs<PointerType>()) { + if (const PointerType *OldPT = OldTy->getAs<PointerType>()) { NewClassTy = NewPT->getPointeeType(); OldClassTy = OldPT->getPointeeType(); } - } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) { - if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) { - NewClassTy = NewRT->getPointeeType(); - OldClassTy = OldRT->getPointeeType(); + } else if (const ReferenceType *NewRT = NewTy->getAs<ReferenceType>()) { + if (const ReferenceType *OldRT = OldTy->getAs<ReferenceType>()) { + if (NewRT->getTypeClass() == OldRT->getTypeClass()) { + NewClassTy = NewRT->getPointeeType(); + OldClassTy = OldRT->getPointeeType(); + } } } @@ -5661,7 +5676,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // The qualifiers of the return types must be the same. - if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) { + if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) { Diag(New->getLocation(), diag::err_covariant_return_type_different_qualifications) << New->getDeclName() << NewTy << OldTy; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f2fc1f4..1b07d19 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -81,6 +81,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { assert(ClassName && "Missing class identifier"); @@ -201,7 +202,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, /// Check then save referenced protocols. if (NumProtoRefs) { IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, - Context); + ProtoLocs, Context); IDecl->setLocEnd(EndProtoLoc); } @@ -279,6 +280,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { // FIXME: Deal with AttrList. @@ -312,7 +314,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, ProcessDeclAttributeList(TUScope, PDecl, AttrList); if (NumProtoRefs) { /// Check then save referenced protocols. - PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); + PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + ProtoLocs, Context); PDecl->setLocEnd(EndProtoLoc); } @@ -432,17 +435,17 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { } } -/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list -/// of properties declared in a protocol and adds them to the list -/// of properties for current class/category if it is not there already. +/// 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::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, +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 && "MergeOneProtocolPropertiesIntoClass"); + assert (CatDecl && "MatchOneProtocolPropertiesInClass"); for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { ObjCPropertyDecl *Pr = (*P); @@ -471,35 +474,35 @@ Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, } } -/// MergeProtocolPropertiesIntoClass - This routine merges properties -/// declared in 'MergeItsProtocols' objects (which can be a class or an -/// inherited protocol into the list of properties for class/category 'CDecl' +/// 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::MergeProtocolPropertiesIntoClass(Decl *CDecl, - DeclPtrTy MergeItsProtocols) { - Decl *ClassDecl = MergeItsProtocols.getAs<Decl>(); +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 && "MergeProtocolPropertiesIntoClass"); + 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) - // Merge properties of category (*P) into IDECL's - MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + // Match properties of category with those of protocol (*P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); - // Go thru the list of protocols for this category and recursively merge - // their properties into this class as well. + // 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) - MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*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) - MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + MatchOneProtocolPropertiesInClass(CatDecl, *P); } return; } @@ -507,19 +510,19 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), E = MDecl->protocol_end(); P != E; ++P) - // Merge properties of class (*P) into IDECL's - MergeOneProtocolPropertiesIntoClass(IDecl, *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 merge - // their properties into this class as well. + // 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) - MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*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) - MergeOneProtocolPropertiesIntoClass(IDecl, *P); + MatchOneProtocolPropertiesInClass(IDecl, *P); } } @@ -559,6 +562,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, unsigned NumElts, AttributeList *attrList) { llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; + llvm::SmallVector<SourceLocation, 8> ProtoLocs; for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; @@ -571,11 +575,13 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, if (attrList) ProcessDeclAttributeList(TUScope, PDecl, attrList); Protocols.push_back(PDecl); + ProtoLocs.push_back(IdentList[i].second); } ObjCForwardProtocolDecl *PDecl = ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc, - &Protocols[0], Protocols.size()); + Protocols.data(), Protocols.size(), + ProtoLocs.data()); CurContext->addDecl(PDecl); CheckObjCDeclScope(PDecl); return DeclPtrTy::make(PDecl); @@ -588,9 +594,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = - ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName); + ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, + CategoryLoc, CategoryName); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -623,12 +631,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, - Context); - CDecl->setLocEnd(EndProtoLoc); + ProtoLocs, Context); // Protocols in the class extension belong to the class. if (!CDecl->getIdentifier()) IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, - NumProtoRefs,Context); + NumProtoRefs, ProtoLocs, + Context); } CheckObjCDeclScope(CDecl); @@ -650,6 +658,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( // Category @implementation with no corresponding @interface. // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), SourceLocation(), CatName); CatIDecl->setClassInterface(IDecl); CatIDecl->insertNextClassCategory(); @@ -1077,6 +1086,92 @@ 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)) { + 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); + } +} + +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 (!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) { @@ -1091,39 +1186,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. if (isa<ObjCInterfaceDecl>(CDecl)) - for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(), - E = CDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->isInvalidDecl()) - continue; - ObjCPropertyImplDecl *PI = 0; - // Is there a matching propery synthesize/dynamic? - for (ObjCImplDecl::propimpl_iterator - I = IMPDecl->propimpl_begin(), - EI = IMPDecl->propimpl_end(); I != EI; ++I) - if ((*I)->getPropertyDecl() == Prop) { - PI = (*I); - break; - } - if (PI) - continue; - if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), - 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(), - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - } - + DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + llvm::DenseSet<Selector> ClsMap; for (ObjCImplementationDecl::classmeth_iterator I = IMPDecl->classmeth_begin(), @@ -1163,7 +1227,18 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, C->getClassInterface()); - } + // Report unimplemented properties in the category as well. + // When reporting on missing setter/getters, do not report when + // setter/getter is implemented in category's primary class + // implementation. + if (ObjCInterfaceDecl *ID = C->getClassInterface()) + if (ObjCImplDecl *IMP = ID->getImplementation()) { + for (ObjCImplementationDecl::instmeth_iterator + I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + } + DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + } } else assert(false && "invalid ObjCContainerDecl type."); } @@ -1694,14 +1769,14 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, // Compares properties declared in this class to those of its // super class. ComparePropertiesInBaseAndSuper(I); - MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I)); + CompareProperties(I, DeclPtrTy::make(I)); } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { // Categories are used to extend the class by declaring new methods. // By the same token, they are also used to add new properties. No // need to compare the added property to those in the class. - // Merge protocol properties into category - MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C)); + // Compare protocol properties with those in category + CompareProperties(C, DeclPtrTy::make(C)); if (C->getIdentifier() == 0) DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); } @@ -2111,7 +2186,8 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, assert(DC && "ClassDecl is not a DeclContext"); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), T); + 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); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 034accd..50976f7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3082,15 +3082,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); - if (Getter || Setter) { + if (Getter) { 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. + PType = Getter->getResultType(); return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } @@ -3663,11 +3657,21 @@ Action::OwningExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg InitExpr) { assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); - - QualType literalType = GetTypeFromParser(Ty); - // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); + + TypeSourceInfo *TInfo; + QualType literalType = GetTypeFromParser(Ty, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(literalType); + + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, move(InitExpr)); +} + +Action::OwningExprResult +Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, + SourceLocation RParenLoc, ExprArg InitExpr) { + QualType literalType = TInfo->getType(); Expr *literalExpr = static_cast<Expr*>(InitExpr.get()); if (literalType->isArrayType()) { @@ -3703,8 +3707,7 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, Result.release(); - // FIXME: Store the TInfo to preserve type information better. - return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType, + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, literalExpr, isFileScope)); } @@ -3906,26 +3909,38 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, Action::OwningExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op) { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - assert((Ty != 0) && (Op.get() != 0) && "ActOnCastExpr(): missing type or expr"); - Expr *castExpr = (Expr *)Op.get(); - //FIXME: Preserve type source info. - QualType castType = GetTypeFromParser(Ty); + TypeSourceInfo *castTInfo; + QualType castType = GetTypeFromParser(Ty, &castTInfo); + if (!castTInfo) + castTInfo = Context.getTrivialTypeSourceInfo(castType); // If the Expr being casted is a ParenListExpr, handle it specially. + Expr *castExpr = (Expr *)Op.get(); if (isa<ParenListExpr>(castExpr)) - return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType); + return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op), + castTInfo); + + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, move(Op)); +} + +Action::OwningExprResult +Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, + SourceLocation RParenLoc, ExprArg Op) { + Expr *castExpr = static_cast<Expr*>(Op.get()); + CXXMethodDecl *Method = 0; - if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr, + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, Kind, Method)) return ExprError(); if (Method) { - OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind, - Method, move(Op)); + // FIXME: preserve type source info here + OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(), + Kind, Method, move(Op)); if (CastArg.isInvalid()) return ExprError(); @@ -3935,8 +3950,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, Op.release(); } - return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(), - Kind, castExpr, castType, + return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(), + Kind, castExpr, Ty, LParenLoc, RParenLoc)); } @@ -3961,8 +3976,9 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) { Action::OwningExprResult Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, SourceLocation RParenLoc, ExprArg Op, - QualType Ty) { + TypeSourceInfo *TInfo) { ParenListExpr *PE = (ParenListExpr *)Op.get(); + QualType Ty = TInfo->getType(); // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. @@ -3982,13 +3998,12 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0], initExprs.size(), RParenLoc); E->setType(Ty); - return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc, - Owned(E)); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E)); } else { // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. Op = MaybeConvertParenListExprToParenExpr(S, move(Op)); - return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, move(Op)); } } @@ -4702,8 +4717,9 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, // Build a compound literal constructing a value of the transparent // union type from this initializer list. - E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer, - false); + TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType); + E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, + Initializer, false); } Sema::AssignConvertType @@ -6785,10 +6801,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), - E = CurBlock->TheDecl->param_end(); AI != E; ++AI) + E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { + (*AI)->setOwningFunction(CurBlock->TheDecl); + // If this has an identifier, add it to the scope stack. if ((*AI)->getIdentifier()) PushOnScopeChains(*AI, CurBlock->TheScope); + } // Check for a valid sentinel attribute on this block. if (!CurBlock->isVariadic && @@ -6868,6 +6887,26 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); + + bool Good = true; + // Check goto/label use. + for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator + I = BSI->LabelMap.begin(), E = BSI->LabelMap.end(); I != E; ++I) { + LabelStmt *L = I->second; + + // Verify that we have no forward references left. If so, there was a goto + // or address of a label taken, but no definition of it. + if (L->getSubStmt() != 0) + continue; + + // Emit error. + Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); + Good = false; + } + BSI->LabelMap.clear(); + if (!Good) + return ExprError(); + AnalysisContext AC(BSI->TheDecl); CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); CheckUnreachable(AC); @@ -7203,8 +7242,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { AlreadyInstantiated = true; } - if (!AlreadyInstantiated) - PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); + 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, + Loc)); + } } // FIXME: keep track of references to static functions diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d10e11f..b004fc3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -196,8 +196,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(TypeRep && "Missing type!"); - // FIXME: Preserve type source info. - QualType Ty = GetTypeFromParser(TypeRep); + TypeSourceInfo *TInfo; + QualType Ty = GetTypeFromParser(TypeRep, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); SourceLocation TyBeginLoc = TypeRange.getBegin(); @@ -252,7 +254,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, } return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), - Ty, TyBeginLoc, Kind, + TInfo, TyBeginLoc, Kind, Exprs[0], RParenLoc)); } @@ -891,9 +893,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *Record = Type->getAs<RecordType>()) { llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions(); + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { // Skip over templated conversion functions; they aren't considered. if (isa<FunctionTemplateDecl>(*I)) @@ -1448,12 +1450,14 @@ QualType Sema::CheckPointerToMemberOperands( // overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { - const char *ReplaceStr = isIndirect ? ".*" : "->*"; Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex->getType() << - CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr); + << (int)isIndirect << lex->getType(); return QualType(); } + // Cast LHS to type of use. + QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; + bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid; + ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue); } if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 85889fa..ea8f4e3 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -398,7 +398,17 @@ Sema::ExprResult Sema::ActOnClassMessage( return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, selectorLoc, rbrac, Args, NumArgs); } - return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; + else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) { + const ObjCInterfaceType *OCIT; + OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>(); + if (!OCIT) { + Diag(receiverLoc, diag::err_invalid_receiver_to_message); + return true; + } + ClassDecl = OCIT->getDecl(); + } + else + return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; } } else ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1970f56..fd62e1a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -382,7 +382,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (hadError) return; - if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement) + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement || + ElementEntity.getKind() == InitializedEntity::EK_VectorElement) ElementEntity.setElementIndex(Init); if (Init >= NumInits || !ILE->getInit(Init)) { @@ -1828,12 +1829,15 @@ bool Sema::CheckInitList(const InitializedEntity &Entity, InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent) - : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index) + : Parent(&Parent), Index(Index) { - if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) + if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { + Kind = EK_ArrayElement; Type = AT->getElementType(); - else + } else { + Kind = EK_VectorElement; Type = Parent.getType()->getAs<VectorType>()->getElementType(); + } } InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, @@ -1862,7 +1866,8 @@ DeclarationName InitializedEntity::getName() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_ArrayOrVectorElement: + case EK_ArrayElement: + case EK_VectorElement: return DeclarationName(); } @@ -1882,7 +1887,8 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_ArrayOrVectorElement: + case EK_ArrayElement: + case EK_VectorElement: return 0; } @@ -2141,11 +2147,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // refers to. QualType ToType = AllowRValues? cv1T1 : DestType; - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), - E = Conversions->end(); - I != E; ++I) { + for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) @@ -2662,9 +2667,9 @@ static void TryUserDefinedConversion(Sema &S, CXXRecordDecl *SourceRecordDecl = cast<CXXRecordDecl>(SourceRecordType->getDecl()); - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = SourceRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; @@ -2917,7 +2922,8 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Casting; case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: return Sema::AA_Initializing; } @@ -2935,7 +2941,8 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity, case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: return false; case InitializedEntity::EK_Parameter: @@ -2981,7 +2988,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, case InitializedEntity::EK_Temporary: case InitializedEntity::EK_Base: case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: // We don't need to copy for any of these initialized entities. return move(CurInit); } diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 5eb819a..d7d3756 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -47,6 +47,11 @@ public: /// \brief The entity being initialized is an exception object that /// is being thrown. EK_Exception, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member, + /// \brief The entity being initialized is an element of an array. + EK_ArrayElement, /// \brief The entity being initialized is an object (or array of /// objects) allocated via new. EK_New, @@ -54,12 +59,10 @@ public: EK_Temporary, /// \brief The entity being initialized is a base member subobject. EK_Base, - /// \brief The entity being initialized is a non-static data member - /// subobject. - EK_Member, - /// \brief The entity being initialized is an element of an array + /// \brief The entity being initialized is an element of a vector. /// or vector. - EK_ArrayOrVectorElement + EK_VectorElement + }; private: @@ -211,7 +214,7 @@ public: /// \brief If this is already the initializer for an array or vector /// element, sets the element index. void setElementIndex(unsigned Index) { - assert(getKind() == EK_ArrayOrVectorElement); + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement); this->Index = Index; } }; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index cda245d..f5d2a7d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -317,16 +317,16 @@ void LookupResult::resolveKind() { // Fast case: no possible ambiguity. if (N == 0) { - assert(ResultKind == NotFound); + assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); return; } // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { - if (isa<FunctionTemplateDecl>(Decls[0])) + if (isa<FunctionTemplateDecl>(*Decls.begin())) ResultKind = FoundOverloaded; - else if (isa<UnresolvedUsingValueDecl>(Decls[0])) + else if (isa<UnresolvedUsingValueDecl>(*Decls.begin())) ResultKind = FoundUnresolvedValue; return; } @@ -445,8 +445,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { - if (R.isAcceptableDecl(*I)) { - R.addDecl(*I); + NamedDecl *D = *I; + if (R.isAcceptableDecl(D)) { + R.addDecl(D); Found = true; } } @@ -463,10 +464,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { if (!Record->isDefinition()) return Found; - const UnresolvedSet *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSet::iterator U = Unresolved->begin(), - UEnd = Unresolved->end(); - U != UEnd; ++U) { + const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); if (!ConvTemplate) continue; @@ -967,6 +967,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Perform qualified name lookup into the LookupCtx. if (LookupDirect(R, LookupCtx)) { R.resolveKind(); + if (isa<CXXRecordDecl>(LookupCtx)) + R.setNamingClass(cast<CXXRecordDecl>(LookupCtx)); return true; } @@ -1039,6 +1041,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, R.getLookupName().getAsOpaquePtr(), Paths)) return false; + R.setNamingClass(LookupRec); + // C++ [class.member.lookup]p2: // [...] If the resulting set of declarations are not all from // sub-objects of the same type, or the set has a nonstatic member @@ -1048,10 +1052,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; + AccessSpecifier SubobjectAccess = AS_private; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); + // Pick the best (i.e. most permissive i.e. numerically lowest) access + // across all paths. + SubobjectAccess = std::min(SubobjectAccess, Path->Access); + // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. @@ -1106,8 +1115,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Lookup in a base class succeeded; return these results. DeclContext::lookup_iterator I, E; - for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) - R.addDecl(*I); + for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) { + NamedDecl *D = *I; + AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, + D->getAccess()); + R.addDecl(D, AS); + } R.resolveKind(); return true; } @@ -1243,7 +1256,12 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { Diag((*DI)->getLocation(), diag::note_hiding_object); // For recovery purposes, go ahead and implement the hiding. - Result.hideDecls(TagDecls); + LookupResult::Filter F = Result.makeFilter(); + while (F.hasNext()) { + if (TagDecls.count(F.next())) + F.erase(); + } + F.done(); return true; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6ec4d1b..44a8f15 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -25,7 +25,6 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> -#include <cstdio> namespace clang { @@ -183,51 +182,53 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// DebugPrint - Print this standard conversion sequence to standard /// error. Useful for debugging overloading issues. void StandardConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); bool PrintedSomething = false; if (First != ICK_Identity) { - fprintf(stderr, "%s", GetImplicitConversionName(First)); + OS << GetImplicitConversionName(First); PrintedSomething = true; } if (Second != ICK_Identity) { if (PrintedSomething) { - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "%s", GetImplicitConversionName(Second)); + OS << GetImplicitConversionName(Second); if (CopyConstructor) { - fprintf(stderr, " (by copy constructor)"); + OS << " (by copy constructor)"; } else if (DirectBinding) { - fprintf(stderr, " (direct reference binding)"); + OS << " (direct reference binding)"; } else if (ReferenceBinding) { - fprintf(stderr, " (reference binding)"); + OS << " (reference binding)"; } PrintedSomething = true; } if (Third != ICK_Identity) { if (PrintedSomething) { - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "%s", GetImplicitConversionName(Third)); + OS << GetImplicitConversionName(Third); PrintedSomething = true; } if (!PrintedSomething) { - fprintf(stderr, "No conversions required"); + OS << "No conversions required"; } } /// DebugPrint - Print this user-defined conversion sequence to standard /// error. Useful for debugging overloading issues. void UserDefinedConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); if (Before.First || Before.Second || Before.Third) { Before.DebugPrint(); - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str()); + OS << "'" << ConversionFunction->getNameAsString() << "'"; if (After.First || After.Second || After.Third) { - fprintf(stderr, " -> "); + OS << " -> "; After.DebugPrint(); } } @@ -235,27 +236,28 @@ void UserDefinedConversionSequence::DebugPrint() const { /// DebugPrint - Print this implicit conversion sequence to standard /// error. Useful for debugging overloading issues. void ImplicitConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); switch (ConversionKind) { case StandardConversion: - fprintf(stderr, "Standard conversion: "); + OS << "Standard conversion: "; Standard.DebugPrint(); break; case UserDefinedConversion: - fprintf(stderr, "User-defined conversion: "); + OS << "User-defined conversion: "; UserDefined.DebugPrint(); break; case EllipsisConversion: - fprintf(stderr, "Ellipsis conversion"); + OS << "Ellipsis conversion"; break; case AmbiguousConversion: - fprintf(stderr, "Ambiguous conversion"); + OS << "Ambiguous conversion"; break; case BadConversion: - fprintf(stderr, "Bad conversion"); + OS << "Bad conversion"; break; } - fprintf(stderr, "\n"); + OS << "\n"; } void AmbiguousConversionSequence::construct() { @@ -1100,7 +1102,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, bool &IncompatibleObjC) { if (!getLangOptions().ObjC1) return false; - + // First, we handle all conversions on ObjC object pointer types. const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *FromObjCPtr = @@ -1141,8 +1143,23 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, QualType ToPointeeType; if (const PointerType *ToCPtr = ToType->getAs<PointerType>()) ToPointeeType = ToCPtr->getPointeeType(); - else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>()) + else if (const BlockPointerType *ToBlockPtr = + ToType->getAs<BlockPointerType>()) { + // Objective C++: We're able to convert from a pointer to any object + // to a block pointer type. + if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) { + ConvertedType = ToType; + return true; + } ToPointeeType = ToBlockPtr->getPointeeType(); + } + else if (FromType->getAs<BlockPointerType>() && + ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { + // Objective C++: We're able to convert from a block pointer type to a + // pointer to any object. + ConvertedType = ToType; + return true; + } else return false; @@ -1164,6 +1181,16 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = ToType; return true; } + // Allow conversion of pointee being objective-c pointer to another one; + // as in I* to id. + if (FromPointeeType->getAs<ObjCObjectPointerType>() && + ToPointeeType->getAs<ObjCObjectPointerType>() && + isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, + IncompatibleObjC)) { + ConvertedType = ToType; + return true; + } + // If we have pointers to functions or blocks, check whether the only // differences in the argument and result types are in Objective-C // pointer conversions. If so, we permit the conversion (but @@ -1523,9 +1550,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (CXXRecordDecl *FromRecordDecl = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = FromRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); @@ -2756,7 +2783,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.FailureKind = ovl_fail_trivial_conversion; return; } @@ -2794,7 +2821,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, case ImplicitConversionSequence::BadConversion: Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.FailureKind = ovl_fail_bad_final_conversion; break; default: @@ -2869,6 +2896,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.Conversions[0] = ObjectInit; return; } @@ -3270,9 +3298,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { // Skip conversion function templates; they don't tell us anything @@ -3334,10 +3362,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSet *Conversions = + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) { QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); @@ -4386,7 +4414,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { QualType FromTy = Conv.Bad.getFromType(); QualType ToTy = Conv.Bad.getToType(); - // Do some hand-waving analysis to see if the non-viability is due to a + // Do some hand-waving analysis to see if the non-viability is due + // to a qualifier mismatch. CanQualType CFromTy = S.Context.getCanonicalType(FromTy); CanQualType CToTy = S.Context.getCanonicalType(ToTy); if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>()) @@ -4436,6 +4465,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + // Diagnose references or pointers to incomplete types differently, + // since it's far from impossible that the incompleteness triggered + // the failure. + QualType TempFromTy = FromTy.getNonReferenceType(); + if (const PointerType *PTy = TempFromTy->getAs<PointerType>()) + TempFromTy = PTy->getPointeeType(); + if (TempFromTy->isIncompleteType()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + return; + } + // TODO: specialize more based on the kind of mismatch S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) << (unsigned) FnKind << FnDesc @@ -4503,6 +4546,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: + case ovl_fail_trivial_conversion: + case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); case ovl_fail_bad_conversion: @@ -4582,12 +4627,23 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, } } +SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { + if (Cand->Function) + return Cand->Function->getLocation(); + if (Cand->IsSurrogate) + return Cand->Surrogate->getLocation(); + return SourceLocation(); +} + struct CompareOverloadCandidatesForDisplay { Sema &S; CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} bool operator()(const OverloadCandidate *L, const OverloadCandidate *R) { + // Fast-path this check. + if (L == R) return false; + // Order first by viability. if (L->Viable) { if (!R->Viable) return true; @@ -4600,25 +4656,132 @@ struct CompareOverloadCandidatesForDisplay { } else if (R->Viable) return false; - // Put declared functions first. - if (L->Function) { - if (!R->Function) return true; - return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(), - R->Function->getLocation()); - } else if (R->Function) return false; - - // Then surrogates. - if (L->IsSurrogate) { - if (!R->IsSurrogate) return true; - return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(), - R->Surrogate->getLocation()); - } else if (R->IsSurrogate) return false; - - // And builtins just come in a jumble. - return false; + assert(L->Viable == R->Viable); + + // Criteria by which we can sort non-viable candidates: + if (!L->Viable) { + // 1. Arity mismatches come after other candidates. + if (L->FailureKind == ovl_fail_too_many_arguments || + L->FailureKind == ovl_fail_too_few_arguments) + return false; + if (R->FailureKind == ovl_fail_too_many_arguments || + R->FailureKind == ovl_fail_too_few_arguments) + return true; + + // 2. Bad conversions come first and are ordered by the number + // of bad conversions and quality of good conversions. + if (L->FailureKind == ovl_fail_bad_conversion) { + if (R->FailureKind != ovl_fail_bad_conversion) + return true; + + // If there's any ordering between the defined conversions... + // FIXME: this might not be transitive. + assert(L->Conversions.size() == R->Conversions.size()); + + int leftBetter = 0; + for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) { + switch (S.CompareImplicitConversionSequences(L->Conversions[I], + R->Conversions[I])) { + case ImplicitConversionSequence::Better: + leftBetter++; + break; + + case ImplicitConversionSequence::Worse: + leftBetter--; + break; + + case ImplicitConversionSequence::Indistinguishable: + break; + } + } + if (leftBetter > 0) return true; + if (leftBetter < 0) return false; + + } else if (R->FailureKind == ovl_fail_bad_conversion) + return false; + + // TODO: others? + } + + // Sort everything else by location. + SourceLocation LLoc = GetLocationForCandidate(L); + SourceLocation RLoc = GetLocationForCandidate(R); + + // Put candidates without locations (e.g. builtins) at the end. + if (LLoc.isInvalid()) return false; + if (RLoc.isInvalid()) return true; + + return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc); } }; +/// CompleteNonViableCandidate - Normally, overload resolution only +/// computes up to the first +void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + assert(!Cand->Viable); + + // Don't do anything on failures other than bad conversion. + if (Cand->FailureKind != ovl_fail_bad_conversion) return; + + // Skip forward to the first bad conversion. + unsigned ConvIdx = 0; + unsigned ConvCount = Cand->Conversions.size(); + while (true) { + assert(ConvIdx != ConvCount && "no bad conversion in candidate"); + ConvIdx++; + if (Cand->Conversions[ConvIdx - 1].isBad()) + break; + } + + if (ConvIdx == ConvCount) + return; + + // FIXME: these should probably be preserved from the overload + // operation somehow. + bool SuppressUserConversions = false; + bool ForceRValue = false; + + const FunctionProtoType* Proto; + unsigned ArgIdx = ConvIdx; + + if (Cand->IsSurrogate) { + QualType ConvType + = Cand->Surrogate->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); + Proto = ConvType->getAs<FunctionProtoType>(); + ArgIdx--; + } else if (Cand->Function) { + Proto = Cand->Function->getType()->getAs<FunctionProtoType>(); + if (isa<CXXMethodDecl>(Cand->Function) && + !isa<CXXConstructorDecl>(Cand->Function)) + ArgIdx--; + } else { + // Builtin binary operator with a bad first conversion. + assert(ConvCount <= 3); + for (; ConvIdx != ConvCount; ++ConvIdx) + Cand->Conversions[ConvIdx] + = S.TryCopyInitialization(Args[ConvIdx], + Cand->BuiltinTypes.ParamTypes[ConvIdx], + SuppressUserConversions, ForceRValue, + /*InOverloadResolution*/ true); + return; + } + + // Fill in the rest of the conversions. + unsigned NumArgsInProto = Proto->getNumArgs(); + for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { + if (ArgIdx < NumArgsInProto) + Cand->Conversions[ConvIdx] + = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx), + SuppressUserConversions, ForceRValue, + /*InOverloadResolution=*/true); + else + Cand->Conversions[ConvIdx].setEllipsis(); + } +} + } // end anonymous namespace /// PrintOverloadCandidates - When overload resolution fails, prints @@ -4636,9 +4799,15 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size()); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), LastCand = CandidateSet.end(); - Cand != LastCand; ++Cand) - if (Cand->Viable || OCD == OCD_AllCandidates) + Cand != LastCand; ++Cand) { + if (Cand->Viable) Cands.push_back(Cand); + else if (OCD == OCD_AllCandidates) { + CompleteNonViableCandidate(*this, Cand, Args, NumArgs); + Cands.push_back(Cand); + } + } + std::sort(Cands.begin(), Cands.end(), CompareOverloadCandidatesForDisplay(*this)); @@ -5909,9 +6078,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 20add00..f8353e3 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -390,7 +390,16 @@ namespace clang { ovl_fail_too_many_arguments, ovl_fail_too_few_arguments, ovl_fail_bad_conversion, - ovl_fail_bad_deduction + ovl_fail_bad_deduction, + + /// This conversion candidate was not considered because it + /// duplicates the work of a trivial or derived-to-base + /// conversion. + ovl_fail_trivial_conversion, + + /// This conversion candidate is not viable because its result + /// type is not implicitly convertible to the desired type. + ovl_fail_bad_final_conversion }; /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 7855a7f..0c207fa 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -412,10 +412,10 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions; llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions; if (const RecordType *RecordTy = CondType->getAs<RecordType>()) { - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl()) ->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I)) if (Conversion->getConversionType().getNonReferenceType() @@ -879,10 +879,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Action::OwningStmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, IdentifierInfo *LabelII) { - // If we are in a block, reject all gotos for now. - if (CurBlock) - return StmtError(Diag(GotoLoc, diag::err_goto_in_block)); - // Look up the record for this label identifier. LabelStmt *&LabelDecl = getLabelMap()[LabelII]; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 2fad832..0040156 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -449,8 +449,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, Loc = KeyLoc; TemplateTypeParmDecl *Param - = TemplateTypeParmDecl::Create(Context, CurContext, Loc, - Depth, Position, ParamName, Typename, + = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), + Loc, Depth, Position, ParamName, Typename, Ellipsis); if (Invalid) Param->setInvalidDecl(); @@ -572,7 +572,8 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, } NonTypeTemplateParmDecl *Param - = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), + = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + D.getIdentifierLoc(), Depth, Position, ParamName, T, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -625,8 +626,8 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, // Construct the parameter object. TemplateTemplateParmDecl *Param = - TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth, - Position, Name, + TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + TmpLoc, Depth, Position, Name, (TemplateParameterList*)Params); // Make sure the parameter is valid. @@ -1586,9 +1587,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { - if ((ObjectType && - computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || - (SS.isSet() && computeDeclContext(SS, EnteringContext))) { + DeclContext *LookupCtx = 0; + if (SS.isSet()) + LookupCtx = computeDeclContext(SS, EnteringContext); + if (!LookupCtx && ObjectType) + LookupCtx = computeDeclContext(QualType::getFromOpaquePtr(ObjectType)); + if (LookupCtx) { // C++0x [temp.names]p5: // If a name prefixed by the keyword template is not the name of // a template, the program is ill-formed. [Note: the keyword @@ -1608,8 +1612,9 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, EnteringContext, Template); - if (TNK == TNK_Non_template && - isCurrentInstantiationWithDependentBases(SS)) { + if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && + isa<CXXRecordDecl>(LookupCtx) && + cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { // This is a dependent template. } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e909c4f..23a9430 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -150,6 +150,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); return Typedef; @@ -208,6 +209,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { if (D->isOutOfLine()) Var->setLexicalDeclContext(D->getLexicalDeclContext()); + Var->setAccess(D->getAccess()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; @@ -375,6 +378,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } Field->setImplicit(D->isImplicit()); + Field->setAccess(D->getAccess()); Owner->addDecl(Field); return Field; @@ -559,6 +563,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return Inst; } + Inst->setAccess(D->getAccess()); Owner->addDecl(Inst); // First, we sort the partial specializations by location, so @@ -634,6 +639,8 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!Instantiated) return 0; + Instantiated->setAccess(D->getAccess()); + // Link the instantiated function template declaration to the function // template from which it was instantiated. FunctionTemplateDecl *InstTemplate @@ -717,7 +724,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); + bool MergeWithParentScope = (TemplateParams != 0) || + !(isa<Decl>(Owner) && + cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); + Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -844,7 +854,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); + bool MergeWithParentScope = (TemplateParams != 0) || + !(isa<Decl>(Owner) && + cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); + Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -958,6 +971,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); + Method->setAccess(D->getAccess()); + if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && !Method->getFriendObjectKind()) Owner->addDecl(Method); @@ -997,7 +1012,9 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { // Allocate the parameter ParmVarDecl *Param - = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), + = ParmVarDecl::Create(SemaRef.Context, + SemaRef.Context.getTranslationUnitDecl(), + D->getLocation(), D->getIdentifier(), T, DI, D->getStorageClass(), 0); // Mark the default argument as being uninstantiated. @@ -1542,7 +1559,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Proto->hasAnyExceptionSpec(), Exceptions.size(), Exceptions.data(), - Proto->getNoReturnAttr())); + Proto->getNoReturnAttr(), + Proto->getCallConv())); } return false; @@ -1647,8 +1665,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be - // recorded. - LocalInstantiationScope Scope(*this); + // recorded, unless we're actually a member function within a local + // class, in which case we need to merge our results with the parent + // scope (of the enclosing function). + bool MergeWithParentScope = false; + if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext())) + MergeWithParentScope = Rec->isLocalClass(); + + LocalInstantiationScope Scope(*this, MergeWithParentScope); // Introduce the instantiated function parameters into the local // instantiation scope. @@ -1685,6 +1709,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); + // This class may have local implicit instantiations that need to be + // instantiation within this scope. + PerformPendingImplicitInstantiations(/*LocalOnly=*/true); + Scope.Exit(); + if (Recursive) { // Instantiate any pending implicit instantiations found during the // instantiation of this template. @@ -2217,10 +2246,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -void Sema::PerformPendingImplicitInstantiations() { - while (!PendingImplicitInstantiations.empty()) { - PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); - PendingImplicitInstantiations.pop_front(); +void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { + while (!PendingLocalImplicitInstantiations.empty() || + (!LocalOnly && !PendingImplicitInstantiations.empty())) { + PendingImplicitInstantiation Inst; + + if (PendingLocalImplicitInstantiations.empty()) { + Inst = PendingImplicitInstantiations.front(); + PendingImplicitInstantiations.pop_front(); + } else { + Inst = PendingLocalImplicitInstantiations.front(); + PendingLocalImplicitInstantiations.pop_front(); + } // Instantiate function definitions if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9515834..9065761 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1374,6 +1374,21 @@ namespace { Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + // By default, use the source location of the type specifier. + TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); + if (TL.needsExtraLocalData()) { + // Set info for the written builtin specifiers. + TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs(); + // Try to have a meaningful source location. + if (TL.getWrittenSignSpec() != TSS_unspecified) + // Sign spec loc overrides the others (e.g., 'unsigned long'). + TL.setBuiltinLoc(DS.getTypeSpecSignLoc()); + else if (TL.getWrittenWidthSpec() != TSW_unspecified) + // Width spec loc overrides type spec loc (e.g., 'short int'). + TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); + } + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 445ef0d..b2102af 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1014,15 +1014,12 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc, - QualType ExplicitTy, + OwningExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, SourceLocation RParenLoc, ExprArg SubExpr) { - return getSema().ActOnCastExpr(/*Scope=*/0, - LParenLoc, - ExplicitTy.getAsOpaquePtr(), - RParenLoc, - move(SubExpr)); + return getSema().BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, + move(SubExpr)); } /// \brief Build a new compound literal expression. @@ -1030,11 +1027,11 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RParenLoc, ExprArg Init) { - return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(), - RParenLoc, move(Init)); + return getSema().BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, + move(Init)); } /// \brief Build a new extended vector element access expression. @@ -1194,30 +1191,30 @@ public: OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc, Stmt::StmtClass Class, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { switch (Class) { case Stmt::CXXStaticCastExprClass: - return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXDynamicCastExprClass: - return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXReinterpretCastExprClass: - return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXConstCastExprClass: - return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); @@ -1235,14 +1232,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_static_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ dynamic_cast expression. @@ -1251,14 +1249,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_dynamic_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ reinterpret_cast expression. @@ -1267,14 +1266,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ const_cast expression. @@ -1283,14 +1283,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_const_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ functional-style cast expression. @@ -1298,13 +1299,13 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange, - QualType T, + TypeSourceInfo *TInfo, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { void *Sub = SubExpr.takeAs<Expr>(); return getSema().ActOnCXXTypeConstructExpr(TypeRange, - T.getAsOpaquePtr(), + TInfo->getType().getAsOpaquePtr(), LParenLoc, Sema::MultiExprArg(getSema(), &Sub, 1), /*CommaLocs=*/0, @@ -2137,7 +2138,11 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T) { - return TransformTypeSpecType(TLB, T); + BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType()); + NewT.setBuiltinLoc(T.getBuiltinLoc()); + if (T.needsExtraLocalData()) + NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs(); + return T.getType(); } template<typename Derived> @@ -3815,15 +3820,17 @@ TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { - QualType T; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { // FIXME: Source location isn't quite accurate. SourceLocation TypeStartLoc = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - T = getDerived().TransformType(E->getTypeAsWritten()); - if (T.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -3833,11 +3840,12 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T, + return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(), + NewT, E->getRParenLoc(), move(SubExpr)); } @@ -3845,28 +3853,25 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { - QualType T; - { - // FIXME: Source location isn't quite accurate. - SourceLocation FakeTypeLoc - = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); - TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName()); - - T = getDerived().TransformType(E->getType()); - if (T.isNull()) - return SemaRef.ExprError(); - } + TypeSourceInfo *OldT = E->getTypeSourceInfo(); + TypeSourceInfo *NewT = getDerived().TransformType(OldT); + if (!NewT) + return SemaRef.ExprError(); OwningExprResult Init = getDerived().TransformExpr(E->getInitializer()); if (Init.isInvalid()) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getType() && + OldT == NewT && Init.get() == E->getInitializer()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T, + // Note: the expression type doesn't necessarily match the + // type-as-written, but that's okay, because it should always be + // derivable from the initializer. + + return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), NewT, /*FIXME:*/E->getInitializer()->getLocEnd(), move(Init)); } @@ -4237,15 +4242,17 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { - QualType ExplicitTy; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { // FIXME: Source location isn't quite accurate. SourceLocation TypeStartLoc = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); - if (ExplicitTy.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -4255,7 +4262,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - ExplicitTy == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); @@ -4269,7 +4276,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), E->getStmtClass(), FakeLAngleLoc, - ExplicitTy, + NewT, FakeRAngleLoc, FakeRAngleLoc, move(SubExpr), @@ -4305,12 +4312,14 @@ template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { - QualType ExplicitTy; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); - if (ExplicitTy.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -4320,14 +4329,14 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - ExplicitTy == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); // FIXME: The end of the type's source range is wrong return getDerived().RebuildCXXFunctionalCastExpr( /*FIXME:*/SourceRange(E->getTypeBeginLoc()), - ExplicitTy, + NewT, /*FIXME:*/E->getSubExpr()->getLocStart(), move(SubExpr), E->getRParenLoc()); |